diff --git a/.hgtags b/.hgtags index 261cb1ea200..602ce40b2cb 100644 --- a/.hgtags +++ b/.hgtags @@ -196,3 +196,5 @@ a41ada2ed4ef735449531c6ebe6cec593d890a1c jdk8-b71 6725b3961f987cf40f446d1c11cd324a3bec545f jdk8-b72 fe94b40ffd9390f6cffcdf51c0389b0e6dde0c13 jdk8-b73 f627eff819628822a0777af8062244352f2a29cf jdk8-b74 +f1478a6d25fddd311a84dcbfac50824cc1858bdd jdk8-b75 +f407160c280d1c5b00d314c535441ac26f195fee jdk8-b76 diff --git a/.hgtags-top-repo b/.hgtags-top-repo index 53096d3923b..b6c4116ea62 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -196,3 +196,5 @@ cdb401a60cea6ad5ef3f498725ed1decf8dda1ea jdk8-b68 c1be681d80a1f1c848dc671d664fccb19e046a12 jdk8-b72 93b9664f97eeb6f89397a8842318ebacaac9feb9 jdk8-b73 b43aa5bd8ca5c8121336495382d35ecfa7a71536 jdk8-b74 +2a713921952cbd77a1e699626976cb6cdfe3e57e jdk8-b75 +278af9fc67e7eba2884936b49ec07345f423aabb jdk8-b76 diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index 2415b520802..d53e56ec100 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=1359376859 +DATE_WHEN_GENERATED=1359971740 ############################################################################### # @@ -10778,7 +10778,8 @@ if test "x$with_milestone" = xyes; then as_fn_error $? "Milestone must have a value" "$LINENO" 5 elif test "x$with_milestone" != x; then MILESTONE="$with_milestone" -else +fi +if test "x$MILESTONE" = x; then MILESTONE=internal fi @@ -29247,6 +29248,12 @@ fi fi +# 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 # Print a helpful message on how to acquire the necessary build dependency. diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in index 5fde9e7cf16..ad882958d9d 100644 --- a/common/autoconf/spec.gmk.in +++ b/common/autoconf/spec.gmk.in @@ -434,6 +434,12 @@ NATIVE2ASCII=@FIXPATH@ $(BOOT_JDK)/bin/native2ascii JARSIGNER=@FIXPATH@ $(BOOT_JDK)/bin/jarsigner +# You run the new javac using the boot jdk with $(BOOT_JDK)/bin/java $(NEW_JAVAC) ... +BOOTSTRAP_JAVAC_JAR:=$(LANGTOOLS_OUTPUTDIR)/dist/bootstrap/lib/javac.jar +BOOTSTRAP_JAVAC_ARGS:="-Xbootclasspath/p:$(BOOTSTRAP_JAVAC_JAR)" -cp $(BOOTSTRAP_JAVAC_JAR) +NEW_JAVAC = $(BOOTSTRAP_JAVAC_ARGS) com.sun.tools.javac.Main +NEW_JAVADOC = $(BOOTSTRAP_JAVAC_ARGS) com.sun.tools.javadoc.Main + # Base flags for RC # Guarding this against resetting value. Legacy make files include spec multiple # times. diff --git a/common/makefiles/IdlCompilation.gmk b/common/makefiles/IdlCompilation.gmk index 6dc5fee2999..2eb77dd3beb 100644 --- a/common/makefiles/IdlCompilation.gmk +++ b/common/makefiles/IdlCompilation.gmk @@ -71,7 +71,7 @@ define add_idl_package $4 $(RM) -f $$(addprefix $3/$$($4_TMPDIR)/,$6) $(CP) -rp $3/$$($4_TMPDIR)/* $3 - ($(CD) $3/$$($4_TMPDIR); find . -type f | sed 's!\./!$3/!g' | awk '{ print $$$$1 ": $4" }' > $5) + ($(CD) $3/$$($4_TMPDIR) && $(FIND) . -type f | $(SED) 's!\./!$3/!g' | $(NAWK) '{ print $$$$1 ": $4" }' > $5) $(RM) -rf $3/$$($4_TMPDIR) endef diff --git a/common/makefiles/JavaCompilation.gmk b/common/makefiles/JavaCompilation.gmk index 59adc339779..27257183ac6 100644 --- a/common/makefiles/JavaCompilation.gmk +++ b/common/makefiles/JavaCompilation.gmk @@ -42,8 +42,8 @@ endif FALSE_FIND_PATTERN:=-name FILE_NAME_THAT_DOESNT_EXIST define SetupJavaCompiler - # param 1 is for example BOOT_JAVAC or NEW_JAVAC - # This is the name later used to decide which java compiler to use. + # param 1 is for example GENERATE_OLD_BYTECODE or GENERATE_NEW_JDKBYTECODE + # This is the name of the compiler setup. # param 2-9 are named args. # JVM:=The jvm used to run the javac/javah command # JAVAC:=The javac jar and bootstrap classpath changes, or just bin/javac if JVM is left out @@ -143,8 +143,8 @@ define SetupArchive ifneq (,$2) $1_DEPS:=$2 else - $1_DEPS:=$$(filter $$(addprefix %,$$($1_FIND_PATTERNS)),\ - $$(call CacheFind $$($1_SRCS))) + $1_DEPS:=$$(filter $$(addprefix %,$$($1_SUFFIXES)),\ + $$(call CacheFind,$$($1_SRCS))) ifneq (,$$($1_GREP_INCLUDE_PATTERNS)) $1_DEPS:=$$(filter $$(addsuffix %,$$($1_GREP_INCLUDE_PATTERNS)),$$($1_DEPS)) endif @@ -487,10 +487,10 @@ define SetupJavaCompilation # Using sjavac to compile. $1 := $$($1_ALL_COPY_TARGETS) $$($1_ALL_COPY_CLEAN_TARGETS) $$($1_BIN)/javac_state - # Create SJAVAC variable, - # expects $1_JAVAC to be "bootclasspathprepend -jar ...javac.jar" - # and it is rewritten into "bootclasspathprepend com.sun.tools.sjavac.Main" - $1_SJAVAC:=$$(word 1,$$($1_JAVAC)) -cp $$(word 3,$$($1_JAVAC)) com.sun.tools.sjavac.Main + # Create SJAVAC variable form JAVAC variable. Expects $1_JAVAC to be + # "bootclasspathprepend -cp .../javac.jar com.sun.tools.javac.Main" + # and javac is simply replaced with sjavac. + $1_SJAVAC:=$$(subst com.sun.tools.javac.Main,com.sun.tools.sjavac.Main,$$($1_JAVAC)) # Set the $1_REMOTE to spawn a background javac server. $1_REMOTE:=--server:portfile=$$($1_SJAVAC_PORTFILE),id=$1,sjavac=$$(subst $$(SPACE),%20,$$(subst $$(COMMA),%2C,$$(strip $$($1_SERVER_JVM) $$($1_SJAVAC)))) diff --git a/common/makefiles/Jprt.gmk b/common/makefiles/Jprt.gmk index b8bc418fbae..c70cf8872b4 100644 --- a/common/makefiles/Jprt.gmk +++ b/common/makefiles/Jprt.gmk @@ -179,27 +179,52 @@ jprt_bundle: $(JPRT_ARCHIVE_BUNDLE) $(JPRT_ARCHIVE_BUNDLE): bundles $(MKDIR) -p $(@D) $(RM) $@ - $(CP) $(BUILD_OUTPUT)/bundles/j2sdk-image.zip $@ + $(CP) $(BUILD_OUTPUT)/bundles/$(JDK_IMAGE_SUBDIR).zip $@ -# This target must be called in the context of a SPEC file -bundles: all +ifeq ($(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU_BITS),solaris-64) + SRC_JDK_IMAGE_DIR := $(JDK_OVERLAY_IMAGE_DIR) + SRC_JRE_IMAGE_DIR := $(JRE_OVERLAY_IMAGE_DIR) +else + SRC_JDK_IMAGE_DIR := $(JDK_IMAGE_DIR) + SRC_JRE_IMAGE_DIR := $(JRE_IMAGE_DIR) +endif +SRC_JDK_BUNDLE_DIR := $(JDK_BUNDLE_DIR) +SRC_JRE_BUNDLE_DIR := $(JRE_BUNDLE_DIR) + +# Bundle up the images +bundles: all bundles-only +bundles-only: start-make @$(call TargetEnter) $(MKDIR) -p $(BUILD_OUTPUT)/bundles -ifeq ($(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU_BITS),solaris-64) - $(CD) $(JDK_OVERLAY_IMAGE_DIR) && $(ZIP) -q -r $(BUILD_OUTPUT)/bundles/j2sdk-image.zip . - $(CD) $(JRE_OVERLAY_IMAGE_DIR) && $(ZIP) -q -r $(BUILD_OUTPUT)/bundles/j2re-image.zip . -else - $(CD) $(JDK_IMAGE_DIR) && $(ZIP) -q -r $(BUILD_OUTPUT)/bundles/j2sdk-image.zip . - $(CD) $(JRE_IMAGE_DIR) && $(ZIP) -q -r $(BUILD_OUTPUT)/bundles/j2re-image.zip . + $(CD) $(SRC_JDK_IMAGE_DIR) && $(ZIP) -q -r $(BUILD_OUTPUT)/bundles/$(JDK_IMAGE_SUBDIR).zip . + $(CD) $(SRC_JRE_IMAGE_DIR) && $(ZIP) -q -r $(BUILD_OUTPUT)/bundles/$(JRE_IMAGE_SUBDIR).zip . if [ -d $(BUILD_OUTPUT)/install/bundles ] ; then \ $(CD) $(BUILD_OUTPUT)/install/bundles && $(ZIP) -q -r $(JPRT_ARCHIVE_INSTALL_BUNDLE) . ; \ fi + @$(call TargetExit) + +# Copy images to one unified location regardless of platform etc. +final-images: all final-images-only +final-images-only: start-make + @$(call TargetEnter) + $(RM) -r $(BUILD_OUTPUT)/final-images + $(MKDIR) -p $(BUILD_OUTPUT)/final-images/$(JDK_IMAGE_SUBDIR) + $(MKDIR) -p $(BUILD_OUTPUT)/final-images/$(JRE_IMAGE_SUBDIR) + $(CP) -R -P $(SRC_JDK_IMAGE_DIR)/* $(BUILD_OUTPUT)/final-images/$(JDK_IMAGE_SUBDIR)/ + $(CP) -R -P $(SRC_JRE_IMAGE_DIR)/* $(BUILD_OUTPUT)/final-images/$(JRE_IMAGE_SUBDIR)/ +ifeq ($(OPENJDK_TARGET_OS),macosx) + $(MKDIR) -p $(BUILD_OUTPUT)/final-images/$(JDK_BUNDLE_SUBDIR) + $(MKDIR) -p $(BUILD_OUTPUT)/final-images/$(JRE_BUNDLE_SUBDIR) + $(CP) -R -P $(SRC_JDK_BUNDLE_DIR)/* $(BUILD_OUTPUT)/final-images/$(JDK_BUNDLE_SUBDIR)/ + $(CP) -R -P $(SRC_JRE_BUNDLE_DIR)/* $(BUILD_OUTPUT)/final-images/$(JRE_BUNDLE_SUBDIR)/ endif @$(call TargetExit) + # Keep track of phony targets PHONY_LIST += jprt_build_product jprt_build_fastdebug jprt_build_debug \ - jprt_build_generic bundles jprt_bundle + jprt_build_generic bundles jprt_bundle \ + final-images final-images-only ########################################################################### # Phony targets diff --git a/common/makefiles/Main.gmk b/common/makefiles/Main.gmk index c96747f090c..ded49ff55e4 100644 --- a/common/makefiles/Main.gmk +++ b/common/makefiles/Main.gmk @@ -75,7 +75,14 @@ ifeq ($(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU_BITS),solaris-64) all: overlay-images endif -start-make: +# Setup a rule for SPEC file that fails if executed. This check makes sure the configuration +# is up to date after changes to configure +$(SPEC): $(wildcard $(SRC_ROOT)/common/autoconf/*) + @$(ECHO) ERROR: $(SPEC) is not up to date + @$(ECHO) Please rerun configure! + @if test "x$(IGNORE_OLD_CONFIG)" != "xtrue"; then exit 1; fi + +start-make: $(SPEC) @$(call AtMakeStart) langtools: langtools-only diff --git a/common/makefiles/javadoc/Javadoc.gmk b/common/makefiles/javadoc/Javadoc.gmk index 6b88a06d748..1d798120708 100644 --- a/common/makefiles/javadoc/Javadoc.gmk +++ b/common/makefiles/javadoc/Javadoc.gmk @@ -46,14 +46,11 @@ HOTSPOT_DOCS_IMPORT_PATH=$(HOTSPOT_OUTPUTDIR)/docs BUILD_NUMBER=$(JDK_BUILD_NUMBER) -BOOT_JAVA_CMD=$(JAVA) - -JAVADOC_JAR = $(LANGTOOLS_DIST)/bootstrap/lib/javadoc.jar -JAVADOC_CMD = $(BOOT_JAVA_CMD) \ +JAVADOC_CMD = $(JAVA) \ -Xmx1024m \ -Djava.awt.headless=true \ - "-Xbootclasspath/p:$(JAVADOC_JAR)" \ - -jar $(JAVADOC_JAR) -bootclasspath $(JDK_OUTPUTDIR)/classes + $(NEW_JAVADOC) \ + -bootclasspath $(JDK_OUTPUTDIR)/classes # Copyright year for beginning of Java and some of the apis # (Needed when creating the javadocs) diff --git a/corba/.hgtags b/corba/.hgtags index c01bb26f197..c292f1b787d 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -196,3 +196,5 @@ d54dc53e223ed9ce7d5f4d2cd02ad9d5def3c2db jdk8-b59 cb40427f47145b01b7e53c3e02b38ff7625efbda jdk8-b72 191afde59e7be0e1a1d76d06f2a32ff17444f0ec jdk8-b73 2132845cf5f717ff5c240a2431c0c0e03e66e3a5 jdk8-b74 +d4e68ce17795601017ac2f952baad7272942c36e jdk8-b75 +58be6ca3c0603882a1ec478724e337aac85e0da0 jdk8-b76 diff --git a/corba/makefiles/BuildCorba.gmk b/corba/makefiles/BuildCorba.gmk index 246c5b9bcec..b177ff2d212 100644 --- a/corba/makefiles/BuildCorba.gmk +++ b/corba/makefiles/BuildCorba.gmk @@ -35,8 +35,6 @@ include MakeBase.gmk include JavaCompilation.gmk include IdlCompilation.gmk -JAVAC_JARS ?= "-Xbootclasspath/p:$(LANGTOOLS_OUTPUTDIR)/dist/bootstrap/lib/javac.jar" \ - -jar $(LANGTOOLS_OUTPUTDIR)/dist/bootstrap/lib/javac.jar # The Corba sources are old and generates a LOT of warnings. # Disable these using Xlint, until someone cares to fix them. DISABLE_CORBA_WARNINGS:=-Xlint:all,-deprecation,-unchecked,-serial,-fallthrough,-cast,-rawtypes,-static,-dep-ann @@ -46,7 +44,7 @@ DISABLE_CORBA_WARNINGS:=-Xlint:all,-deprecation,-unchecked,-serial,-fallthrough, # Thus we force the target bytecode to the boot jdk bytecode. $(eval $(call SetupJavaCompiler,GENERATE_OLDBYTECODE,\ JVM:=$(JAVA),\ - JAVAC:=$(JAVAC_JARS),\ + JAVAC:=$(NEW_JAVAC),\ FLAGS:=$(BOOT_JDK_SOURCETARGET) -bootclasspath $(BOOT_RTJAR) $(DISABLE_CORBA_WARNINGS),\ SERVER_DIR:=$(SJAVAC_SERVER_DIR),\ SERVER_JVM:=$(SJAVAC_SERVER_JAVA))) @@ -56,7 +54,7 @@ $(eval $(call SetupJavaCompiler,GENERATE_OLDBYTECODE,\ # cannot necessarily be run with the boot jdk. $(eval $(call SetupJavaCompiler,GENERATE_NEWBYTECODE,\ JVM:=$(JAVA),\ - JAVAC:=$(JAVAC_JARS),\ + JAVAC:=$(NEW_JAVAC),\ FLAGS:=-cp $(BOOT_TOOLSJAR) -XDignore.symbol.file=true $(DISABLE_CORBA_WARNINGS),\ SERVER_DIR:=$(SJAVAC_SERVER_DIR),\ SERVER_JVM:=$(SJAVAC_SERVER_JAVA))) diff --git a/hotspot/.hgtags b/hotspot/.hgtags index d46eb646def..da10e708478 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -311,3 +311,6 @@ d5cb5830f570d1304ea4b196dde672a291b55f29 jdk8-b72 70c89bd6b895a10d25ca70e08093c09ff2005fda hs25-b16 1a3e54283c54aaa8b3437813e8507fbdc966e5b6 jdk8-b74 b4391649e91ea8d37f66317a03d6d2573a93d10d hs25-b17 +6778d0b1659323a506ca47600ca29a9d9f8b383d jdk8-b75 +20b605466ccb1b3725eb25314d9e8782199630c5 jdk8-b76 +412d722168bc23f8e6d98995202728678561417f hs25-b18 diff --git a/hotspot/agent/src/os/linux/LinuxDebuggerLocal.c b/hotspot/agent/src/os/linux/LinuxDebuggerLocal.c index 5b49294e975..1d3c3bbd027 100644 --- a/hotspot/agent/src/os/linux/LinuxDebuggerLocal.c +++ b/hotspot/agent/src/os/linux/LinuxDebuggerLocal.c @@ -280,7 +280,7 @@ JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLo return (err == PS_OK)? array : 0; } -#if defined(i386) || defined(ia64) || defined(amd64) || defined(sparc) || defined(sparcv9) +#if defined(i386) || defined(amd64) || defined(sparc) || defined(sparcv9) JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_getThreadIntegerRegisterSet0 (JNIEnv *env, jobject this_obj, jint lwp_id) { @@ -299,9 +299,6 @@ JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLo #ifdef i386 #define NPRGREG sun_jvm_hotspot_debugger_x86_X86ThreadContext_NPRGREG #endif -#ifdef ia64 -#define NPRGREG IA64_REG_COUNT -#endif #ifdef amd64 #define NPRGREG sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_NPRGREG #endif @@ -336,13 +333,6 @@ JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLo #endif /* i386 */ -#if ia64 - regs = (*env)->GetLongArrayElements(env, array, &isCopy); - for (i = 0; i < NPRGREG; i++ ) { - regs[i] = 0xDEADDEAD; - } -#endif /* ia64 */ - #ifdef amd64 #define REG_INDEX(reg) sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_##reg diff --git a/hotspot/agent/src/os/linux/libproc.h b/hotspot/agent/src/os/linux/libproc.h index 5f583631c08..4cde0c19d76 100644 --- a/hotspot/agent/src/os/linux/libproc.h +++ b/hotspot/agent/src/os/linux/libproc.h @@ -79,14 +79,6 @@ combination of ptrace and /proc calls. *************************************************************************************/ -#ifdef ia64 -struct user_regs_struct { -/* copied from user.h which doesn't define this in a struct */ - -#define IA64_REG_COUNT (EF_SIZE/8+32) /* integer and fp regs */ -unsigned long regs[IA64_REG_COUNT]; /* integer and fp regs */ -}; -#endif #if defined(sparc) || defined(sparcv9) #define user_regs_struct pt_regs diff --git a/hotspot/agent/src/os/win32/windbg/sawindbg.cpp b/hotspot/agent/src/os/win32/windbg/sawindbg.cpp index c0a1e66965e..2ee4a2a02f1 100644 --- a/hotspot/agent/src/os/win32/windbg/sawindbg.cpp +++ b/hotspot/agent/src/os/win32/windbg/sawindbg.cpp @@ -27,10 +27,7 @@ #include "sun_jvm_hotspot_debugger_windbg_WindbgDebuggerLocal.h" -#ifdef _M_IA64 - #include "sun_jvm_hotspot_debugger_ia64_IA64ThreadContext.h" - #define NPRGREG sun_jvm_hotspot_debugger_ia64_IA64ThreadContext_NPRGREG -#elif _M_IX86 +#ifdef _M_IX86 #include "sun_jvm_hotspot_debugger_x86_X86ThreadContext.h" #define NPRGREG sun_jvm_hotspot_debugger_x86_X86ThreadContext_NPRGREG #elif _M_AMD64 @@ -491,92 +488,7 @@ static bool addThreads(JNIEnv* env, jobject obj) { memset(&context, 0, sizeof(CONTEXT)); #undef REG_INDEX -#ifdef _M_IA64 - #define REG_INDEX(x) sun_jvm_hotspot_debugger_ia64_IA64ThreadContext_##x - - context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG; - ptrIDebugAdvanced->GetThreadContext(&context, sizeof(CONTEXT)); - - ptrRegs[REG_INDEX(GR0)] = 0; // always 0 - ptrRegs[REG_INDEX(GR1)] = context.IntGp; // r1 - ptrRegs[REG_INDEX(GR2)] = context.IntT0; // r2-r3 - ptrRegs[REG_INDEX(GR3)] = context.IntT1; - ptrRegs[REG_INDEX(GR4)] = context.IntS0; // r4-r7 - ptrRegs[REG_INDEX(GR5)] = context.IntS1; - ptrRegs[REG_INDEX(GR6)] = context.IntS2; - ptrRegs[REG_INDEX(GR7)] = context.IntS3; - ptrRegs[REG_INDEX(GR8)] = context.IntV0; // r8 - ptrRegs[REG_INDEX(GR9)] = context.IntT2; // r9-r11 - ptrRegs[REG_INDEX(GR10)] = context.IntT3; - ptrRegs[REG_INDEX(GR11)] = context.IntT4; - ptrRegs[REG_INDEX(GR12)] = context.IntSp; // r12 stack pointer - ptrRegs[REG_INDEX(GR13)] = context.IntTeb; // r13 teb - ptrRegs[REG_INDEX(GR14)] = context.IntT5; // r14-r31 - ptrRegs[REG_INDEX(GR15)] = context.IntT6; - ptrRegs[REG_INDEX(GR16)] = context.IntT7; - ptrRegs[REG_INDEX(GR17)] = context.IntT8; - ptrRegs[REG_INDEX(GR18)] = context.IntT9; - ptrRegs[REG_INDEX(GR19)] = context.IntT10; - ptrRegs[REG_INDEX(GR20)] = context.IntT11; - ptrRegs[REG_INDEX(GR21)] = context.IntT12; - ptrRegs[REG_INDEX(GR22)] = context.IntT13; - ptrRegs[REG_INDEX(GR23)] = context.IntT14; - ptrRegs[REG_INDEX(GR24)] = context.IntT15; - ptrRegs[REG_INDEX(GR25)] = context.IntT16; - ptrRegs[REG_INDEX(GR26)] = context.IntT17; - ptrRegs[REG_INDEX(GR27)] = context.IntT18; - ptrRegs[REG_INDEX(GR28)] = context.IntT19; - ptrRegs[REG_INDEX(GR29)] = context.IntT20; - ptrRegs[REG_INDEX(GR30)] = context.IntT21; - ptrRegs[REG_INDEX(GR31)] = context.IntT22; - - ptrRegs[REG_INDEX(INT_NATS)] = context.IntNats; - ptrRegs[REG_INDEX(PREDS)] = context.Preds; - - ptrRegs[REG_INDEX(BR_RP)] = context.BrRp; - ptrRegs[REG_INDEX(BR1)] = context.BrS0; // b1-b5 - ptrRegs[REG_INDEX(BR2)] = context.BrS1; - ptrRegs[REG_INDEX(BR3)] = context.BrS2; - ptrRegs[REG_INDEX(BR4)] = context.BrS3; - ptrRegs[REG_INDEX(BR5)] = context.BrS4; - ptrRegs[REG_INDEX(BR6)] = context.BrT0; // b6-b7 - ptrRegs[REG_INDEX(BR7)] = context.BrT1; - - ptrRegs[REG_INDEX(AP_UNAT)] = context.ApUNAT; - ptrRegs[REG_INDEX(AP_LC)] = context.ApLC; - ptrRegs[REG_INDEX(AP_EC)] = context.ApEC; - ptrRegs[REG_INDEX(AP_CCV)] = context.ApCCV; - ptrRegs[REG_INDEX(AP_DCR)] = context.ApDCR; - - ptrRegs[REG_INDEX(RS_PFS)] = context.RsPFS; - ptrRegs[REG_INDEX(RS_BSP)] = context.RsBSP; - ptrRegs[REG_INDEX(RS_BSPSTORE)] = context.RsBSPSTORE; - ptrRegs[REG_INDEX(RS_RSC)] = context.RsRSC; - ptrRegs[REG_INDEX(RS_RNAT)] = context.RsRNAT; - - ptrRegs[REG_INDEX(ST_IPSR)] = context.StIPSR; - ptrRegs[REG_INDEX(ST_IIP)] = context.StIIP; - ptrRegs[REG_INDEX(ST_IFS)] = context.StIFS; - - ptrRegs[REG_INDEX(DB_I0)] = context.DbI0; - ptrRegs[REG_INDEX(DB_I1)] = context.DbI1; - ptrRegs[REG_INDEX(DB_I2)] = context.DbI2; - ptrRegs[REG_INDEX(DB_I3)] = context.DbI3; - ptrRegs[REG_INDEX(DB_I4)] = context.DbI4; - ptrRegs[REG_INDEX(DB_I5)] = context.DbI5; - ptrRegs[REG_INDEX(DB_I6)] = context.DbI6; - ptrRegs[REG_INDEX(DB_I7)] = context.DbI7; - - ptrRegs[REG_INDEX(DB_D0)] = context.DbD0; - ptrRegs[REG_INDEX(DB_D1)] = context.DbD1; - ptrRegs[REG_INDEX(DB_D2)] = context.DbD2; - ptrRegs[REG_INDEX(DB_D3)] = context.DbD3; - ptrRegs[REG_INDEX(DB_D4)] = context.DbD4; - ptrRegs[REG_INDEX(DB_D5)] = context.DbD5; - ptrRegs[REG_INDEX(DB_D6)] = context.DbD6; - ptrRegs[REG_INDEX(DB_D7)] = context.DbD7; - -#elif _M_IX86 +#ifdef _M_IX86 #define REG_INDEX(x) sun_jvm_hotspot_debugger_x86_X86ThreadContext_##x context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS; diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/amd64/WindbgAMD64Thread.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/amd64/WindbgAMD64Thread.java index bf30dd0a5bf..ec5aea35e8c 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/amd64/WindbgAMD64Thread.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/amd64/WindbgAMD64Thread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 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 @@ -34,21 +34,11 @@ class WindbgAMD64Thread implements ThreadProxy { private boolean gotID; private long id; - /** The address argument must be the address of the HANDLE of the - desired thread in the target process. */ + // The address argument must be the address of the OSThread::_thread_id WindbgAMD64Thread(WindbgDebugger debugger, Address addr) { this.debugger = debugger; - // FIXME: size of data fetched here should be configurable. - // However, making it so would produce a dependency on the "types" - // package from the debugger package, which is not desired. - - // another hack here is that we use sys thread id instead of handle. - // windbg can't get details based on handles it seems. - // I assume that osThread_win32 thread struct has _thread_id (which - // sys thread id) just after handle field. - - this.sysId = (int) addr.addOffsetTo(debugger.getAddressSize()).getCIntegerAt(0, 4, true); - gotID = false; + this.sysId = (long)addr.getCIntegerAt(0, 4, true); + gotID = false; } WindbgAMD64Thread(WindbgDebugger debugger, long sysId) { diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/x86/WindbgX86Thread.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/x86/WindbgX86Thread.java index 84d19e03bc0..e5417972b13 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/x86/WindbgX86Thread.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/windbg/x86/WindbgX86Thread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2003, 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 @@ -34,21 +34,11 @@ class WindbgX86Thread implements ThreadProxy { private boolean gotID; private long id; - /** The address argument must be the address of the HANDLE of the - desired thread in the target process. */ + // The address argument must be the address of OSThread::_thread_id WindbgX86Thread(WindbgDebugger debugger, Address addr) { this.debugger = debugger; - // FIXME: size of data fetched here should be configurable. - // However, making it so would produce a dependency on the "types" - // package from the debugger package, which is not desired. - - // another hack here is that we use sys thread id instead of handle. - // windbg can't get details based on handles it seems. - // I assume that osThread_win32 thread struct has _thread_id (which - // sys thread id) just after handle field. - - this.sysId = (int) addr.addOffsetTo(debugger.getAddressSize()).getCIntegerAt(0, 4, true); - gotID = false; + this.sysId = (long)addr.getCIntegerAt(0, 4, true); + gotID = false; } WindbgX86Thread(WindbgDebugger debugger, long sysId) { diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/BinaryTreeDictionary.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/AFLBinaryTreeDictionary.java similarity index 85% rename from hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/BinaryTreeDictionary.java rename to hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/AFLBinaryTreeDictionary.java index 802af91bbc7..5b56cf5f815 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/BinaryTreeDictionary.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/AFLBinaryTreeDictionary.java @@ -1,6 +1,6 @@ /* * @(#)BinaryTreeDictionary.java - * Copyright (c) 2000, 2008, 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 @@ -30,7 +30,7 @@ import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.types.*; import sun.jvm.hotspot.runtime.*; -public class BinaryTreeDictionary extends VMObject { +public class AFLBinaryTreeDictionary extends VMObject { static { VM.registerVMInitializedObserver(new Observer() { public void update(Observable o, Object data) { @@ -40,8 +40,8 @@ public class BinaryTreeDictionary extends VMObject { } private static synchronized void initialize(TypeDataBase db) { - Type type = db.lookupType("BinaryTreeDictionary"); - totalSizeField = type.getCIntegerField("_totalSize"); + Type type = db.lookupType("AFLBinaryTreeDictionary"); + totalSizeField = type.getCIntegerField("_total_size"); } // Fields @@ -53,7 +53,7 @@ public class BinaryTreeDictionary extends VMObject { } // Constructor - public BinaryTreeDictionary(Address addr) { + public AFLBinaryTreeDictionary(Address addr) { super(addr); } } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/CompactibleFreeListSpace.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/CompactibleFreeListSpace.java index c2e8200b694..f47f0e81127 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/CompactibleFreeListSpace.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/CompactibleFreeListSpace.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 @@ -117,9 +117,9 @@ public class CompactibleFreeListSpace extends CompactibleSpace { } // large block - BinaryTreeDictionary bfbd = (BinaryTreeDictionary) VMObjectFactory.newObject(BinaryTreeDictionary.class, + AFLBinaryTreeDictionary aflbd = (AFLBinaryTreeDictionary) VMObjectFactory.newObject(AFLBinaryTreeDictionary.class, dictionaryField.getValue(addr)); - size += bfbd.size(); + size += aflbd.size(); // linear block in TLAB diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/FreeList.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/FreeList.java index 23d7c3d34ee..2d0024e1d2d 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/FreeList.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/FreeList.java @@ -1,7 +1,7 @@ /* * @(#)FreeList.java * - * Copyright (c) 2000, 2008, 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 @@ -41,7 +41,7 @@ public class FreeList extends VMObject { } private static synchronized void initialize(TypeDataBase db) { - Type type = db.lookupType("FreeList"); + Type type = db.lookupType("FreeList"); sizeField = type.getCIntegerField("_size"); countField = type.getCIntegerField("_count"); headerSize = type.getSize(); diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java index 59923078d3d..f944188f4d1 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java @@ -467,7 +467,7 @@ public class ObjectHeap { liveRegions.add(tlab.start()); liveRegions.add(tlab.start()); liveRegions.add(tlab.top()); - liveRegions.add(tlab.end()); + liveRegions.add(tlab.hardEnd()); } } } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/OSThread.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/OSThread.java index cdcbf113871..fb17c53d329 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/OSThread.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/OSThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ import sun.jvm.hotspot.types.*; // to the sys_thread_t structure of the classic JVM implementation. public class OSThread extends VMObject { private static JIntField interruptedField; + private static JIntField threadIdField; static { VM.registerVMInitializedObserver(new Observer() { public void update(Observable o, Object data) { @@ -43,6 +44,7 @@ public class OSThread extends VMObject { private static synchronized void initialize(TypeDataBase db) { Type type = db.lookupType("OSThread"); interruptedField = type.getJIntField("_interrupted"); + threadIdField = type.getJIntField("_thread_id"); } public OSThread(Address addr) { @@ -52,4 +54,9 @@ public class OSThread extends VMObject { public boolean interrupted() { return ((int)interruptedField.getValue(addr)) != 0; } + + public int threadId() { + return (int)threadIdField.getValue(addr); + } + } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ThreadLocalAllocBuffer.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ThreadLocalAllocBuffer.java index 381b53deded..738dc94fa91 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ThreadLocalAllocBuffer.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ThreadLocalAllocBuffer.java @@ -27,6 +27,7 @@ package sun.jvm.hotspot.runtime; import java.io.*; import java.util.*; import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.oops.*; import sun.jvm.hotspot.types.*; /**

ThreadLocalAllocBuffer: a descriptor for thread-local storage @@ -62,9 +63,22 @@ public class ThreadLocalAllocBuffer extends VMObject { super(addr); } - public Address start() { return startField.getValue(addr); } - public Address end() { return endField.getValue(addr); } - public Address top() { return topField.getValue(addr); } + public Address start() { return startField.getValue(addr); } + public Address end() { return endField.getValue(addr); } + public Address top() { return topField.getValue(addr); } + public Address hardEnd() { return end().addOffsetTo(alignmentReserve()); } + + private long alignmentReserve() { + return Oop.alignObjectSize(endReserve()); + } + + private long endReserve() { + long minFillerArraySize = Array.baseOffsetInBytes(BasicType.T_INT); + long reserveForAllocationPrefetch = VM.getVM().getReserveForAllocationPrefetch(); + long heapWordSize = VM.getVM().getHeapWordSize(); + + return Math.max(minFillerArraySize, reserveForAllocationPrefetch * heapWordSize); + } /** Support for iteration over heap -- not sure how this will interact with GC in reflective system, but necessary for the diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java index 5531980b1f8..80464a10bb0 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java @@ -114,6 +114,7 @@ public class VM { private int invalidOSREntryBCI; private ReversePtrs revPtrs; private VMRegImpl vmregImpl; + private int reserveForAllocationPrefetch; // System.getProperties from debuggee VM private Properties sysProps; @@ -293,6 +294,10 @@ public class VM { vmRelease = CStringUtilities.getString(releaseAddr); Address vmInternalInfoAddr = vmVersion.getAddressField("_s_internal_vm_info_string").getValue(); vmInternalInfo = CStringUtilities.getString(vmInternalInfoAddr); + + CIntegerType intType = (CIntegerType) db.lookupType("int"); + CIntegerField reserveForAllocationPrefetchField = vmVersion.getCIntegerField("_reserve_for_allocation_prefetch"); + reserveForAllocationPrefetch = (int)reserveForAllocationPrefetchField.getCInteger(intType); } catch (Exception exp) { throw new RuntimeException("can't determine target's VM version : " + exp.getMessage()); } @@ -778,6 +783,10 @@ public class VM { return vmInternalInfo; } + public int getReserveForAllocationPrefetch() { + return reserveForAllocationPrefetch; + } + public boolean isSharingEnabled() { if (sharingEnabled == null) { Flag flag = getCommandLineFlag("UseSharedSpaces"); diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/win32_amd64/Win32AMD64JavaThreadPDAccess.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/win32_amd64/Win32AMD64JavaThreadPDAccess.java index e18dd4f8053..86255a48f6e 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/win32_amd64/Win32AMD64JavaThreadPDAccess.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/win32_amd64/Win32AMD64JavaThreadPDAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, 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 @@ -43,7 +43,7 @@ public class Win32AMD64JavaThreadPDAccess implements JavaThreadPDAccess { private static AddressField osThreadField; // Field from OSThread - private static Field osThreadThreadHandleField; + private static Field osThreadThreadIdField; // This is currently unneeded but is being kept in case we change // the currentFrameGuess algorithm @@ -64,7 +64,7 @@ public class Win32AMD64JavaThreadPDAccess implements JavaThreadPDAccess { osThreadField = type.getAddressField("_osthread"); type = db.lookupType("OSThread"); - osThreadThreadHandleField = type.getField("_thread_handle"); + osThreadThreadIdField = type.getField("_thread_id"); } public Address getLastJavaFP(Address addr) { @@ -128,10 +128,10 @@ public class Win32AMD64JavaThreadPDAccess implements JavaThreadPDAccess { // Fetch the OSThread (for now and for simplicity, not making a // separate "OSThread" class in this package) Address osThreadAddr = osThreadField.getValue(addr); - // Get the address of the HANDLE within the OSThread - Address threadHandleAddr = - osThreadAddr.addOffsetTo(osThreadThreadHandleField.getOffset()); + // Get the address of the thread_id within the OSThread + Address threadIdAddr = + osThreadAddr.addOffsetTo(osThreadThreadIdField.getOffset()); JVMDebugger debugger = VM.getVM().getDebugger(); - return debugger.getThreadForIdentifierAddress(threadHandleAddr); + return debugger.getThreadForIdentifierAddress(threadIdAddr); } } diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/win32_x86/Win32X86JavaThreadPDAccess.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/win32_x86/Win32X86JavaThreadPDAccess.java index dff6615a008..435e4762335 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/win32_x86/Win32X86JavaThreadPDAccess.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/win32_x86/Win32X86JavaThreadPDAccess.java @@ -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 @@ -42,7 +42,7 @@ public class Win32X86JavaThreadPDAccess implements JavaThreadPDAccess { private static AddressField osThreadField; // Field from OSThread - private static Field osThreadThreadHandleField; + private static Field osThreadThreadIdField; // This is currently unneeded but is being kept in case we change // the currentFrameGuess algorithm @@ -63,7 +63,7 @@ public class Win32X86JavaThreadPDAccess implements JavaThreadPDAccess { osThreadField = type.getAddressField("_osthread"); type = db.lookupType("OSThread"); - osThreadThreadHandleField = type.getField("_thread_handle"); + osThreadThreadIdField = type.getField("_thread_id"); } public Address getLastJavaFP(Address addr) { @@ -127,10 +127,10 @@ public class Win32X86JavaThreadPDAccess implements JavaThreadPDAccess { // Fetch the OSThread (for now and for simplicity, not making a // separate "OSThread" class in this package) Address osThreadAddr = osThreadField.getValue(addr); - // Get the address of the HANDLE within the OSThread - Address threadHandleAddr = - osThreadAddr.addOffsetTo(osThreadThreadHandleField.getOffset()); + // Get the address of the thread_id within the OSThread + Address threadIdAddr = + osThreadAddr.addOffsetTo(osThreadThreadIdField.getOffset()); JVMDebugger debugger = VM.getVM().getDebugger(); - return debugger.getThreadForIdentifierAddress(threadHandleAddr); + return debugger.getThreadForIdentifierAddress(threadIdAddr); } } diff --git a/hotspot/make/Makefile b/hotspot/make/Makefile index fe5a6b684d6..a1d8cb9dde6 100644 --- a/hotspot/make/Makefile +++ b/hotspot/make/Makefile @@ -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 @@ -87,7 +87,6 @@ endif # Typical C1/C2 targets made available with this Makefile C1_VM_TARGETS=product1 fastdebug1 optimized1 jvmg1 C2_VM_TARGETS=product fastdebug optimized jvmg -KERNEL_VM_TARGETS=productkernel fastdebugkernel optimizedkernel jvmgkernel ZERO_VM_TARGETS=productzero fastdebugzero optimizedzero jvmgzero SHARK_VM_TARGETS=productshark fastdebugshark optimizedshark jvmgshark MINIMAL1_VM_TARGETS=productminimal1 fastdebugminimal1 jvmgminimal1 @@ -161,11 +160,6 @@ $(C2_VM_TARGETS): $(CD) $(GAMMADIR)/make; \ $(MAKE) BUILD_FLAVOR=$@ VM_TARGET=$@ generic_build2 $(ALT_OUT) -$(KERNEL_VM_TARGETS): - $(CD) $(GAMMADIR)/make; \ - $(MAKE) BUILD_FLAVOR=$(@:%kernel=%) VM_TARGET=$@ \ - generic_buildkernel $(ALT_OUT) - $(ZERO_VM_TARGETS): $(CD) $(GAMMADIR)/make; \ $(MAKE) BUILD_FLAVOR=$(@:%zero=%) VM_TARGET=$@ \ @@ -223,24 +217,6 @@ else $(MAKE_ARGS) $(VM_TARGET) endif -generic_buildkernel: - $(MKDIR) -p $(OUTPUTDIR) -ifeq ($(OSNAME),windows) - ifeq ($(ARCH_DATA_MODEL), 32) - $(CD) $(OUTPUTDIR); \ - $(NMAKE) -f $(ABS_OS_MAKEFILE) \ - Variant=kernel \ - WorkSpace=$(ABS_GAMMADIR) \ - BootStrapDir=$(ABS_BOOTDIR) \ - BuildUser=$(USERNAME) \ - $(MAKE_ARGS) $(VM_TARGET:%kernel=%) - else - @$(ECHO) "No kernel ($(VM_TARGET)) for ARCH_DATA_MODEL=$(ARCH_DATA_MODEL)" - endif -else - @$(ECHO) "No kernel ($(VM_TARGET)) for OS_NAME=$(OSNAME)" -endif - generic_buildzero: $(MKDIR) -p $(OUTPUTDIR) $(CD) $(OUTPUTDIR); \ @@ -314,12 +290,10 @@ XUSAGE=$(HS_SRC_DIR)/share/vm/Xusage.txt DOCS_DIR=$(OUTPUTDIR)/$(VM_PLATFORM)_docs C1_BASE_DIR=$(OUTPUTDIR)/$(VM_PLATFORM)_compiler1 C2_BASE_DIR=$(OUTPUTDIR)/$(VM_PLATFORM)_compiler2 -KERNEL_BASE_DIR=$(OUTPUTDIR)/$(VM_PLATFORM)_kernel ZERO_BASE_DIR=$(OUTPUTDIR)/$(VM_PLATFORM)_zero SHARK_BASE_DIR=$(OUTPUTDIR)/$(VM_PLATFORM)_shark C1_DIR=$(C1_BASE_DIR)/$(VM_SUBDIR) C2_DIR=$(C2_BASE_DIR)/$(VM_SUBDIR) -KERNEL_DIR=$(KERNEL_BASE_DIR)/$(VM_SUBDIR) ZERO_DIR=$(ZERO_BASE_DIR)/$(VM_SUBDIR) SHARK_DIR=$(SHARK_BASE_DIR)/$(VM_SUBDIR) MINIMAL1_BASE_DIR=$(OUTPUTDIR)/$(VM_PLATFORM)_minimal1 @@ -333,10 +307,6 @@ ifeq ($(JVM_VARIANT_CLIENT), true) MISC_DIR=$(C1_DIR) GEN_DIR=$(C1_BASE_DIR)/generated endif -ifeq ($(JVM_VARIANT_KERNEL), true) - MISC_DIR=$(C2_DIR) - GEN_DIR=$(C2_BASE_DIR)/generated -endif ifeq ($(JVM_VARIANT_ZEROSHARK), true) MISC_DIR=$(SHARK_DIR) GEN_DIR=$(SHARK_BASE_DIR)/generated @@ -386,16 +356,6 @@ $(EXPORT_SERVER_DIR)/%.pdb: $(C2_DIR)/%.pdb $(install-file) $(EXPORT_SERVER_DIR)/%.map: $(C2_DIR)/%.map $(install-file) - -# Kernel files always come from kernel area -$(EXPORT_KERNEL_DIR)/%.diz: $(KERNEL_DIR)/%.diz - $(install-file) -$(EXPORT_KERNEL_DIR)/%.dll: $(KERNEL_DIR)/%.dll - $(install-file) -$(EXPORT_KERNEL_DIR)/%.pdb: $(KERNEL_DIR)/%.pdb - $(install-file) -$(EXPORT_KERNEL_DIR)/%.map: $(KERNEL_DIR)/%.map - $(install-file) endif # Minimal JVM files always come from minimal area @@ -538,7 +498,7 @@ $(EXPORT_DOCS_DIR)/platform/jvmti/%: $(DOCS_DIR)/% $(install-file) # Xusage file -$(EXPORT_SERVER_DIR)/Xusage.txt $(EXPORT_CLIENT_DIR)/Xusage.txt $(EXPORT_KERNEL_DIR)/Xusage.txt $(EXPORT_MINIMAL_DIR)/Xusage.txt: $(XUSAGE) +$(EXPORT_SERVER_DIR)/Xusage.txt $(EXPORT_CLIENT_DIR)/Xusage.txt $(EXPORT_MINIMAL_DIR)/Xusage.txt: $(XUSAGE) $(prep-target) $(RM) $@.temp $(SED) 's/\(separated by \)[;:]/\1$(PATH_SEP)/g' $< > $@.temp @@ -551,7 +511,6 @@ clobber clean: clean_build clean_export clean_jdk clean_build: $(RM) -r $(C1_DIR) $(RM) -r $(C2_DIR) - $(RM) -r $(KERNEL_DIR) $(RM) -r $(ZERO_DIR) $(RM) -r $(SHARK_DIR) $(RM) -r $(MINIMAL1_DIR) @@ -586,10 +545,6 @@ test_jdk: $(JDK_IMAGE_DIR)/bin/java -d$(ARCH_DATA_MODEL) -server -Xinternalversion $(JDK_IMAGE_DIR)/bin/java -d$(ARCH_DATA_MODEL) -server -version endif - ifeq ($(JVM_VARIANT_KERNEL), true) - $(JDK_IMAGE_DIR)/bin/java -d$(ARCH_DATA_MODEL) -kernel -Xinternalversion - $(JDK_IMAGE_DIR)/bin/java -d$(ARCH_DATA_MODEL) -kernel -version - endif copy_product_jdk:: $(RM) -r $(JDK_IMAGE_DIR) @@ -665,7 +620,6 @@ target_help: @$(ECHO) "Other targets are:" @$(ECHO) " $(C1_VM_TARGETS)" @$(ECHO) " $(C2_VM_TARGETS)" - @$(ECHO) " $(KERNEL_VM_TARGETS)" @$(ECHO) " $(MINIMAL1_VM_TARGETS)" # Variable help (only common ones used by this workspace) @@ -761,8 +715,8 @@ endif include $(GAMMADIR)/make/jprt.gmk .PHONY: all world clobber clean help $(C1_VM_TARGETS) $(C2_VM_TARGETS) \ - $(KERNEL_VM_TARGETS) $(MINIMAL1_VM_TARGETS) \ - generic_build1 generic_build2 generic_buildkernel generic_buildminimal1 generic_export \ + $(MINIMAL1_VM_TARGETS) \ + generic_build1 generic_build2 generic_buildminimal1 generic_export \ export_product export_fastdebug export_debug export_optimized \ export_jdk_product export_jdk_fastdebug export_jdk_debug \ create_jdk copy_jdk update_jdk test_jdk \ diff --git a/hotspot/make/bsd/makefiles/dtrace.make b/hotspot/make/bsd/makefiles/dtrace.make index d325f2082dd..1c53841b56c 100644 --- a/hotspot/make/bsd/makefiles/dtrace.make +++ b/hotspot/make/bsd/makefiles/dtrace.make @@ -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 @@ -25,10 +25,9 @@ # Rules to build jvm_db/dtrace, used by vm.make # We build libjvm_dtrace/libjvm_db/dtrace for COMPILER1 and COMPILER2 -# but not for CORE or KERNEL configurations. +# but not for CORE configuration. ifneq ("${TYPE}", "CORE") -ifneq ("${TYPE}", "KERNEL") ifeq ($(OS_VENDOR), Darwin) # we build dtrace for macosx using USDT2 probes @@ -280,13 +279,6 @@ endif # ifneq ("${dtraceFound}", "") endif # ifeq ($(OS_VENDOR), Darwin) -else # KERNEL build - -dtraceCheck: - $(QUIETLY) echo "**NOTICE** Dtrace support disabled for KERNEL builds" - -endif # ifneq ("${TYPE}", "KERNEL") - else # CORE build dtraceCheck: diff --git a/hotspot/make/bsd/makefiles/mapfile-vers-debug b/hotspot/make/bsd/makefiles/mapfile-vers-debug index ef827302c54..24144fe9b70 100644 --- a/hotspot/make/bsd/makefiles/mapfile-vers-debug +++ b/hotspot/make/bsd/makefiles/mapfile-vers-debug @@ -188,6 +188,7 @@ SUNWprivate_1.1 { JVM_IsSilentCompiler; JVM_IsSupportedJNIVersion; JVM_IsThreadAlive; + JVM_IsVMGeneratedMethodIx; JVM_LatestUserDefinedLoader; JVM_Listen; JVM_LoadClass0; diff --git a/hotspot/make/bsd/makefiles/mapfile-vers-product b/hotspot/make/bsd/makefiles/mapfile-vers-product index 0d2b04ca774..c165c16e2d8 100644 --- a/hotspot/make/bsd/makefiles/mapfile-vers-product +++ b/hotspot/make/bsd/makefiles/mapfile-vers-product @@ -188,6 +188,7 @@ SUNWprivate_1.1 { JVM_IsSilentCompiler; JVM_IsSupportedJNIVersion; JVM_IsThreadAlive; + JVM_IsVMGeneratedMethodIx; JVM_LatestUserDefinedLoader; JVM_Listen; JVM_LoadClass0; diff --git a/hotspot/make/bsd/makefiles/minimal1.make b/hotspot/make/bsd/makefiles/minimal1.make index 9494f78bcdd..abfbc4c9490 100644 --- a/hotspot/make/bsd/makefiles/minimal1.make +++ b/hotspot/make/bsd/makefiles/minimal1.make @@ -30,7 +30,7 @@ INCLUDE_VM_STRUCTS ?= false INCLUDE_JNI_CHECK ?= false INCLUDE_SERVICES ?= false INCLUDE_MANAGEMENT ?= false -INCLUDE_ALTERNATE_GCS ?= false +INCLUDE_ALL_GCS ?= false INCLUDE_NMT ?= false INCLUDE_CDS ?= false diff --git a/hotspot/make/excludeSrc.make b/hotspot/make/excludeSrc.make index 721aea5c7e5..589c262ca3c 100644 --- a/hotspot/make/excludeSrc.make +++ b/hotspot/make/excludeSrc.make @@ -72,12 +72,10 @@ ifeq ($(INCLUDE_CDS), false) Src_Files_EXCLUDE += metaspaceShared.cpp endif -ifeq ($(INCLUDE_ALTERNATE_GCS), false) - CXXFLAGS += -DINCLUDE_ALTERNATE_GCS=0 - CFLAGS += -DINCLUDE_ALTERNATE_GCS=0 +ifeq ($(INCLUDE_ALL_GCS), false) + CXXFLAGS += -DINCLUDE_ALL_GCS=0 + CFLAGS += -DINCLUDE_ALL_GCS=0 - CXXFLAGS += -DSERIALGC - CFLAGS += -DSERIALGC Src_Files_EXCLUDE += \ cmsAdaptiveSizePolicy.cpp cmsCollectorPolicy.cpp \ cmsGCAdaptivePolicyCounters.cpp cmsLockVerifier.cpp cmsPermGen.cpp compactibleFreeListSpace.cpp \ diff --git a/hotspot/make/hotspot_version b/hotspot/make/hotspot_version index c47d3d18289..6f09485a3a3 100644 --- a/hotspot/make/hotspot_version +++ b/hotspot/make/hotspot_version @@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2013 HS_MAJOR_VER=25 HS_MINOR_VER=0 -HS_BUILD_NUMBER=17 +HS_BUILD_NUMBER=18 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 ae4e2f9bcc3..27238f5720a 100644 --- a/hotspot/make/linux/makefiles/mapfile-vers-debug +++ b/hotspot/make/linux/makefiles/mapfile-vers-debug @@ -184,6 +184,7 @@ SUNWprivate_1.1 { JVM_IsSilentCompiler; JVM_IsSupportedJNIVersion; JVM_IsThreadAlive; + JVM_IsVMGeneratedMethodIx; JVM_LatestUserDefinedLoader; JVM_Listen; JVM_LoadClass0; diff --git a/hotspot/make/linux/makefiles/mapfile-vers-product b/hotspot/make/linux/makefiles/mapfile-vers-product index 9a3028d2a09..04531fa15aa 100644 --- a/hotspot/make/linux/makefiles/mapfile-vers-product +++ b/hotspot/make/linux/makefiles/mapfile-vers-product @@ -184,6 +184,7 @@ SUNWprivate_1.1 { JVM_IsSilentCompiler; JVM_IsSupportedJNIVersion; JVM_IsThreadAlive; + JVM_IsVMGeneratedMethodIx; JVM_LatestUserDefinedLoader; JVM_Listen; JVM_LoadClass0; diff --git a/hotspot/make/linux/makefiles/minimal1.make b/hotspot/make/linux/makefiles/minimal1.make index 9494f78bcdd..abfbc4c9490 100644 --- a/hotspot/make/linux/makefiles/minimal1.make +++ b/hotspot/make/linux/makefiles/minimal1.make @@ -30,7 +30,7 @@ INCLUDE_VM_STRUCTS ?= false INCLUDE_JNI_CHECK ?= false INCLUDE_SERVICES ?= false INCLUDE_MANAGEMENT ?= false -INCLUDE_ALTERNATE_GCS ?= false +INCLUDE_ALL_GCS ?= false INCLUDE_NMT ?= false INCLUDE_CDS ?= false diff --git a/hotspot/make/solaris/Makefile b/hotspot/make/solaris/Makefile index 4a47cb93716..83e4df66579 100644 --- a/hotspot/make/solaris/Makefile +++ b/hotspot/make/solaris/Makefile @@ -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 @@ -157,13 +157,11 @@ SUBDIRS_C1 = $(addprefix $(OSNAME)_$(BUILDARCH)_compiler1/,$(TARGETS)) SUBDIRS_C2 = $(addprefix $(OSNAME)_$(BUILDARCH)_compiler2/,$(TARGETS)) SUBDIRS_TIERED = $(addprefix $(OSNAME)_$(BUILDARCH)_tiered/,$(TARGETS)) SUBDIRS_CORE = $(addprefix $(OSNAME)_$(BUILDARCH)_core/,$(TARGETS)) -SUBDIRS_KERNEL = $(addprefix $(OSNAME)_$(BUILDARCH)_kernel/,$(TARGETS)) TARGETS_C2 = $(TARGETS) TARGETS_C1 = $(addsuffix 1,$(TARGETS)) TARGETS_TIERED = $(addsuffix tiered,$(TARGETS)) TARGETS_CORE = $(addsuffix core,$(TARGETS)) -TARGETS_KERNEL = $(addsuffix kernel,$(TARGETS)) BUILDTREE_MAKE = $(GAMMADIR)/make/$(OSNAME)/makefiles/buildtree.make BUILDTREE_VARS = GAMMADIR=$(GAMMADIR) OS_FAMILY=$(OSNAME) ARCH=$(SRCARCH) BUILDARCH=$(BUILDARCH) LIBARCH=$(LIBARCH) @@ -229,10 +227,6 @@ $(SUBDIRS_CORE): $(BUILDTREE_MAKE) $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks $(BUILDTREE) VARIANT=core -$(SUBDIRS_KERNEL): $(BUILDTREE_MAKE) - $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks - $(BUILDTREE) VARIANT=kernel - # Define INSTALL=y at command line to automatically copy JVM into JAVA_HOME $(TARGETS_C2): $(SUBDIRS_C2) @@ -271,20 +265,10 @@ ifdef INSTALL cd $(OSNAME)_$(BUILDARCH)_core/$(patsubst %core,%,$@) && $(MAKE) $(MFLAGS) install endif -$(TARGETS_KERNEL): $(SUBDIRS_KERNEL) - cd $(OSNAME)_$(BUILDARCH)_kernel/$(patsubst %kernel,%,$@) && $(MAKE) $(MFLAGS) -ifeq ($(TEST_IN_BUILD),true) - cd $(OSNAME)_$(BUILDARCH)_kernel/$(patsubst %kernel,%,$@) && ./test_gamma -endif -ifdef INSTALL - cd $(OSNAME)_$(BUILDARCH)_kernel/$(patsubst %kernel,%,$@) && $(MAKE) $(MFLAGS) install -endif - # Just build the tree, and nothing else: tree: $(SUBDIRS_C2) tree1: $(SUBDIRS_C1) treecore: $(SUBDIRS_CORE) -treekernel: $(SUBDIRS_KERNEL) # Doc target. This is the same for all build options. # Hence create a docs directory beside ...$(ARCH)_[...] @@ -304,10 +288,10 @@ core: jvmgcore productcore clean_docs: rm -rf $(SUBDIR_DOCS) -clean_compiler1 clean_compiler2 clean_core clean_kernel: +clean_compiler1 clean_compiler2 clean_core: rm -rf $(OSNAME)_$(BUILDARCH)_$(subst clean_,,$@) -clean: clean_compiler2 clean_compiler1 clean_core clean_docs clean_kernel +clean: clean_compiler2 clean_compiler1 clean_core clean_docs include $(GAMMADIR)/make/cscope.make diff --git a/hotspot/make/solaris/makefiles/dtrace.make b/hotspot/make/solaris/makefiles/dtrace.make index 111acdb0d96..b57365b93dc 100644 --- a/hotspot/make/solaris/makefiles/dtrace.make +++ b/hotspot/make/solaris/makefiles/dtrace.make @@ -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 @@ -25,10 +25,9 @@ # Rules to build jvm_db/dtrace, used by vm.make # We build libjvm_dtrace/libjvm_db/dtrace for COMPILER1 and COMPILER2 -# but not for CORE or KERNEL configurations. +# but not for CORE configuration. ifneq ("${TYPE}", "CORE") -ifneq ("${TYPE}", "KERNEL") ifdef USE_GCC @@ -362,13 +361,6 @@ endif # ifneq ("${dtraceFound}", "") endif # ifdef USE_GCC -else # KERNEL build - -dtraceCheck: - $(QUIETLY) echo "**NOTICE** Dtrace support disabled for KERNEL builds" - -endif # ifneq ("${TYPE}", "KERNEL") - else # CORE build dtraceCheck: diff --git a/hotspot/make/solaris/makefiles/mapfile-vers b/hotspot/make/solaris/makefiles/mapfile-vers index bf21253062e..d58807b046d 100644 --- a/hotspot/make/solaris/makefiles/mapfile-vers +++ b/hotspot/make/solaris/makefiles/mapfile-vers @@ -184,6 +184,7 @@ SUNWprivate_1.1 { JVM_IsSilentCompiler; JVM_IsSupportedJNIVersion; JVM_IsThreadAlive; + JVM_IsVMGeneratedMethodIx; JVM_LatestUserDefinedLoader; JVM_Listen; JVM_LoadClass0; diff --git a/hotspot/make/windows/build.bat b/hotspot/make/windows/build.bat index e4eab3abf0c..5df20dd4f1e 100644 --- a/hotspot/make/windows/build.bat +++ b/hotspot/make/windows/build.bat @@ -1,6 +1,6 @@ @echo off REM -REM Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. +REM Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. REM DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. REM REM This code is free software; you can redistribute it and/or modify it @@ -67,7 +67,6 @@ goto usage :test1 if "%2" == "core" goto test2 -if "%2" == "kernel" goto test2 if "%2" == "compiler1" goto test2 if "%2" == "compiler2" goto test2 if "%2" == "tiered" goto test2 @@ -109,7 +108,7 @@ echo Usage: build flavor version workspace bootstrap_dir [build_id] [windbg_home echo. echo where: echo flavor is "product", "debug" or "fastdebug", -echo version is "core", "kernel", "compiler1", "compiler2", or "tiered", +echo version is "core", "compiler1", "compiler2", or "tiered", echo workspace is source directory without trailing slash, echo bootstrap_dir is a full path to a JDK in which bin/java echo and bin/javac are present and working, and build_id is an diff --git a/hotspot/make/windows/create_obj_files.sh b/hotspot/make/windows/create_obj_files.sh index 78fabc06ddc..14a7087f2aa 100644 --- a/hotspot/make/windows/create_obj_files.sh +++ b/hotspot/make/windows/create_obj_files.sh @@ -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 @@ -107,7 +107,6 @@ COMPILER2_PATHS="${COMPILER2_PATHS} ${GENERATED}/adfiles" # Include dirs per type. case "${TYPE}" in "core") Src_Dirs="${CORE_PATHS}" ;; - "kernel") Src_Dirs="${BASE_PATHS} ${COMPILER1_PATHS}" ;; "compiler1") Src_Dirs="${CORE_PATHS} ${COMPILER1_PATHS}" ;; "compiler2") Src_Dirs="${CORE_PATHS} ${COMPILER2_PATHS}" ;; "tiered") Src_Dirs="${CORE_PATHS} ${COMPILER1_PATHS} ${COMPILER2_PATHS}" ;; @@ -120,16 +119,12 @@ COMPILER1_SPECIFIC_FILES="c1_*" SHARK_SPECIFIC_FILES="shark" ZERO_SPECIFIC_FILES="zero" -# These files need to be excluded when building the kernel target. -KERNEL_EXCLUDED_FILES="attachListener.cpp attachListener_windows.cpp metaspaceShared_${Platform_arch_model}.cpp forte.cpp fprofiler.cpp heapDumper.cpp heapInspection.cpp jniCheck.cpp jvmtiCodeBlobEvents.cpp jvmtiExtensions.cpp jvmtiImpl.cpp jvmtiRawMonitor.cpp jvmtiTagMap.cpp jvmtiTrace.cpp vmStructs.cpp g1MemoryPool.cpp psMemoryPool.cpp gcAdaptivePolicyCounters.cpp concurrentGCThread.cpp metaspaceShared.cpp mutableNUMASpace.cpp allocationStats.cpp gSpaceCounters.cpp immutableSpace.cpp mutableSpace.cpp spaceCounters.cpp yieldingWorkgroup.cpp" - # Always exclude these. Src_Files_EXCLUDE="jsig.c jvmtiEnvRecommended.cpp jvmtiEnvStub.cpp" # Exclude per type. case "${TYPE}" in "core") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER1_SPECIFIC_FILES} ${COMPILER2_SPECIFIC_FILES} ${ZERO_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES} ciTypeFlow.cpp" ;; - "kernel") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER2_SPECIFIC_FILES} ${ZERO_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES} ${KERNEL_EXCLUDED_FILES} ciTypeFlow.cpp" ;; "compiler1") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER2_SPECIFIC_FILES} ${ZERO_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES} ciTypeFlow.cpp" ;; "compiler2") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER1_SPECIFIC_FILES} ${ZERO_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES}" ;; "tiered") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${ZERO_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES}" ;; diff --git a/hotspot/make/windows/makefiles/defs.make b/hotspot/make/windows/makefiles/defs.make index e637c00335d..5d58e699bf2 100644 --- a/hotspot/make/windows/makefiles/defs.make +++ b/hotspot/make/windows/makefiles/defs.make @@ -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 @@ -157,7 +157,7 @@ endif MAKE_ARGS += RM="$(RM)" MAKE_ARGS += ZIPEXE=$(ZIPEXE) -# On 32 bit windows we build server, client and kernel, on 64 bit just server. +# On 32 bit windows we build server and client, on 64 bit just server. ifeq ($(JVM_VARIANTS),) ifeq ($(ARCH_DATA_MODEL), 32) JVM_VARIANTS:=client,server @@ -250,7 +250,6 @@ endif EXPORT_SERVER_DIR = $(EXPORT_JRE_BIN_DIR)/server EXPORT_CLIENT_DIR = $(EXPORT_JRE_BIN_DIR)/client -EXPORT_KERNEL_DIR = $(EXPORT_JRE_BIN_DIR)/kernel ifeq ($(JVM_VARIANT_SERVER),true) EXPORT_LIST += $(EXPORT_SERVER_DIR)/Xusage.txt @@ -277,18 +276,6 @@ ifeq ($(JVM_VARIANT_CLIENT),true) endif endif endif -ifeq ($(JVM_VARIANT_KERNEL),true) - EXPORT_LIST += $(EXPORT_KERNEL_DIR)/Xusage.txt - EXPORT_LIST += $(EXPORT_KERNEL_DIR)/jvm.$(LIBRARY_SUFFIX) - ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) - ifeq ($(ZIP_DEBUGINFO_FILES),1) - EXPORT_LIST += $(EXPORT_KERNEL_DIR)/jvm.diz - else - EXPORT_LIST += $(EXPORT_KERNEL_DIR)/jvm.pdb - EXPORT_LIST += $(EXPORT_KERNEL_DIR)/jvm.map - endif - endif -endif EXPORT_LIST += $(EXPORT_JRE_LIB_DIR)/wb.jar diff --git a/hotspot/make/windows/makefiles/projectcreator.make b/hotspot/make/windows/makefiles/projectcreator.make index 5d71de6618a..68d098d0de3 100644 --- a/hotspot/make/windows/makefiles/projectcreator.make +++ b/hotspot/make/windows/makefiles/projectcreator.make @@ -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 @@ -166,63 +166,6 @@ ProjectCreatorIDEOptions=$(ProjectCreatorIDEOptions) \ $(ProjectCreatorIDEOptionsIgnoreCompiler1:TARGET=core) \ $(ProjectCreatorIDEOptionsIgnoreCompiler2:TARGET=core) -################################################## -# JKERNEL specific options -################################################## -ProjectCreatorIDEOptions=$(ProjectCreatorIDEOptions) \ - -define_kernel KERNEL \ -$(ProjectCreatorIDEOptionsIgnoreCompiler2:TARGET=kernel) \ - -ignorePath_kernel src/share/vm/gc_implementation/parallelScavenge \ - -ignorePath_kernel src/share/vm/gc_implementation/parNew \ - -ignorePath_kernel src/share/vm/gc_implementation/concurrentMarkSweep \ - -ignorePath_kernel src/share/vm/gc_implementation/g1 \ - -ignoreFile_kernel attachListener.cpp \ - -ignoreFile_kernel attachListener_windows.cpp \ - -ignoreFile_kernel dump.cpp \ - -ignoreFile_kernel dump_$(Platform_arch_model).cpp \ - -ignoreFile_kernel forte.cpp \ - -ignoreFile_kernel fprofiler.cpp \ - -ignoreFile_kernel heapDumper.cpp \ - -ignoreFile_kernel heapInspection.cpp \ - -ignoreFile_kernel jniCheck.cpp \ - -ignoreFile_kernel jvmtiCodeBlobEvents.cpp \ - -ignoreFile_kernel jvmtiExtensions.cpp \ - -ignoreFile_kernel jvmtiImpl.cpp \ - -ignoreFile_kernel jvmtiRawMonitor.cpp \ - -ignoreFile_kernel jvmtiTagMap.cpp \ - -ignoreFile_kernel jvmtiTrace.cpp \ - -ignoreFile_kernel jvmtiTrace.hpp \ - -ignoreFile_kernel restore.cpp \ - -ignoreFile_kernel serialize.cpp \ - -ignoreFile_kernel vmStructs.cpp \ - -ignoreFile_kernel g1MemoryPool.cpp \ - -ignoreFile_kernel g1MemoryPool.hpp \ - -ignoreFile_kernel psMemoryPool.cpp \ - -ignoreFile_kernel psMemoryPool.hpp \ - -ignoreFile_kernel gcAdaptivePolicyCounters.cpp \ - -ignoreFile_kernel concurrentGCThread.cpp \ - -ignoreFile_kernel mutableNUMASpace.cpp \ - -ignoreFile_kernel ciTypeFlow.cpp \ - -ignoreFile_kernel ciTypeFlow.hpp \ - -ignoreFile_kernel oop.pcgc.inline.hpp \ - -ignoreFile_kernel oop.psgc.inline.hpp \ - -ignoreFile_kernel allocationStats.cpp \ - -ignoreFile_kernel allocationStats.hpp \ - -ignoreFile_kernel concurrentGCThread.hpp \ - -ignoreFile_kernel gSpaceCounters.cpp \ - -ignoreFile_kernel gSpaceCounters.hpp \ - -ignoreFile_kernel gcAdaptivePolicyCounters.hpp \ - -ignoreFile_kernel immutableSpace.cpp \ - -ignoreFile_kernel mutableNUMASpace.hpp \ - -ignoreFile_kernel mutableSpace.cpp \ - -ignoreFile_kernel spaceCounters.cpp \ - -ignoreFile_kernel spaceCounters.hpp \ - -ignoreFile_kernel yieldingWorkgroup.cpp \ - -ignoreFile_kernel yieldingWorkgroup.hpp \ - -ignorePath_kernel vmStructs_ \ - -ignoreFile_kernel $(Platform_arch_model).ad \ - -additionalFile_kernel gcTaskManager.hpp - ################################################## # Client(C1) compiler specific options ################################################## diff --git a/hotspot/make/windows/makefiles/vm.make b/hotspot/make/windows/makefiles/vm.make index b1e71de0e5a..2e501a7b9f7 100644 --- a/hotspot/make/windows/makefiles/vm.make +++ b/hotspot/make/windows/makefiles/vm.make @@ -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 @@ -44,10 +44,6 @@ CXX_FLAGS=$(CXX_FLAGS) /D "ASSERT" # No need to define anything, CORE is defined as !COMPILER1 && !COMPILER2 !endif -!if "$(Variant)" == "kernel" -CXX_FLAGS=$(CXX_FLAGS) /D "KERNEL" -!endif - !if "$(Variant)" == "compiler1" CXX_FLAGS=$(CXX_FLAGS) /D "COMPILER1" !endif diff --git a/hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp index fa5ce4fa6be..6d936b376e0 100644 --- a/hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp @@ -30,10 +30,11 @@ #include "c1/c1_Runtime1.hpp" #include "nativeInst_sparc.hpp" #include "runtime/sharedRuntime.hpp" +#include "utilities/macros.hpp" #include "vmreg_sparc.inline.hpp" -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" -#endif +#endif // INCLUDE_ALL_GCS #define __ ce->masm()-> @@ -420,7 +421,7 @@ void ArrayCopyStub::emit_code(LIR_Assembler* ce) { /////////////////////////////////////////////////////////////////////////////////// -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void G1PreBarrierStub::emit_code(LIR_Assembler* ce) { // At this point we know that marking is in progress. @@ -483,7 +484,7 @@ void G1PostBarrierStub::emit_code(LIR_Assembler* ce) { __ delayed()->nop(); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS /////////////////////////////////////////////////////////////////////////////////// #undef __ diff --git a/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp index 017baa61d0a..b8c838b1620 100644 --- a/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp @@ -35,6 +35,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/signature.hpp" #include "runtime/vframeArray.hpp" +#include "utilities/macros.hpp" #include "vmreg_sparc.inline.hpp" // Implementation of StubAssembler @@ -822,7 +823,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { } break; -#ifndef SERIALGC +#if INCLUDE_ALL_GCS case g1_pre_barrier_slow_id: { // G4: previous value of memory BarrierSet* bs = Universe::heap()->barrier_set(); @@ -984,7 +985,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { __ delayed()->restore(); } break; -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS default: { __ set_info("unimplemented entry", dont_gc_arguments); diff --git a/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp b/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp index 0dcdea0567b..c642e915fe1 100644 --- a/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp @@ -42,7 +42,7 @@ define_pd_global(bool, ProfileInterpreter, false); #else define_pd_global(bool, ProfileInterpreter, true); #endif // CC_INTERP -define_pd_global(bool, TieredCompilation, trueInTiered); +define_pd_global(bool, TieredCompilation, false); define_pd_global(intx, CompileThreshold, 10000); define_pd_global(intx, BackEdgeThreshold, 140000); diff --git a/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp b/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp index 6066c2019d5..4918746db13 100644 --- a/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp @@ -45,6 +45,7 @@ #include "runtime/timer.hpp" #include "runtime/vframeArray.hpp" #include "utilities/debug.hpp" +#include "utilities/macros.hpp" #ifdef SHARK #include "shark/shark_globals.hpp" #endif @@ -551,7 +552,7 @@ address InterpreterGenerator::generate_accessor_entry(void) { } address InterpreterGenerator::generate_Reference_get_entry(void) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS if (UseG1GC) { // We need to generate have a routine that generates code to: // * load the value in the referent field @@ -563,7 +564,7 @@ address InterpreterGenerator::generate_Reference_get_entry(void) { // field as live. Unimplemented(); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // If G1 is not enabled then attempt to go through the accessor entry point // Reference.get is an accessor diff --git a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp index 3690a9272e4..251e42cd6af 100644 --- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp @@ -36,11 +36,12 @@ #include "runtime/os.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" #include "gc_implementation/g1/heapRegion.hpp" -#endif +#endif // INCLUDE_ALL_GCS #ifdef PRODUCT #define BLOCK_COMMENT(str) /* nothing */ @@ -3867,7 +3868,7 @@ void MacroAssembler::bang_stack_size(Register Rsize, Register Rtsp, } /////////////////////////////////////////////////////////////////////////////////// -#ifndef SERIALGC +#if INCLUDE_ALL_GCS static address satb_log_enqueue_with_frame = NULL; static u_char* satb_log_enqueue_with_frame_end = NULL; @@ -4231,7 +4232,7 @@ void MacroAssembler::g1_write_barrier_post(Register store_addr, Register new_val bind(filtered); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS /////////////////////////////////////////////////////////////////////////////////// void MacroAssembler::card_write_barrier_post(Register store_addr, Register new_val, Register tmp) { diff --git a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp index dffef7e794b..26605cbfa4c 100644 --- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp @@ -26,6 +26,7 @@ #define CPU_SPARC_VM_MACROASSEMBLER_SPARC_HPP #include "asm/assembler.hpp" +#include "utilities/macros.hpp" // promises that the system will not use traps 16-31 #define ST_RESERVED_FOR_USER_0 0x10 @@ -1181,13 +1182,13 @@ public: void card_write_barrier_post(Register store_addr, Register new_val, Register tmp); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // General G1 pre-barrier generator. void g1_write_barrier_pre(Register obj, Register index, int offset, Register pre_val, Register tmp, bool preserve_o_regs); // General G1 post-barrier generator void g1_write_barrier_post(Register store_addr, Register new_val, Register tmp); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // pushes double TOS element of FPU stack on CPU stack; pops from FPU stack void push_fTOS(); diff --git a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp index ed46aa9cdc4..b5cfa00f975 100644 --- a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp @@ -44,6 +44,7 @@ #include "runtime/timer.hpp" #include "runtime/vframeArray.hpp" #include "utilities/debug.hpp" +#include "utilities/macros.hpp" #ifndef CC_INTERP #ifndef FAST_DISPATCH @@ -734,7 +735,7 @@ address InterpreterGenerator::generate_accessor_entry(void) { // Method entry for java.lang.ref.Reference.get. address InterpreterGenerator::generate_Reference_get_entry(void) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Code: _aload_0, _getfield, _areturn // parameter size = 1 // @@ -805,7 +806,7 @@ address InterpreterGenerator::generate_Reference_get_entry(void) { (void) generate_normal_entry(false); return entry; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // If G1 is not enabled then attempt to go through the accessor entry point // Reference.get is an accessor diff --git a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp index 931342ded12..d32a2493cfb 100644 --- a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp @@ -34,6 +34,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/synchronizer.hpp" +#include "utilities/macros.hpp" #ifndef CC_INTERP #define __ _masm-> @@ -53,7 +54,7 @@ static void do_oop_store(InterpreterMacroAssembler* _masm, assert(tmp != val && tmp != base && tmp != index, "register collision"); assert(index == noreg || offset == 0, "only one offset"); switch (barrier) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS case BarrierSet::G1SATBCT: case BarrierSet::G1SATBCTLogging: { @@ -82,7 +83,7 @@ static void do_oop_store(InterpreterMacroAssembler* _masm, } } break; -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS case BarrierSet::CardTableModRef: case BarrierSet::CardTableExtension: { diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.cpp b/hotspot/src/cpu/x86/vm/assembler_x86.cpp index 795461d6abf..b94aaa9368c 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp @@ -36,11 +36,12 @@ #include "runtime/os.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" #include "gc_implementation/g1/heapRegion.hpp" -#endif +#endif // INCLUDE_ALL_GCS #ifdef PRODUCT #define BLOCK_COMMENT(str) /* nothing */ diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.hpp b/hotspot/src/cpu/x86/vm/assembler_x86.hpp index 8dad416b09f..97a5bfc0368 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.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 @@ -543,7 +543,7 @@ class Assembler : public AbstractAssembler { // of instructions are freely declared without the need for wrapping them an ifdef. // (Some dangerous instructions are ifdef's out of inappropriate jvm's.) // In the .cpp file the implementations are wrapped so that they are dropped out - // of the resulting jvm. This is done mostly to keep the footprint of KERNEL + // of the resulting jvm. This is done mostly to keep the footprint of MINIMAL // to the size it was prior to merging up the 32bit and 64bit assemblers. // // This does mean you'll get a linker/runtime error if you use a 64bit only instruction diff --git a/hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp b/hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp index 53c7cbacd1c..806bce01bfa 100644 --- a/hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_CodeStubs_x86.cpp @@ -30,10 +30,11 @@ #include "c1/c1_Runtime1.hpp" #include "nativeInst_x86.hpp" #include "runtime/sharedRuntime.hpp" +#include "utilities/macros.hpp" #include "vmreg_x86.inline.hpp" -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" -#endif +#endif // INCLUDE_ALL_GCS #define __ ce->masm()-> @@ -482,7 +483,7 @@ void ArrayCopyStub::emit_code(LIR_Assembler* ce) { } ///////////////////////////////////////////////////////////////////////////// -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void G1PreBarrierStub::emit_code(LIR_Assembler* ce) { // At this point we know that marking is in progress. @@ -528,7 +529,7 @@ void G1PostBarrierStub::emit_code(LIR_Assembler* ce) { __ jmp(_continuation); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS ///////////////////////////////////////////////////////////////////////////// #undef __ diff --git a/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp b/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp index e02d5f6af7f..d3ac75e4013 100644 --- a/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp @@ -36,6 +36,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/signature.hpp" #include "runtime/vframeArray.hpp" +#include "utilities/macros.hpp" #include "vmreg_x86.inline.hpp" @@ -1607,7 +1608,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { } break; -#ifndef SERIALGC +#if INCLUDE_ALL_GCS case g1_pre_barrier_slow_id: { StubFrame f(sasm, "g1_pre_barrier", dont_gc_arguments); @@ -1804,7 +1805,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { } break; -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS default: { StubFrame f(sasm, "unimplemented entry", dont_gc_arguments); diff --git a/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp b/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp index 5ad08b0f158..f63b8c46d58 100644 --- a/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp +++ b/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp @@ -44,7 +44,7 @@ define_pd_global(bool, ProfileInterpreter, false); #else define_pd_global(bool, ProfileInterpreter, true); #endif // CC_INTERP -define_pd_global(bool, TieredCompilation, trueInTiered); +define_pd_global(bool, TieredCompilation, false); define_pd_global(intx, CompileThreshold, 10000); define_pd_global(intx, BackEdgeThreshold, 100000); diff --git a/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp b/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp index 9c3a2f31aeb..55b29fb2f6c 100644 --- a/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp +++ b/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp @@ -45,6 +45,7 @@ #include "runtime/timer.hpp" #include "runtime/vframeArray.hpp" #include "utilities/debug.hpp" +#include "utilities/macros.hpp" #ifdef SHARK #include "shark/shark_globals.hpp" #endif @@ -938,7 +939,7 @@ address InterpreterGenerator::generate_accessor_entry(void) { } address InterpreterGenerator::generate_Reference_get_entry(void) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS if (UseG1GC) { // We need to generate have a routine that generates code to: // * load the value in the referent field @@ -950,7 +951,7 @@ address InterpreterGenerator::generate_Reference_get_entry(void) { // field as live. Unimplemented(); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // If G1 is not enabled then attempt to go through the accessor entry point // Reference.get is an accessor diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp index e4b221b289b..c1e4c96e610 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp @@ -37,11 +37,12 @@ #include "runtime/os.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" #include "gc_implementation/g1/heapRegion.hpp" -#endif +#endif // INCLUDE_ALL_GCS #ifdef PRODUCT #define BLOCK_COMMENT(str) /* nothing */ @@ -3207,7 +3208,7 @@ void MacroAssembler::vxorps(XMMRegister dst, XMMRegister nds, AddressLiteral src ////////////////////////////////////////////////////////////////////////////////// -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void MacroAssembler::g1_write_barrier_pre(Register obj, Register pre_val, @@ -3417,7 +3418,7 @@ void MacroAssembler::g1_write_barrier_post(Register store_addr, bind(done); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS ////////////////////////////////////////////////////////////////////////////////// diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp index e4b89322b9d..9500f3164fa 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp @@ -26,6 +26,7 @@ #define CPU_X86_VM_MACROASSEMBLER_X86_HPP #include "asm/assembler.hpp" +#include "utilities/macros.hpp" // MacroAssembler extends Assembler by frequently used macros. @@ -294,7 +295,7 @@ class MacroAssembler: public Assembler { void store_check(Register obj); // store check for obj - register is destroyed afterwards void store_check(Register obj, Address dst); // same as above, dst is exact store location (reg. is destroyed) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void g1_write_barrier_pre(Register obj, Register pre_val, @@ -309,7 +310,7 @@ class MacroAssembler: public Assembler { Register tmp, Register tmp2); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // split store_check(Register obj) to enhance instruction interleaving void store_check_part_1(Register obj); diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp index aabc3dbbacd..a562bee3e53 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp @@ -44,6 +44,7 @@ #include "runtime/timer.hpp" #include "runtime/vframeArray.hpp" #include "utilities/debug.hpp" +#include "utilities/macros.hpp" #define __ _masm-> @@ -761,7 +762,7 @@ address InterpreterGenerator::generate_accessor_entry(void) { // Method entry for java.lang.ref.Reference.get. address InterpreterGenerator::generate_Reference_get_entry(void) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Code: _aload_0, _getfield, _areturn // parameter size = 1 // @@ -844,7 +845,7 @@ address InterpreterGenerator::generate_Reference_get_entry(void) { return entry; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // If G1 is not enabled then attempt to go through the accessor entry point // Reference.get is an accessor diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp index 3e3cc0fc1f5..26eadba79b2 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp @@ -44,6 +44,7 @@ #include "runtime/timer.hpp" #include "runtime/vframeArray.hpp" #include "utilities/debug.hpp" +#include "utilities/macros.hpp" #define __ _masm-> @@ -742,7 +743,7 @@ address InterpreterGenerator::generate_accessor_entry(void) { // Method entry for java.lang.ref.Reference.get. address InterpreterGenerator::generate_Reference_get_entry(void) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Code: _aload_0, _getfield, _areturn // parameter size = 1 // @@ -821,7 +822,7 @@ address InterpreterGenerator::generate_Reference_get_entry(void) { return entry; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // If G1 is not enabled then attempt to go through the accessor entry point // Reference.get is an accessor diff --git a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp index e2a20531f82..371517c0537 100644 --- a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp @@ -35,6 +35,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/synchronizer.hpp" +#include "utilities/macros.hpp" #ifndef CC_INTERP #define __ _masm-> @@ -125,7 +126,7 @@ static void do_oop_store(InterpreterMacroAssembler* _masm, bool precise) { assert(val == noreg || val == rax, "parameter is just for looks"); switch (barrier) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS case BarrierSet::G1SATBCT: case BarrierSet::G1SATBCTLogging: { @@ -164,7 +165,7 @@ static void do_oop_store(InterpreterMacroAssembler* _masm, } break; -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS case BarrierSet::CardTableModRef: case BarrierSet::CardTableExtension: { diff --git a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp index eedab0b4b22..d1e22d25990 100644 --- a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp @@ -35,6 +35,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/synchronizer.hpp" +#include "utilities/macros.hpp" #ifndef CC_INTERP @@ -136,7 +137,7 @@ static void do_oop_store(InterpreterMacroAssembler* _masm, bool precise) { assert(val == noreg || val == rax, "parameter is just for looks"); switch (barrier) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS case BarrierSet::G1SATBCT: case BarrierSet::G1SATBCTLogging: { @@ -167,7 +168,7 @@ static void do_oop_store(InterpreterMacroAssembler* _masm, } break; -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS case BarrierSet::CardTableModRef: case BarrierSet::CardTableExtension: { diff --git a/hotspot/src/cpu/zero/vm/assembler_zero.cpp b/hotspot/src/cpu/zero/vm/assembler_zero.cpp index d70a2adc746..ad1107ed12f 100644 --- a/hotspot/src/cpu/zero/vm/assembler_zero.cpp +++ b/hotspot/src/cpu/zero/vm/assembler_zero.cpp @@ -36,11 +36,12 @@ #include "runtime/os.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" #include "gc_implementation/g1/heapRegion.hpp" -#endif +#endif // INCLUDE_ALL_GCS int AbstractAssembler::code_fill_byte() { return 0; diff --git a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp index c6f82cd74a8..a199d037cbc 100644 --- a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp +++ b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp @@ -47,6 +47,7 @@ #include "runtime/vframeArray.hpp" #include "stack_zero.inline.hpp" #include "utilities/debug.hpp" +#include "utilities/macros.hpp" #ifdef SHARK #include "shark/shark_globals.hpp" #endif @@ -791,7 +792,7 @@ address InterpreterGenerator::generate_accessor_entry() { } address InterpreterGenerator::generate_Reference_get_entry(void) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS if (UseG1GC) { // We need to generate have a routine that generates code to: // * load the value in the referent field @@ -803,7 +804,7 @@ address InterpreterGenerator::generate_Reference_get_entry(void) { // field as live. Unimplemented(); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // If G1 is not enabled then attempt to go through the accessor entry point // Reference.get is an accessor diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index 8ff3c786b8b..537b48cdbc9 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -1155,13 +1155,9 @@ void os::Linux::capture_initial_stack(size_t max_size) { // for initial thread if its stack size exceeds 6M. Cap it at 2M, // in case other parts in glibc still assumes 2M max stack size. // FIXME: alt signal stack is gone, maybe we can relax this constraint? -#ifndef IA64 - if (stack_size > 2 * K * K) stack_size = 2 * K * K; -#else // Problem still exists RH7.2 (IA64 anyway) but 2MB is a little small - if (stack_size > 4 * K * K) stack_size = 4 * K * K; -#endif - + if (stack_size > 2 * K * K IA64_ONLY(*2)) + stack_size = 2 * K * K IA64_ONLY(*2); // Try to figure out where the stack base (top) is. This is harder. // // When an application is started, glibc saves the initial stack pointer in @@ -4367,16 +4363,12 @@ int os::Linux::safe_cond_timedwait(pthread_cond_t *_cond, pthread_mutex_t *_mute if (is_NPTL()) { return pthread_cond_timedwait(_cond, _mutex, _abstime); } else { -#ifndef IA64 // 6292965: LinuxThreads pthread_cond_timedwait() resets FPU control // word back to default 64bit precision if condvar is signaled. Java // wants 53bit precision. Save and restore current value. int fpu = get_fpu_control_word(); -#endif // IA64 int status = pthread_cond_timedwait(_cond, _mutex, _abstime); -#ifndef IA64 set_fpu_control_word(fpu); -#endif // IA64 return status; } } diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index 98b3077d1fa..eb16478ab8b 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -349,6 +349,33 @@ address os::current_stack_base() { #ifdef _M_IA64 // IA64 has memory and register stacks + // + // This is the stack layout you get on NT/IA64 if you specify 1MB stack limit + // at thread creation (1MB backing store growing upwards, 1MB memory stack + // growing downwards, 2MB summed up) + // + // ... + // ------- top of stack (high address) ----- + // | + // | 1MB + // | Backing Store (Register Stack) + // | + // | / \ + // | | + // | | + // | | + // ------------------------ stack base ----- + // | 1MB + // | Memory Stack + // | + // | | + // | | + // | | + // | \ / + // | + // ----- bottom of stack (low address) ----- + // ... + stack_size = stack_size / 2; #endif return stack_bottom + stack_size; @@ -2005,17 +2032,34 @@ LONG Handle_Exception(struct _EXCEPTION_POINTERS* exceptionInfo, address handler JavaThread* thread = JavaThread::current(); // Save pc in thread #ifdef _M_IA64 - thread->set_saved_exception_pc((address)exceptionInfo->ContextRecord->StIIP); + // Do not blow up if no thread info available. + if (thread) { + // Saving PRECISE pc (with slot information) in thread. + uint64_t precise_pc = (uint64_t) exceptionInfo->ExceptionRecord->ExceptionAddress; + // Convert precise PC into "Unix" format + precise_pc = (precise_pc & 0xFFFFFFFFFFFFFFF0) | ((precise_pc & 0xF) >> 2); + thread->set_saved_exception_pc((address)precise_pc); + } // Set pc to handler exceptionInfo->ContextRecord->StIIP = (DWORD64)handler; + // Clear out psr.ri (= Restart Instruction) in order to continue + // at the beginning of the target bundle. + exceptionInfo->ContextRecord->StIPSR &= 0xFFFFF9FFFFFFFFFF; + assert(((DWORD64)handler & 0xF) == 0, "Target address must point to the beginning of a bundle!"); #elif _M_AMD64 - thread->set_saved_exception_pc((address)exceptionInfo->ContextRecord->Rip); + // Do not blow up if no thread info available. + if (thread) { + thread->set_saved_exception_pc((address)(DWORD_PTR)exceptionInfo->ContextRecord->Rip); + } // Set pc to handler exceptionInfo->ContextRecord->Rip = (DWORD64)handler; #else - thread->set_saved_exception_pc((address)exceptionInfo->ContextRecord->Eip); + // Do not blow up if no thread info available. + if (thread) { + thread->set_saved_exception_pc((address)(DWORD_PTR)exceptionInfo->ContextRecord->Eip); + } // Set pc to handler - exceptionInfo->ContextRecord->Eip = (LONG)handler; + exceptionInfo->ContextRecord->Eip = (DWORD)(DWORD_PTR)handler; #endif // Continue the execution @@ -2040,6 +2084,14 @@ extern "C" void events(); // included or copied here. #define EXCEPTION_INFO_EXEC_VIOLATION 0x08 +// Handle NAT Bit consumption on IA64. +#ifdef _M_IA64 +#define EXCEPTION_REG_NAT_CONSUMPTION STATUS_REG_NAT_CONSUMPTION +#endif + +// Windows Vista/2008 heap corruption check +#define EXCEPTION_HEAP_CORRUPTION 0xC0000374 + #define def_excpt(val) #val, val struct siglabel { @@ -2082,6 +2134,10 @@ struct siglabel exceptlabels[] = { def_excpt(EXCEPTION_GUARD_PAGE), def_excpt(EXCEPTION_INVALID_HANDLE), def_excpt(EXCEPTION_UNCAUGHT_CXX_EXCEPTION), + def_excpt(EXCEPTION_HEAP_CORRUPTION), +#ifdef _M_IA64 + def_excpt(EXCEPTION_REG_NAT_CONSUMPTION), +#endif NULL, 0 }; @@ -2206,7 +2262,14 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { if (InterceptOSException) return EXCEPTION_CONTINUE_SEARCH; DWORD exception_code = exceptionInfo->ExceptionRecord->ExceptionCode; #ifdef _M_IA64 - address pc = (address) exceptionInfo->ContextRecord->StIIP; + // On Itanium, we need the "precise pc", which has the slot number coded + // into the least 4 bits: 0000=slot0, 0100=slot1, 1000=slot2 (Windows format). + address pc = (address) exceptionInfo->ExceptionRecord->ExceptionAddress; + // Convert the pc to "Unix format", which has the slot number coded + // into the least 2 bits: 0000=slot0, 0001=slot1, 0010=slot2 + // This is needed for IA64 because "relocation" / "implicit null check" / "poll instruction" + // information is saved in the Unix format. + address pc_unix_format = (address) ((((uint64_t)pc) & 0xFFFFFFFFFFFFFFF0) | ((((uint64_t)pc) & 0xF) >> 2)); #elif _M_AMD64 address pc = (address) exceptionInfo->ContextRecord->Rip; #else @@ -2321,29 +2384,40 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { if (exception_code == EXCEPTION_STACK_OVERFLOW) { if (os::uses_stack_guard_pages()) { #ifdef _M_IA64 - // - // If it's a legal stack address continue, Windows will map it in. - // + // Use guard page for register stack. PEXCEPTION_RECORD exceptionRecord = exceptionInfo->ExceptionRecord; address addr = (address) exceptionRecord->ExceptionInformation[1]; - if (addr > thread->stack_yellow_zone_base() && addr < thread->stack_base() ) - return EXCEPTION_CONTINUE_EXECUTION; + // Check for a register stack overflow on Itanium + if (thread->addr_inside_register_stack_red_zone(addr)) { + // Fatal red zone violation happens if the Java program + // catches a StackOverflow error and does so much processing + // that it runs beyond the unprotected yellow guard zone. As + // a result, we are out of here. + fatal("ERROR: Unrecoverable stack overflow happened. JVM will exit."); + } else if(thread->addr_inside_register_stack(addr)) { + // Disable the yellow zone which sets the state that + // we've got a stack overflow problem. + if (thread->stack_yellow_zone_enabled()) { + thread->disable_stack_yellow_zone(); + } + // Give us some room to process the exception. + thread->disable_register_stack_guard(); + // Tracing with +Verbose. + if (Verbose) { + tty->print_cr("SOF Compiled Register Stack overflow at " INTPTR_FORMAT " (SIGSEGV)", pc); + tty->print_cr("Register Stack access at " INTPTR_FORMAT, addr); + tty->print_cr("Register Stack base " INTPTR_FORMAT, thread->register_stack_base()); + tty->print_cr("Register Stack [" INTPTR_FORMAT "," INTPTR_FORMAT "]", + thread->register_stack_base(), + thread->register_stack_base() + thread->stack_size()); + } - // The register save area is the same size as the memory stack - // and starts at the page just above the start of the memory stack. - // If we get a fault in this area, we've run out of register - // stack. If we are in java, try throwing a stack overflow exception. - if (addr > thread->stack_base() && - addr <= (thread->stack_base()+thread->stack_size()) ) { - char buf[256]; - jio_snprintf(buf, sizeof(buf), - "Register stack overflow, addr:%p, stack_base:%p\n", - addr, thread->stack_base() ); - tty->print_raw_cr(buf); - // If not in java code, return and hope for the best. - return in_java ? Handle_Exception(exceptionInfo, - SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW)) - : EXCEPTION_CONTINUE_EXECUTION; + // Reguard the permanent register stack red zone just to be sure. + // We saw Windows silently disabling this without telling us. + thread->enable_register_stack_red_zone(); + + return Handle_Exception(exceptionInfo, + SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW)); } #endif if (thread->stack_yellow_zone_enabled()) { @@ -2418,50 +2492,33 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { { // Null pointer exception. #ifdef _M_IA64 - // We catch register stack overflows in compiled code by doing - // an explicit compare and executing a st8(G0, G0) if the - // BSP enters into our guard area. We test for the overflow - // condition and fall into the normal null pointer exception - // code if BSP hasn't overflowed. - if ( in_java ) { - if(thread->register_stack_overflow()) { - assert((address)exceptionInfo->ContextRecord->IntS3 == - thread->register_stack_limit(), - "GR7 doesn't contain register_stack_limit"); - // Disable the yellow zone which sets the state that - // we've got a stack overflow problem. - if (thread->stack_yellow_zone_enabled()) { - thread->disable_stack_yellow_zone(); + // Process implicit null checks in compiled code. Note: Implicit null checks + // can happen even if "ImplicitNullChecks" is disabled, e.g. in vtable stubs. + if (CodeCache::contains((void*) pc_unix_format) && !MacroAssembler::needs_explicit_null_check((intptr_t) addr)) { + CodeBlob *cb = CodeCache::find_blob_unsafe(pc_unix_format); + // Handle implicit null check in UEP method entry + if (cb && (cb->is_frame_complete_at(pc) || + (cb->is_nmethod() && ((nmethod *)cb)->inlinecache_check_contains(pc)))) { + if (Verbose) { + intptr_t *bundle_start = (intptr_t*) ((intptr_t) pc_unix_format & 0xFFFFFFFFFFFFFFF0); + tty->print_cr("trap: null_check at " INTPTR_FORMAT " (SIGSEGV)", pc_unix_format); + tty->print_cr(" to addr " INTPTR_FORMAT, addr); + tty->print_cr(" bundle is " INTPTR_FORMAT " (high), " INTPTR_FORMAT " (low)", + *(bundle_start + 1), *bundle_start); } - // Give us some room to process the exception - thread->disable_register_stack_guard(); - // Update GR7 with the new limit so we can continue running - // compiled code. - exceptionInfo->ContextRecord->IntS3 = - (ULONGLONG)thread->register_stack_limit(); return Handle_Exception(exceptionInfo, - SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW)); - } else { - // - // Check for implicit null - // We only expect null pointers in the stubs (vtable) - // the rest are checked explicitly now. - // - if (((uintptr_t)addr) < os::vm_page_size() ) { - // an access to the first page of VM--assume it is a null pointer - address stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL); - if (stub != NULL) return Handle_Exception(exceptionInfo, stub); - } + SharedRuntime::continuation_for_implicit_exception(thread, pc_unix_format, SharedRuntime::IMPLICIT_NULL)); } - } // in_java + } - // IA64 doesn't use implicit null checking yet. So we shouldn't - // get here. - tty->print_raw_cr("Access violation, possible null pointer exception"); + // Implicit null checks were processed above. Hence, we should not reach + // here in the usual case => die! + if (Verbose) tty->print_raw_cr("Access violation, possible null pointer exception"); report_error(t, exception_code, pc, exceptionInfo->ExceptionRecord, exceptionInfo->ContextRecord); return EXCEPTION_CONTINUE_SEARCH; -#else /* !IA64 */ + +#else // !IA64 // Windows 98 reports faulting addresses incorrectly if (!MacroAssembler::needs_explicit_null_check((intptr_t)addr) || @@ -2493,7 +2550,24 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { report_error(t, exception_code, pc, exceptionInfo->ExceptionRecord, exceptionInfo->ContextRecord); return EXCEPTION_CONTINUE_SEARCH; - } + } // /EXCEPTION_ACCESS_VIOLATION + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +#if defined _M_IA64 + else if ((exception_code == EXCEPTION_ILLEGAL_INSTRUCTION || + exception_code == EXCEPTION_ILLEGAL_INSTRUCTION_2)) { + M37 handle_wrong_method_break(0, NativeJump::HANDLE_WRONG_METHOD, PR0); + + // Compiled method patched to be non entrant? Following conditions must apply: + // 1. must be first instruction in bundle + // 2. must be a break instruction with appropriate code + if((((uint64_t) pc & 0x0F) == 0) && + (((IPF_Bundle*) pc)->get_slot0() == handle_wrong_method_break.bits())) { + return Handle_Exception(exceptionInfo, + (address)SharedRuntime::get_handle_wrong_method_stub()); + } + } // /EXCEPTION_ILLEGAL_INSTRUCTION +#endif + if (in_java) { switch (exception_code) { diff --git a/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp b/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp index fc55e4ec71e..9eabc200bb8 100644 --- a/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp +++ b/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp @@ -372,7 +372,7 @@ frame os::current_frame() { CAST_FROM_FN_PTR(address, os::current_frame)); if (os::is_first_C_frame(&myframe)) { // stack is not walkable - return frame(NULL, NULL, NULL); + return frame(); } else { return os::get_sender_for_C_frame(&myframe); } diff --git a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp index 907395bb22a..bfb0e960a0c 100644 --- a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp +++ b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp @@ -189,7 +189,7 @@ frame os::current_frame() { CAST_FROM_FN_PTR(address, os::current_frame)); if (os::is_first_C_frame(&myframe)) { // stack is not walkable - return frame(NULL, NULL, NULL); + return frame(); } else { return os::get_sender_for_C_frame(&myframe); } diff --git a/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp b/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp index e8bd38dc13e..1ef29f99a55 100644 --- a/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp +++ b/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp @@ -399,7 +399,7 @@ frame os::current_frame() { typedef intptr_t* get_fp_func (); get_fp_func* func = CAST_TO_FN_PTR(get_fp_func*, StubRoutines::x86::get_previous_fp_entry()); - if (func == NULL) return frame(NULL, NULL, NULL); + if (func == NULL) return frame(); intptr_t* fp = (*func)(); #else intptr_t* fp = _get_previous_fp(); @@ -410,7 +410,7 @@ frame os::current_frame() { CAST_FROM_FN_PTR(address, os::current_frame)); if (os::is_first_C_frame(&myframe)) { // stack is not walkable - return frame(NULL, NULL, NULL); + return frame(); } else { return os::get_sender_for_C_frame(&myframe); } diff --git a/hotspot/src/share/tools/whitebox/sun/hotspot/WhiteBox.java b/hotspot/src/share/tools/whitebox/sun/hotspot/WhiteBox.java index 3a8592dec58..ecc5085896f 100644 --- a/hotspot/src/share/tools/whitebox/sun/hotspot/WhiteBox.java +++ b/hotspot/src/share/tools/whitebox/sun/hotspot/WhiteBox.java @@ -76,4 +76,9 @@ public class WhiteBox { public native long g1NumFreeRegions(); public native int g1RegionSize(); public native Object[] parseCommandLine(String commandline, DiagnosticCommand[] args); + + // NMT + public native boolean NMTAllocTest(); + public native boolean NMTFreeTestMemory(); + public native boolean NMTWaitForDataMerge(); } diff --git a/hotspot/src/share/vm/adlc/adlparse.cpp b/hotspot/src/share/vm/adlc/adlparse.cpp index 6d08eab8010..04fb735c38c 100644 --- a/hotspot/src/share/vm/adlc/adlparse.cpp +++ b/hotspot/src/share/vm/adlc/adlparse.cpp @@ -168,7 +168,7 @@ void ADLParser::instr_parse(void) { // Check for block delimiter if ( (_curchar != '%') || ( next_char(), (_curchar != '{')) ) { - parse_err(SYNERR, "missing '%{' in instruction definition\n"); + parse_err(SYNERR, "missing '%%{' in instruction definition\n"); return; } next_char(); // Maintain the invariant @@ -253,7 +253,7 @@ void ADLParser::instr_parse(void) { } while(_curchar != '%'); next_char(); if (_curchar != '}') { - parse_err(SYNERR, "missing '%}' in instruction definition\n"); + parse_err(SYNERR, "missing '%%}' in instruction definition\n"); return; } // Check for "Set" form of chain rule @@ -423,7 +423,7 @@ void ADLParser::oper_parse(void) { skipws(); // Check for block delimiter if ((_curchar != '%') || (*(_ptr+1) != '{')) { // If not open block - parse_err(SYNERR, "missing '%c{' in operand definition\n","%"); + parse_err(SYNERR, "missing '%%{' in operand definition\n"); return; } next_char(); next_char(); // Skip over "%{" symbol @@ -483,7 +483,7 @@ void ADLParser::oper_parse(void) { } while(_curchar != '%'); next_char(); if (_curchar != '}') { - parse_err(SYNERR, "missing '%}' in operand definition\n"); + parse_err(SYNERR, "missing '%%}' in operand definition\n"); return; } // Add operand to tail of operand list @@ -1324,7 +1324,7 @@ void ADLParser::pipe_parse(void) { // Check for block delimiter if ( (_curchar != '%') || ( next_char(), (_curchar != '{')) ) { - parse_err(SYNERR, "missing '%{' in pipeline definition\n"); + parse_err(SYNERR, "missing '%%{' in pipeline definition\n"); return; } next_char(); // Maintain the invariant @@ -1341,7 +1341,7 @@ void ADLParser::pipe_parse(void) { skipws(); if ( (_curchar != '%') || ( next_char(), (_curchar != '{')) ) { - parse_err(SYNERR, "expected '%{'\n"); + parse_err(SYNERR, "expected '%%{'\n"); return; } next_char(); skipws(); @@ -1397,7 +1397,7 @@ void ADLParser::pipe_parse(void) { skipws(); if ( (_curchar != '%') || ( next_char(), (_curchar != '{')) ) { - parse_err(SYNERR, "expected '%{'\n"); + parse_err(SYNERR, "expected '%%{'\n"); return; } next_char(); skipws(); @@ -1586,7 +1586,7 @@ void ADLParser::pipe_parse(void) { if ( (_curchar != '%') || ( next_char(), (_curchar != '}')) ) { - parse_err(SYNERR, "expected '%}', found \"%c\"\n", _curchar); + parse_err(SYNERR, "expected '%%}', found \"%c\"\n", _curchar); } next_char(); skipws(); @@ -1612,7 +1612,7 @@ void ADLParser::pipe_parse(void) { next_char(); if (_curchar != '}') { - parse_err(SYNERR, "missing \"%}\" in pipeline definition\n"); + parse_err(SYNERR, "missing \"%%}\" in pipeline definition\n"); return; } @@ -1775,7 +1775,7 @@ void ADLParser::pipe_class_parse(PipelineForm &pipeline) { // Check for block delimiter if ( (_curchar != '%') || ( next_char(), (_curchar != '{')) ) { - parse_err(SYNERR, "missing \"%{\" in pipe_class definition\n"); + parse_err(SYNERR, "missing \"%%{\" in pipe_class definition\n"); return; } next_char(); @@ -2062,7 +2062,7 @@ void ADLParser::pipe_class_parse(PipelineForm &pipeline) { next_char(); if (_curchar != '}') { - parse_err(SYNERR, "missing \"%}\" in pipe_class definition\n"); + parse_err(SYNERR, "missing \"%%}\" in pipe_class definition\n"); return; } @@ -3341,12 +3341,12 @@ Interface *ADLParser::mem_interface_parse(void) { char *disp = NULL; if (_curchar != '%') { - parse_err(SYNERR, "Missing '%{' for 'interface' block.\n"); + parse_err(SYNERR, "Missing '%%{' for 'interface' block.\n"); return NULL; } next_char(); // Skip '%' if (_curchar != '{') { - parse_err(SYNERR, "Missing '%{' for 'interface' block.\n"); + parse_err(SYNERR, "Missing '%%{' for 'interface' block.\n"); return NULL; } next_char(); // Skip '{' @@ -3354,7 +3354,7 @@ Interface *ADLParser::mem_interface_parse(void) { do { char *field = get_ident(); if (field == NULL) { - parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%}' ending interface.\n"); + parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n"); return NULL; } if ( strcmp(field,"base") == 0 ) { @@ -3370,13 +3370,13 @@ Interface *ADLParser::mem_interface_parse(void) { disp = interface_field_parse(); } else { - parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%}' ending interface.\n"); + parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n"); return NULL; } } while( _curchar != '%' ); next_char(); // Skip '%' if ( _curchar != '}' ) { - parse_err(SYNERR, "Missing '%}' for 'interface' block.\n"); + parse_err(SYNERR, "Missing '%%}' for 'interface' block.\n"); return NULL; } next_char(); // Skip '}' @@ -3403,12 +3403,12 @@ Interface *ADLParser::cond_interface_parse(void) { const char *greater_format = "gt"; if (_curchar != '%') { - parse_err(SYNERR, "Missing '%{' for 'cond_interface' block.\n"); + parse_err(SYNERR, "Missing '%%{' for 'cond_interface' block.\n"); return NULL; } next_char(); // Skip '%' if (_curchar != '{') { - parse_err(SYNERR, "Missing '%{' for 'cond_interface' block.\n"); + parse_err(SYNERR, "Missing '%%{' for 'cond_interface' block.\n"); return NULL; } next_char(); // Skip '{' @@ -3416,7 +3416,7 @@ Interface *ADLParser::cond_interface_parse(void) { do { char *field = get_ident(); if (field == NULL) { - parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%}' ending interface.\n"); + parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n"); return NULL; } if ( strcmp(field,"equal") == 0 ) { @@ -3438,13 +3438,13 @@ Interface *ADLParser::cond_interface_parse(void) { greater = interface_field_parse(&greater_format); } else { - parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%}' ending interface.\n"); + parse_err(SYNERR, "Expected keyword, base|index|scale|disp, or '%%}' ending interface.\n"); return NULL; } } while( _curchar != '%' ); next_char(); // Skip '%' if ( _curchar != '}' ) { - parse_err(SYNERR, "Missing '%}' for 'interface' block.\n"); + parse_err(SYNERR, "Missing '%%}' for 'interface' block.\n"); return NULL; } next_char(); // Skip '}' @@ -3543,7 +3543,7 @@ MatchRule *ADLParser::match_parse(FormDict &operands) { } else if ((cnstr = find_cpp_block("match constructor")) == NULL ) { parse_err(SYNERR, "invalid construction of match rule\n" - "Missing ';' or invalid '%{' and '%}' constructor\n"); + "Missing ';' or invalid '%%{' and '%%}' constructor\n"); return NULL; // No MatchRule to return } if (_AD._adl_debug > 1) @@ -3646,7 +3646,7 @@ FormatRule* ADLParser::format_parse(void) { // Check for closing '"' and '%}' in format description skipws(); // Move to closing '%}' if ( _curchar != '%' ) { - parse_err(SYNERR, "non-blank characters between closing '\"' and '%' in format"); + parse_err(SYNERR, "non-blank characters between closing '\"' and '%%' in format"); return NULL; } } // Done with format description inside @@ -3654,7 +3654,7 @@ FormatRule* ADLParser::format_parse(void) { skipws(); // Past format description, at '%' if ( _curchar != '%' || *(_ptr+1) != '}' ) { - parse_err(SYNERR, "missing '%}' at end of format block"); + parse_err(SYNERR, "missing '%%}' at end of format block"); return NULL; } next_char(); // Move past the '%' @@ -3785,7 +3785,7 @@ FormatRule* ADLParser::template_parse(void) { skipws(); // Past format description, at '%' if ( _curchar != '%' || *(_ptr+1) != '}' ) { - parse_err(SYNERR, "missing '%}' at end of format block"); + parse_err(SYNERR, "missing '%%}' at end of format block"); return NULL; } next_char(); // Move past the '%' @@ -3834,7 +3834,7 @@ ExpandRule* ADLParser::expand_parse(InstructForm *instr) { skipws(); // Skip leading whitespace if ((_curchar != '%') || (next_char(), (_curchar != '{')) ) { // If not open block - parse_err(SYNERR, "missing '%{' in expand definition\n"); + parse_err(SYNERR, "missing '%%{' in expand definition\n"); return(NULL); } next_char(); // Maintain the invariant @@ -3933,7 +3933,7 @@ ExpandRule* ADLParser::expand_parse(InstructForm *instr) { } while(_curchar != '%'); next_char(); if (_curchar != '}') { - parse_err(SYNERR, "missing '%}' in expand rule definition\n"); + parse_err(SYNERR, "missing '%%}' in expand rule definition\n"); return(NULL); } next_char(); diff --git a/hotspot/src/share/vm/c1/c1_CodeStubs.hpp b/hotspot/src/share/vm/c1/c1_CodeStubs.hpp index 5b46ce1b6d0..9fbeb29b5a4 100644 --- a/hotspot/src/share/vm/c1/c1_CodeStubs.hpp +++ b/hotspot/src/share/vm/c1/c1_CodeStubs.hpp @@ -31,6 +31,7 @@ #include "c1/c1_LIR.hpp" #include "c1/c1_Runtime1.hpp" #include "utilities/array.hpp" +#include "utilities/macros.hpp" class CodeEmitInfo; class LIR_Assembler; @@ -515,7 +516,7 @@ class ArrayCopyStub: public CodeStub { }; ////////////////////////////////////////////////////////////////////////////////////////// -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Code stubs for Garbage-First barriers. class G1PreBarrierStub: public CodeStub { @@ -608,7 +609,7 @@ class G1PostBarrierStub: public CodeStub { #endif // PRODUCT }; -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS ////////////////////////////////////////////////////////////////////////////////////////// #endif // SHARE_VM_C1_C1_CODESTUBS_HPP diff --git a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp index cbaf83b8fea..9491607adfa 100644 --- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp +++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp @@ -3667,11 +3667,12 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, Bytecode } // now perform tests that are based on flag settings - if (callee->force_inline() || callee->should_inline()) { - // ignore heuristic controls on inlining - if (callee->force_inline()) - print_inlining(callee, "force inline by annotation"); + if (callee->force_inline()) { + print_inlining(callee, "force inline by annotation"); + } else if (callee->should_inline()) { + print_inlining(callee, "force inline by CompileOracle"); } else { + // use heuristic controls on inlining if (inline_level() > MaxInlineLevel ) INLINE_BAILOUT("inlining too deep"); if (recursive_inline_level(callee) > MaxRecursiveInlineLevel) INLINE_BAILOUT("recursive inlining too deep"); if (callee->code_size_for_inlining() > max_inline_size() ) INLINE_BAILOUT("callee is too large"); diff --git a/hotspot/src/share/vm/c1/c1_Instruction.cpp b/hotspot/src/share/vm/c1/c1_Instruction.cpp index 628091ce315..985cb098e6f 100644 --- a/hotspot/src/share/vm/c1/c1_Instruction.cpp +++ b/hotspot/src/share/vm/c1/c1_Instruction.cpp @@ -188,7 +188,7 @@ ciType* LoadIndexed::exact_type() const { ciType* LoadIndexed::declared_type() const { ciType* array_type = array()->declared_type(); - if (array_type == NULL) { + if (array_type == NULL || !array_type->is_loaded()) { return NULL; } assert(array_type->is_array_klass(), "what else?"); diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp index 65bc34e3de6..b46acec1474 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp @@ -35,9 +35,10 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "utilities/bitMap.inline.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/heapRegion.hpp" -#endif +#endif // INCLUDE_ALL_GCS #ifdef ASSERT #define __ gen()->lir(__FILE__, __LINE__)-> @@ -1417,12 +1418,12 @@ void LIRGenerator::pre_barrier(LIR_Opr addr_opr, LIR_Opr pre_val, bool do_load, bool patch, CodeEmitInfo* info) { // Do the pre-write barrier, if any. switch (_bs->kind()) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS case BarrierSet::G1SATBCT: case BarrierSet::G1SATBCTLogging: G1SATBCardTableModRef_pre_barrier(addr_opr, pre_val, do_load, patch, info); break; -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS case BarrierSet::CardTableModRef: case BarrierSet::CardTableExtension: // No pre barriers @@ -1439,12 +1440,12 @@ void LIRGenerator::pre_barrier(LIR_Opr addr_opr, LIR_Opr pre_val, void LIRGenerator::post_barrier(LIR_OprDesc* addr, LIR_OprDesc* new_val) { switch (_bs->kind()) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS case BarrierSet::G1SATBCT: case BarrierSet::G1SATBCTLogging: G1SATBCardTableModRef_post_barrier(addr, new_val); break; -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS case BarrierSet::CardTableModRef: case BarrierSet::CardTableExtension: CardTableModRef_post_barrier(addr, new_val); @@ -1459,7 +1460,7 @@ void LIRGenerator::post_barrier(LIR_OprDesc* addr, LIR_OprDesc* new_val) { } //////////////////////////////////////////////////////////////////////// -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void LIRGenerator::G1SATBCardTableModRef_pre_barrier(LIR_Opr addr_opr, LIR_Opr pre_val, bool do_load, bool patch, CodeEmitInfo* info) { @@ -1575,7 +1576,7 @@ void LIRGenerator::G1SATBCardTableModRef_post_barrier(LIR_OprDesc* addr, LIR_Opr __ branch_destination(slow->continuation()); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS //////////////////////////////////////////////////////////////////////// void LIRGenerator::CardTableModRef_post_barrier(LIR_OprDesc* addr, LIR_OprDesc* new_val) { @@ -2181,7 +2182,7 @@ void LIRGenerator::do_UnsafeGetObject(UnsafeGetObject* x) { get_Object_unsafe(value, src.result(), off.result(), type, x->is_volatile()); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // We might be reading the value of the referent field of a // Reference object in order to attach it back to the live // object graph. If G1 is enabled then we need to record @@ -2311,7 +2312,7 @@ void LIRGenerator::do_UnsafeGetObject(UnsafeGetObject* x) { __ branch_destination(Lcont->label()); } } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS if (x->is_volatile() && os::is_MP()) __ membar_acquire(); } diff --git a/hotspot/src/share/vm/ci/ciEnv.cpp b/hotspot/src/share/vm/ci/ciEnv.cpp index bb51f88c7b9..bd18105d9ba 100644 --- a/hotspot/src/share/vm/ci/ciEnv.cpp +++ b/hotspot/src/share/vm/ci/ciEnv.cpp @@ -52,6 +52,7 @@ #include "runtime/reflection.hpp" #include "runtime/sharedRuntime.hpp" #include "utilities/dtrace.hpp" +#include "utilities/macros.hpp" #ifdef COMPILER1 #include "c1/c1_Runtime1.hpp" #endif @@ -1168,7 +1169,7 @@ void ciEnv::dump_replay_data() { void ciEnv::dump_replay_data(outputStream* out) { ASSERT_IN_VM; - + ResourceMark rm; #if INCLUDE_JVMTI out->print_cr("JvmtiExport can_access_local_variables %d", _jvmti_can_access_local_variables); out->print_cr("JvmtiExport can_hotswap_or_post_breakpoint %d", _jvmti_can_hotswap_or_post_breakpoint); diff --git a/hotspot/src/share/vm/ci/ciInstanceKlass.cpp b/hotspot/src/share/vm/ci/ciInstanceKlass.cpp index de5e973bfbf..d74e3693ae1 100644 --- a/hotspot/src/share/vm/ci/ciInstanceKlass.cpp +++ b/hotspot/src/share/vm/ci/ciInstanceKlass.cpp @@ -580,6 +580,7 @@ class StaticFinalFieldPrinter : public FieldClosure { } void do_field(fieldDescriptor* fd) { if (fd->is_final() && !fd->has_initial_value()) { + ResourceMark rm; oop mirror = fd->field_holder()->java_mirror(); _out->print("staticfield %s %s %s ", _holder, fd->name()->as_quoted_ascii(), fd->signature()->as_quoted_ascii()); switch (fd->field_type()) { @@ -643,6 +644,8 @@ class StaticFinalFieldPrinter : public FieldClosure { void ciInstanceKlass::dump_replay_data(outputStream* out) { ASSERT_IN_VM; + ResourceMark rm; + InstanceKlass* ik = get_instanceKlass(); ConstantPool* cp = ik->constants(); diff --git a/hotspot/src/share/vm/ci/ciMethod.cpp b/hotspot/src/share/vm/ci/ciMethod.cpp index 8ad9ecb1199..0fa11470c94 100644 --- a/hotspot/src/share/vm/ci/ciMethod.cpp +++ b/hotspot/src/share/vm/ci/ciMethod.cpp @@ -977,7 +977,7 @@ bool ciMethod::can_be_compiled() { // ciMethod::set_not_compilable // // Tell the VM that this method cannot be compiled at all. -void ciMethod::set_not_compilable() { +void ciMethod::set_not_compilable(const char* reason) { check_is_loaded(); VM_ENTRY_MARK; ciEnv* env = CURRENT_ENV; @@ -986,7 +986,7 @@ void ciMethod::set_not_compilable() { } else { _is_c2_compilable = false; } - get_Method()->set_not_compilable(env->comp_level()); + get_Method()->set_not_compilable(env->comp_level(), true, reason); } // ------------------------------------------------------------------ @@ -1178,6 +1178,7 @@ ciMethodBlocks *ciMethod::get_method_blocks() { void ciMethod::dump_replay_data(outputStream* st) { ASSERT_IN_VM; + ResourceMark rm; Method* method = get_Method(); Klass* holder = method->method_holder(); st->print_cr("ciMethod %s %s %s %d %d %d %d %d", diff --git a/hotspot/src/share/vm/ci/ciMethod.hpp b/hotspot/src/share/vm/ci/ciMethod.hpp index 193eb68de05..c98f2c0dccf 100644 --- a/hotspot/src/share/vm/ci/ciMethod.hpp +++ b/hotspot/src/share/vm/ci/ciMethod.hpp @@ -252,7 +252,7 @@ class ciMethod : public ciMetadata { bool has_option(const char *option); bool can_be_compiled(); bool can_be_osr_compiled(int entry_bci); - void set_not_compilable(); + void set_not_compilable(const char* reason = NULL); bool has_compiled_code(); void log_nmethod_identity(xmlStream* log); bool is_not_reached(int bci); diff --git a/hotspot/src/share/vm/ci/ciMethodData.cpp b/hotspot/src/share/vm/ci/ciMethodData.cpp index ee5490be877..c30c6c36437 100644 --- a/hotspot/src/share/vm/ci/ciMethodData.cpp +++ b/hotspot/src/share/vm/ci/ciMethodData.cpp @@ -374,6 +374,7 @@ void ciMethodData::print_impl(outputStream* st) { void ciMethodData::dump_replay_data(outputStream* out) { ASSERT_IN_VM; + ResourceMark rm; MethodData* mdo = get_MethodData(); Method* method = mdo->method(); Klass* holder = method->method_holder(); diff --git a/hotspot/src/share/vm/ci/ciReplay.cpp b/hotspot/src/share/vm/ci/ciReplay.cpp index 9b532b8e26b..030d93db7c3 100644 --- a/hotspot/src/share/vm/ci/ciReplay.cpp +++ b/hotspot/src/share/vm/ci/ciReplay.cpp @@ -30,6 +30,7 @@ #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" #include "utilities/copy.hpp" +#include "utilities/macros.hpp" #ifndef PRODUCT diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp index 557707ba432..d46a1eab840 100644 --- a/hotspot/src/share/vm/classfile/classFileParser.cpp +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp @@ -1947,6 +1947,8 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, u2** localvariable_type_table_start; u2 method_parameters_length = 0; u1* method_parameters_data = NULL; + bool method_parameters_seen = false; + bool method_parameters_four_byte_flags; bool parsed_code_attribute = false; bool parsed_checked_exceptions_attribute = false; bool parsed_stackmap_attribute = false; @@ -2157,22 +2159,32 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, method_attribute_length, cp, CHECK_(nullHandle)); } else if (method_attribute_name == vmSymbols::tag_method_parameters()) { + // reject multiple method parameters + if (method_parameters_seen) { + classfile_parse_error("Multiple MethodParameters attributes in class file %s", CHECK_(nullHandle)); + } + method_parameters_seen = true; 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) { + // Use the attribute length to figure out the size of flags + if (method_attribute_length == (method_parameters_length * 6u) + 1u) { + method_parameters_four_byte_flags = true; + } else if (method_attribute_length == (method_parameters_length * 4u) + 1u) { + method_parameters_four_byte_flags = false; + } else { classfile_parse_error( - "Invalid MethodParameters method attribute length %u in class file %s", + "Invalid MethodParameters method attribute length %u in class file", method_attribute_length, CHECK_(nullHandle)); } + method_parameters_data = cfs->get_u1_buffer(); + cfs->skip_u2_fast(method_parameters_length); + if (method_parameters_four_byte_flags) { + cfs->skip_u4_fast(method_parameters_length); + } else { + cfs->skip_u2_fast(method_parameters_length); + } // ignore this attribute if it cannot be reflected if (!SystemDictionary::Parameter_klass_loaded()) method_parameters_length = 0; @@ -2316,15 +2328,16 @@ methodHandle ClassFileParser::parse_method(ClassLoaderData* loader_data, // Copy method parameters if (method_parameters_length > 0) { MethodParametersElement* elem = m->constMethod()->method_parameters_start(); - for(int i = 0; i < method_parameters_length; i++) { - elem[i].name_cp_index = - Bytes::get_Java_u2(method_parameters_data); + for (int i = 0; i < method_parameters_length; i++) { + elem[i].name_cp_index = Bytes::get_Java_u2(method_parameters_data); method_parameters_data += 2; - 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; + if (method_parameters_four_byte_flags) { + elem[i].flags = Bytes::get_Java_u4(method_parameters_data); + method_parameters_data += 4; + } else { + elem[i].flags = Bytes::get_Java_u2(method_parameters_data); + method_parameters_data += 2; + } } } diff --git a/hotspot/src/share/vm/classfile/classLoaderData.cpp b/hotspot/src/share/vm/classfile/classLoaderData.cpp index 22cc8cf9bb1..e74a88d7d33 100644 --- a/hotspot/src/share/vm/classfile/classLoaderData.cpp +++ b/hotspot/src/share/vm/classfile/classLoaderData.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 @@ -50,11 +50,12 @@ #include "classfile/classLoaderData.hpp" #include "classfile/classLoaderData.inline.hpp" #include "classfile/javaClasses.hpp" +#include "classfile/metadataOnStackMark.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" #include "memory/metadataFactory.hpp" #include "memory/metaspaceShared.hpp" -#include "prims/jvmtiRedefineClasses.hpp" +#include "memory/oopFactory.hpp" #include "runtime/jniHandles.hpp" #include "runtime/mutex.hpp" #include "runtime/safepoint.hpp" @@ -723,13 +724,13 @@ void ClassLoaderDataGraph::dump_on(outputStream * const out) { } MetaspaceAux::dump(out); } +#endif // PRODUCT void ClassLoaderData::print_value_on(outputStream* out) const { if (class_loader() == NULL) { - out->print_cr("NULL class_loader"); + out->print("NULL class_loader"); } else { out->print("class loader "PTR_FORMAT, this); class_loader()->print_value_on(out); } } -#endif // PRODUCT diff --git a/hotspot/src/share/vm/classfile/classLoaderData.hpp b/hotspot/src/share/vm/classfile/classLoaderData.hpp index 9525658e67a..f72645db1c4 100644 --- a/hotspot/src/share/vm/classfile/classLoaderData.hpp +++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp @@ -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 @@ -220,7 +220,7 @@ class ClassLoaderData : public CHeapObj { void set_jmethod_ids(JNIMethodBlock* new_block) { _jmethod_ids = new_block; } void print_value() { print_value_on(tty); } - void print_value_on(outputStream* out) const PRODUCT_RETURN; + void print_value_on(outputStream* out) const; void dump(outputStream * const out) PRODUCT_RETURN; void verify(); const char* loader_name(); diff --git a/hotspot/src/share/vm/classfile/metadataOnStackMark.cpp b/hotspot/src/share/vm/classfile/metadataOnStackMark.cpp new file mode 100644 index 00000000000..1f24042f5cb --- /dev/null +++ b/hotspot/src/share/vm/classfile/metadataOnStackMark.cpp @@ -0,0 +1,69 @@ +/* + * 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. + * + */ + +#include "precompiled.hpp" +#include "classfile/metadataOnStackMark.hpp" +#include "code/codeCache.hpp" +#include "compiler/compileBroker.hpp" +#include "oops/metadata.hpp" +#include "runtime/synchronizer.hpp" +#include "runtime/thread.hpp" +#include "utilities/growableArray.hpp" + + +// Keep track of marked on-stack metadata so it can be cleared. +GrowableArray* _marked_objects = NULL; +NOT_PRODUCT(bool MetadataOnStackMark::_is_active = false;) + +// Walk metadata on the stack and mark it so that redefinition doesn't delete +// it. Class unloading also walks the previous versions and might try to +// delete it, so this class is used by class unloading also. +MetadataOnStackMark::MetadataOnStackMark() { + assert(SafepointSynchronize::is_at_safepoint(), "sanity check"); + NOT_PRODUCT(_is_active = true;) + if (_marked_objects == NULL) { + _marked_objects = new (ResourceObj::C_HEAP, mtClass) GrowableArray(1000, true); + } + Threads::metadata_do(Metadata::mark_on_stack); + CodeCache::alive_nmethods_do(nmethod::mark_on_stack); + CompileBroker::mark_on_stack(); +} + +MetadataOnStackMark::~MetadataOnStackMark() { + assert(SafepointSynchronize::is_at_safepoint(), "sanity check"); + // Unmark everything that was marked. Can't do the same walk because + // redefine classes messes up the code cache so the set of methods + // might not be the same. + for (int i = 0; i< _marked_objects->length(); i++) { + _marked_objects->at(i)->set_on_stack(false); + } + _marked_objects->clear(); // reuse growable array for next time. + NOT_PRODUCT(_is_active = false;) +} + +// Record which objects are marked so we can unmark the same objects. +void MetadataOnStackMark::record(Metadata* m) { + assert(_is_active, "metadata on stack marking is active"); + _marked_objects->push(m); +} diff --git a/hotspot/src/share/vm/classfile/metadataOnStackMark.hpp b/hotspot/src/share/vm/classfile/metadataOnStackMark.hpp new file mode 100644 index 00000000000..5a4fda2f332 --- /dev/null +++ b/hotspot/src/share/vm/classfile/metadataOnStackMark.hpp @@ -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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_CLASSFILE_METADATAONSTACKMARK_HPP +#define SHARE_VM_CLASSFILE_METADATAONSTACKMARK_HPP + +#include "memory/allocation.hpp" + +class Metadata; + +// Helper class to mark and unmark metadata used on the stack as either handles +// or executing methods, so that it can't be deleted during class redefinition +// and class unloading. +// This is also used for other things that can be deallocated, like class +// metadata during parsing, relocated methods, and methods in backtraces. +class MetadataOnStackMark : public StackObj { + NOT_PRODUCT(static bool _is_active;) + public: + MetadataOnStackMark(); + ~MetadataOnStackMark(); + static void record(Metadata* m); +}; + +#endif // SHARE_VM_CLASSFILE_METADATAONSTACKMARK_HPP diff --git a/hotspot/src/share/vm/classfile/stackMapFrame.hpp b/hotspot/src/share/vm/classfile/stackMapFrame.hpp index 3329f7a9e8b..bdeb956ba68 100644 --- a/hotspot/src/share/vm/classfile/stackMapFrame.hpp +++ b/hotspot/src/share/vm/classfile/stackMapFrame.hpp @@ -178,7 +178,7 @@ class StackMapFrame : public ResourceObj { #ifdef DEBUG // Put bogus type to indicate it's no longer valid. if (_stack_mark != -1) { - for (int i = _stack_mark; i >= _stack_size; --i) { + for (int i = _stack_mark - 1; i >= _stack_size; --i) { _stack[i] = VerificationType::bogus_type(); } } diff --git a/hotspot/src/share/vm/classfile/systemDictionary.cpp b/hotspot/src/share/vm/classfile/systemDictionary.cpp index 54601625056..a7370fcce29 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp @@ -1199,66 +1199,6 @@ instanceKlassHandle SystemDictionary::load_shared_class( return ik; } -#ifdef KERNEL -// Some classes on the bootstrap class path haven't been installed on the -// system yet. Call the DownloadManager method to make them appear in the -// bootstrap class path and try again to load the named class. -// Note that with delegation class loaders all classes in another loader will -// first try to call this so it'd better be fast!! -static instanceKlassHandle download_and_retry_class_load( - Symbol* class_name, - TRAPS) { - - Klass* dlm = SystemDictionary::DownloadManager_klass(); - instanceKlassHandle nk; - - // If download manager class isn't loaded just return. - if (dlm == NULL) return nk; - - { HandleMark hm(THREAD); - ResourceMark rm(THREAD); - Handle s = java_lang_String::create_from_symbol(class_name, CHECK_(nk)); - Handle class_string = java_lang_String::externalize_classname(s, CHECK_(nk)); - - // return value - JavaValue result(T_OBJECT); - - // Call the DownloadManager. We assume that it has a lock because - // multiple classes could be not found and downloaded at the same time. - // class sun.misc.DownloadManager; - // public static String getBootClassPathEntryForClass(String className); - JavaCalls::call_static(&result, - KlassHandle(THREAD, dlm), - vmSymbols::getBootClassPathEntryForClass_name(), - vmSymbols::string_string_signature(), - class_string, - CHECK_(nk)); - - // Get result.string and add to bootclasspath - assert(result.get_type() == T_OBJECT, "just checking"); - oop obj = (oop) result.get_jobject(); - if (obj == NULL) { return nk; } - - Handle h_obj(THREAD, obj); - char* new_class_name = java_lang_String::as_platform_dependent_str(h_obj, - CHECK_(nk)); - - // lock the loader - // we use this lock because JVMTI does. - Handle loader_lock(THREAD, SystemDictionary::system_loader_lock()); - - ObjectLocker ol(loader_lock, THREAD); - // add the file to the bootclasspath - ClassLoader::update_class_path_entry_list(new_class_name, true); - } // end HandleMark - - if (TraceClassLoading) { - ClassLoader::print_bootclasspath(); - } - return ClassLoader::load_classfile(class_name, CHECK_(nk)); -} -#endif // KERNEL - instanceKlassHandle SystemDictionary::load_instance_class(Symbol* class_name, Handle class_loader, TRAPS) { instanceKlassHandle nh = instanceKlassHandle(); // null Handle @@ -1278,15 +1218,6 @@ instanceKlassHandle SystemDictionary::load_instance_class(Symbol* class_name, Ha k = ClassLoader::load_classfile(class_name, CHECK_(nh)); } -#ifdef KERNEL - // If the VM class loader has failed to load the class, call the - // DownloadManager class to make it magically appear on the classpath - // and try again. This is only configured with the Kernel VM. - if (k.is_null()) { - k = download_and_retry_class_load(class_name, CHECK_(nh)); - } -#endif // KERNEL - // find_or_define_instance_class may return a different InstanceKlass if (!k.is_null()) { k = find_or_define_instance_class(class_name, class_loader, k, CHECK_(nh)); @@ -1822,13 +1753,7 @@ bool SystemDictionary::initialize_wk_klass(WKID id, int init_opt, TRAPS) { Symbol* symbol = vmSymbols::symbol_at((vmSymbols::SID)sid); Klass** klassp = &_well_known_klasses[id]; bool must_load = (init_opt < SystemDictionary::Opt); - bool try_load = true; - if (init_opt == SystemDictionary::Opt_Kernel) { -#ifndef KERNEL - try_load = false; -#endif //KERNEL - } - if ((*klassp) == NULL && try_load) { + if ((*klassp) == NULL) { if (must_load) { (*klassp) = resolve_or_fail(symbol, true, CHECK_0); // load required class } else { @@ -1918,12 +1843,6 @@ void SystemDictionary::initialize_preloaded_classes(TRAPS) { //_box_klasses[T_OBJECT] = WK_KLASS(object_klass); //_box_klasses[T_ARRAY] = WK_KLASS(object_klass); -#ifdef KERNEL - if (DownloadManager_klass() == NULL) { - warning("Cannot find sun/jkernel/DownloadManager"); - } -#endif // KERNEL - { // Compute whether we should use loadClass or loadClassInternal when loading classes. Method* method = InstanceKlass::cast(ClassLoader_klass())->find_method(vmSymbols::loadClassInternal_name(), vmSymbols::string_class_signature()); _has_loadClassInternal = (method != NULL); diff --git a/hotspot/src/share/vm/classfile/systemDictionary.hpp b/hotspot/src/share/vm/classfile/systemDictionary.hpp index e2f660ee171..d415c9b1e4f 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.hpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.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 @@ -168,8 +168,6 @@ class SymbolPropertyTable; /* It's okay if this turns out to be NULL in non-1.4 JDKs. */ \ do_klass(nio_Buffer_klass, java_nio_Buffer, Opt ) \ \ - do_klass(DownloadManager_klass, sun_jkernel_DownloadManager, Opt_Kernel ) \ - \ do_klass(PostVMInitHook_klass, sun_misc_PostVMInitHook, Opt ) \ \ /* Preload boxing klasses */ \ @@ -211,7 +209,6 @@ class SystemDictionary : AllStatic { Opt, // preload tried; NULL if not present Opt_Only_JDK14NewRef, // preload tried; use only with NewReflection Opt_Only_JDK15, // preload tried; use only with JDK1.5+ - Opt_Kernel, // preload tried only #ifdef KERNEL OPTION_LIMIT, CEIL_LG_OPTION_LIMIT = 4 // OPTION_LIMIT <= (1<print_short_name(tty); tty->cr(); } - method->set_not_compilable_quietly(); + method->set_not_compilable(CompLevel_all, !quietly, "excluded by CompilerOracle"); } return false; diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp index 78d956ff11d..cb8b73743e1 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp @@ -102,7 +102,7 @@ CompactibleFreeListSpace::CompactibleFreeListSpace(BlockOffsetSharedArray* bs, // temporarily disabled). switch (dictionaryChoice) { case FreeBlockDictionary::dictionaryBinaryTree: - _dictionary = new BinaryTreeDictionary(mr); + _dictionary = new AFLBinaryTreeDictionary(mr); break; case FreeBlockDictionary::dictionarySplayTree: case FreeBlockDictionary::dictionarySkipList: @@ -122,7 +122,8 @@ CompactibleFreeListSpace::CompactibleFreeListSpace(BlockOffsetSharedArray* bs, // moved to its new location before the klass is moved. // Set the _refillSize for the linear allocation blocks if (!use_adaptive_freelists) { - FreeChunk* fc = _dictionary->get_chunk(mr.word_size()); + FreeChunk* fc = _dictionary->get_chunk(mr.word_size(), + FreeBlockDictionary::atLeast); // The small linAB initially has all the space and will allocate // a chunk of any size. HeapWord* addr = (HeapWord*) fc; @@ -1647,7 +1648,8 @@ CompactibleFreeListSpace::getChunkFromIndexedFreeListHelper(size_t size, FreeChunk* CompactibleFreeListSpace::getChunkFromDictionary(size_t size) { assert_locked(); - FreeChunk* fc = _dictionary->get_chunk(size); + FreeChunk* fc = _dictionary->get_chunk(size, + FreeBlockDictionary::atLeast); if (fc == NULL) { return NULL; } @@ -1664,7 +1666,8 @@ CompactibleFreeListSpace::getChunkFromDictionary(size_t size) { FreeChunk* CompactibleFreeListSpace::getChunkFromDictionaryExact(size_t size) { assert_locked(); - FreeChunk* fc = _dictionary->get_chunk(size); + FreeChunk* fc = _dictionary->get_chunk(size, + FreeBlockDictionary::atLeast); if (fc == NULL) { return fc; } @@ -1677,7 +1680,8 @@ CompactibleFreeListSpace::getChunkFromDictionaryExact(size_t size) { if (fc->size() < size + MinChunkSize) { // Return the chunk to the dictionary and go get a bigger one. returnChunkToDictionary(fc); - fc = _dictionary->get_chunk(size + MinChunkSize); + fc = _dictionary->get_chunk(size + MinChunkSize, + FreeBlockDictionary::atLeast); if (fc == NULL) { return NULL; } diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp index 1b3d93ed248..23c95897cfa 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp @@ -131,7 +131,7 @@ class CompactibleFreeListSpace: public CompactibleSpace { LinearAllocBlock _smallLinearAllocBlock; FreeBlockDictionary::DictionaryChoice _dictionaryChoice; - FreeBlockDictionary* _dictionary; // ptr to dictionary for large size blocks + AFLBinaryTreeDictionary* _dictionary; // ptr to dictionary for large size blocks AdaptiveFreeList _indexedFreeList[IndexSetSize]; // indexed array for small size blocks diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/vmStructs_cms.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/vmStructs_cms.hpp index a67e19d89d2..1a46ed3f52d 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/vmStructs_cms.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/vmStructs_cms.hpp @@ -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 @@ -25,8 +25,6 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_VMSTRUCTS_CMS_HPP #define SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_VMSTRUCTS_CMS_HPP -typedef BinaryTreeDictionary AFLBinaryTreeDictionary; - #define VM_STRUCTS_CMS(nonstatic_field, \ volatile_nonstatic_field, \ static_field) \ @@ -34,14 +32,15 @@ typedef BinaryTreeDictionary AFLBinaryTreeDictionar nonstatic_field(CompactibleFreeListSpace, _bt, BlockOffsetArrayNonContigSpace) \ \ nonstatic_field(CMSBitMap, _bmWordSize, size_t) \ - nonstatic_field(CMSBitMap, _shifter, const int) \ - nonstatic_field(CMSBitMap, _bm, BitMap) \ - nonstatic_field(CMSBitMap, _virtual_space, VirtualSpace) \ + nonstatic_field(CMSBitMap, _shifter, const int) \ + nonstatic_field(CMSBitMap, _bm, BitMap) \ + nonstatic_field(CMSBitMap, _virtual_space, VirtualSpace) \ nonstatic_field(CMSCollector, _markBitMap, CMSBitMap) \ nonstatic_field(ConcurrentMarkSweepGeneration, _cmsSpace, CompactibleFreeListSpace*) \ static_field(ConcurrentMarkSweepThread, _collector, CMSCollector*) \ nonstatic_field(LinearAllocBlock, _word_size, size_t) \ nonstatic_field(AFLBinaryTreeDictionary, _total_size, size_t) \ + nonstatic_field(CompactibleFreeListSpace, _dictionary, AFLBinaryTreeDictionary*) \ nonstatic_field(CompactibleFreeListSpace, _indexedFreeList[0], FreeList) \ nonstatic_field(CompactibleFreeListSpace, _smallLinearAllocBlock, LinearAllocBlock) @@ -62,10 +61,9 @@ typedef BinaryTreeDictionary AFLBinaryTreeDictionar declare_toplevel_type(SurrogateLockerThread*) \ declare_toplevel_type(CompactibleFreeListSpace*) \ declare_toplevel_type(CMSCollector*) \ - declare_toplevel_type(AFLBinaryTreeDictionary*) \ + declare_toplevel_type(AFLBinaryTreeDictionary) \ declare_toplevel_type(LinearAllocBlock) \ - declare_toplevel_type(FreeBlockDictionary) \ - declare_type(AFLBinaryTreeDictionary, FreeBlockDictionary) + declare_toplevel_type(FreeBlockDictionary) #define VM_INT_CONSTANTS_CMS(declare_constant) \ declare_constant(Generation::ConcurrentMarkSweep) \ diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp index 3199cbf5a60..28c733c150f 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp @@ -571,19 +571,14 @@ ConcurrentMark::ConcurrentMark(G1CollectedHeap* g1h, ReservedSpace heap_rs) : _sleep_factor = 0.0; _marking_task_overhead = 1.0; } else { - if (ConcGCThreads > 0) { - // notice that ConcGCThreads overwrites G1MarkingOverheadPercent + if (!FLAG_IS_DEFAULT(ConcGCThreads) && ConcGCThreads > 0) { + // Note: ConcGCThreads has precedence over G1MarkingOverheadPercent // if both are set - - _parallel_marking_threads = (uint) ConcGCThreads; - _max_parallel_marking_threads = _parallel_marking_threads; _sleep_factor = 0.0; _marking_task_overhead = 1.0; } else if (G1MarkingOverheadPercent > 0) { - // we will calculate the number of parallel marking threads - // based on a target overhead with respect to the soft real-time - // goal - + // We will calculate the number of parallel marking threads based + // on a target overhead with respect to the soft real-time goal double marking_overhead = (double) G1MarkingOverheadPercent / 100.0; double overall_cm_overhead = (double) MaxGCPauseMillis * marking_overhead / @@ -596,17 +591,22 @@ ConcurrentMark::ConcurrentMark(G1CollectedHeap* g1h, ReservedSpace heap_rs) : double sleep_factor = (1.0 - marking_task_overhead) / marking_task_overhead; - _parallel_marking_threads = (uint) marking_thread_num; - _max_parallel_marking_threads = _parallel_marking_threads; + FLAG_SET_ERGO(uintx, ConcGCThreads, (uint) marking_thread_num); _sleep_factor = sleep_factor; _marking_task_overhead = marking_task_overhead; } else { - _parallel_marking_threads = scale_parallel_threads((uint)ParallelGCThreads); - _max_parallel_marking_threads = _parallel_marking_threads; + // Calculate the number of parallel marking threads by scaling + // the number of parallel GC threads. + uint marking_thread_num = scale_parallel_threads((uint) ParallelGCThreads); + FLAG_SET_ERGO(uintx, ConcGCThreads, marking_thread_num); _sleep_factor = 0.0; _marking_task_overhead = 1.0; } + assert(ConcGCThreads > 0, "Should have been set"); + _parallel_marking_threads = (uint) ConcGCThreads; + _max_parallel_marking_threads = _parallel_marking_threads; + if (parallel_marking_threads() > 1) { _cleanup_task_overhead = 1.0; } else { @@ -1190,7 +1190,7 @@ void ConcurrentMark::scanRootRegions() { uint active_workers = MAX2(1U, parallel_marking_threads()); CMRootRegionScanTask task(this); - if (parallel_marking_threads() > 0) { + if (use_parallel_marking_threads()) { _parallel_workers->set_active_workers((int) active_workers); _parallel_workers->run_task(&task); } else { @@ -1226,7 +1226,7 @@ void ConcurrentMark::markFromRoots() { set_phase(active_workers, true /* concurrent */); CMConcurrentMarkingTask markingTask(this, cmThread()); - if (parallel_marking_threads() > 0) { + if (use_parallel_marking_threads()) { _parallel_workers->set_active_workers((int)active_workers); // Don't set _n_par_threads because it affects MT in proceess_strong_roots() // and the decisions on that MT processing is made elsewhere. @@ -2167,7 +2167,8 @@ void ConcurrentMark::completeCleanup() { assert(tmp_free_list.is_empty(), "post-condition"); } -// Support closures for reference procssing in G1 +// Supporting Object and Oop closures for reference discovery +// and processing in during marking bool G1CMIsAliveClosure::do_object_b(oop obj) { HeapWord* addr = (HeapWord*)obj; @@ -2175,73 +2176,26 @@ bool G1CMIsAliveClosure::do_object_b(oop obj) { (!_g1->is_in_g1_reserved(addr) || !_g1->is_obj_ill(obj)); } -class G1CMKeepAliveClosure: public ExtendedOopClosure { - G1CollectedHeap* _g1; - ConcurrentMark* _cm; - public: - G1CMKeepAliveClosure(G1CollectedHeap* g1, ConcurrentMark* cm) : - _g1(g1), _cm(cm) { - assert(Thread::current()->is_VM_thread(), "otherwise fix worker id"); - } +// 'Keep Alive' oop closure used by both serial parallel reference processing. +// Uses the CMTask associated with a worker thread (for serial reference +// processing the CMTask for worker 0 is used) to preserve (mark) and +// trace referent objects. +// +// Using the CMTask and embedded local queues avoids having the worker +// threads operating on the global mark stack. This reduces the risk +// of overflowing the stack - which we would rather avoid at this late +// state. Also using the tasks' local queues removes the potential +// of the workers interfering with each other that could occur if +// operating on the global stack. - virtual void do_oop(narrowOop* p) { do_oop_work(p); } - virtual void do_oop( oop* p) { do_oop_work(p); } - - template void do_oop_work(T* p) { - oop obj = oopDesc::load_decode_heap_oop(p); - HeapWord* addr = (HeapWord*)obj; - - if (_cm->verbose_high()) { - gclog_or_tty->print_cr("\t[0] we're looking at location " - "*"PTR_FORMAT" = "PTR_FORMAT, - p, (void*) obj); - } - - if (_g1->is_in_g1_reserved(addr) && _g1->is_obj_ill(obj)) { - _cm->mark_and_count(obj); - _cm->mark_stack_push(obj); - } - } -}; - -class G1CMDrainMarkingStackClosure: public VoidClosure { - ConcurrentMark* _cm; - CMMarkStack* _markStack; - G1CMKeepAliveClosure* _oopClosure; - public: - G1CMDrainMarkingStackClosure(ConcurrentMark* cm, CMMarkStack* markStack, - G1CMKeepAliveClosure* oopClosure) : - _cm(cm), - _markStack(markStack), - _oopClosure(oopClosure) { } - - void do_void() { - _markStack->drain(_oopClosure, _cm->nextMarkBitMap(), false); - } -}; - -// 'Keep Alive' closure used by parallel reference processing. -// An instance of this closure is used in the parallel reference processing -// code rather than an instance of G1CMKeepAliveClosure. We could have used -// the G1CMKeepAliveClosure as it is MT-safe. Also reference objects are -// placed on to discovered ref lists once so we can mark and push with no -// need to check whether the object has already been marked. Using the -// G1CMKeepAliveClosure would mean, however, having all the worker threads -// operating on the global mark stack. This means that an individual -// worker would be doing lock-free pushes while it processes its own -// discovered ref list followed by drain call. If the discovered ref lists -// are unbalanced then this could cause interference with the other -// workers. Using a CMTask (and its embedded local data structures) -// avoids that potential interference. -class G1CMParKeepAliveAndDrainClosure: public OopClosure { +class G1CMKeepAliveAndDrainClosure: public OopClosure { ConcurrentMark* _cm; CMTask* _task; int _ref_counter_limit; int _ref_counter; public: - G1CMParKeepAliveAndDrainClosure(ConcurrentMark* cm, CMTask* task) : - _cm(cm), _task(task), - _ref_counter_limit(G1RefProcDrainInterval) { + G1CMKeepAliveAndDrainClosure(ConcurrentMark* cm, CMTask* task) : + _cm(cm), _task(task), _ref_counter_limit(G1RefProcDrainInterval) { assert(_ref_counter_limit > 0, "sanity"); _ref_counter = _ref_counter_limit; } @@ -2262,18 +2216,22 @@ class G1CMParKeepAliveAndDrainClosure: public OopClosure { _ref_counter--; if (_ref_counter == 0) { - // We have dealt with _ref_counter_limit references, pushing them and objects - // reachable from them on to the local stack (and possibly the global stack). - // Call do_marking_step() to process these entries. We call the routine in a - // loop, which we'll exit if there's nothing more to do (i.e. we're done - // with the entries that we've pushed as a result of the deal_with_reference - // calls above) or we overflow. - // Note: CMTask::do_marking_step() can set the CMTask::has_aborted() flag - // while there may still be some work to do. (See the comment at the - // beginning of CMTask::do_marking_step() for those conditions - one of which - // is reaching the specified time target.) It is only when - // CMTask::do_marking_step() returns without setting the has_aborted() flag - // that the marking has completed. + // We have dealt with _ref_counter_limit references, pushing them + // and objects reachable from them on to the local stack (and + // possibly the global stack). Call CMTask::do_marking_step() to + // process these entries. + // + // We call CMTask::do_marking_step() in a loop, which we'll exit if + // there's nothing more to do (i.e. we're done with the entries that + // were pushed as a result of the CMTask::deal_with_reference() calls + // above) or we overflow. + // + // Note: CMTask::do_marking_step() can set the CMTask::has_aborted() + // flag while there may still be some work to do. (See the comment at + // the beginning of CMTask::do_marking_step() for those conditions - + // one of which is reaching the specified time target.) It is only + // when CMTask::do_marking_step() returns without setting the + // has_aborted() flag that the marking step has completed. do { double mark_step_duration_ms = G1ConcMarkStepDurationMillis; _task->do_marking_step(mark_step_duration_ms, @@ -2290,36 +2248,59 @@ class G1CMParKeepAliveAndDrainClosure: public OopClosure { } }; -class G1CMParDrainMarkingStackClosure: public VoidClosure { +// 'Drain' oop closure used by both serial and parallel reference processing. +// Uses the CMTask associated with a given worker thread (for serial +// reference processing the CMtask for worker 0 is used). Calls the +// do_marking_step routine, with an unbelievably large timeout value, +// to drain the marking data structures of the remaining entries +// added by the 'keep alive' oop closure above. + +class G1CMDrainMarkingStackClosure: public VoidClosure { ConcurrentMark* _cm; - CMTask* _task; + CMTask* _task; + bool _do_stealing; + bool _do_termination; public: - G1CMParDrainMarkingStackClosure(ConcurrentMark* cm, CMTask* task) : - _cm(cm), _task(task) { } + G1CMDrainMarkingStackClosure(ConcurrentMark* cm, CMTask* task, bool is_par) : + _cm(cm), _task(task) { + assert(is_par || _task->worker_id() == 0, + "Only task for worker 0 should be used if ref processing is single threaded"); + // We only allow stealing and only enter the termination protocol + // in CMTask::do_marking_step() if this closure is being instantiated + // for parallel reference processing. + _do_stealing = _do_termination = is_par; + } void do_void() { do { if (_cm->verbose_high()) { - gclog_or_tty->print_cr("\t[%u] Drain: Calling do marking_step", - _task->worker_id()); + gclog_or_tty->print_cr("\t[%u] Drain: Calling do_marking_step - " + "stealing: %s, termination: %s", + _task->worker_id(), + BOOL_TO_STR(_do_stealing), + BOOL_TO_STR(_do_termination)); } - // We call CMTask::do_marking_step() to completely drain the local and - // global marking stacks. The routine is called in a loop, which we'll - // exit if there's nothing more to do (i.e. we'completely drained the - // entries that were pushed as a result of applying the - // G1CMParKeepAliveAndDrainClosure to the entries on the discovered ref - // lists above) or we overflow the global marking stack. - // Note: CMTask::do_marking_step() can set the CMTask::has_aborted() flag - // while there may still be some work to do. (See the comment at the - // beginning of CMTask::do_marking_step() for those conditions - one of which - // is reaching the specified time target.) It is only when - // CMTask::do_marking_step() returns without setting the has_aborted() flag - // that the marking has completed. + // We call CMTask::do_marking_step() to completely drain the local + // and global marking stacks of entries pushed by the 'keep alive' + // oop closure (an instance of G1CMKeepAliveAndDrainClosure above). + // + // CMTask::do_marking_step() is called in a loop, which we'll exit + // if there's nothing more to do (i.e. we'completely drained the + // entries that were pushed as a a result of applying the 'keep alive' + // closure to the entries on the discovered ref lists) or we overflow + // the global marking stack. + // + // Note: CMTask::do_marking_step() can set the CMTask::has_aborted() + // flag while there may still be some work to do. (See the comment at + // the beginning of CMTask::do_marking_step() for those conditions - + // one of which is reaching the specified time target.) It is only + // when CMTask::do_marking_step() returns without setting the + // has_aborted() flag that the marking step has completed. _task->do_marking_step(1000000000.0 /* something very large */, - true /* do_stealing */, - true /* do_termination */); + _do_stealing, + _do_termination); } while (_task->has_aborted() && !_cm->has_overflown()); } }; @@ -2352,19 +2333,23 @@ class G1CMRefProcTaskProxy: public AbstractGangTask { ProcessTask& _proc_task; G1CollectedHeap* _g1h; ConcurrentMark* _cm; + bool _processing_is_mt; public: G1CMRefProcTaskProxy(ProcessTask& proc_task, G1CollectedHeap* g1h, ConcurrentMark* cm) : AbstractGangTask("Process reference objects in parallel"), - _proc_task(proc_task), _g1h(g1h), _cm(cm) { } + _proc_task(proc_task), _g1h(g1h), _cm(cm) { + ReferenceProcessor* rp = _g1h->ref_processor_cm(); + _processing_is_mt = rp->processing_is_mt(); + } virtual void work(uint worker_id) { CMTask* marking_task = _cm->task(worker_id); G1CMIsAliveClosure g1_is_alive(_g1h); - G1CMParKeepAliveAndDrainClosure g1_par_keep_alive(_cm, marking_task); - G1CMParDrainMarkingStackClosure g1_par_drain(_cm, marking_task); + G1CMKeepAliveAndDrainClosure g1_par_keep_alive(_cm, marking_task); + G1CMDrainMarkingStackClosure g1_par_drain(_cm, marking_task, _processing_is_mt); _proc_task.work(worker_id, g1_is_alive, g1_par_keep_alive, g1_par_drain); } @@ -2372,6 +2357,7 @@ public: void G1CMRefProcTaskExecutor::execute(ProcessTask& proc_task) { assert(_workers != NULL, "Need parallel worker threads."); + assert(_g1h->ref_processor_cm()->processing_is_mt(), "processing is not MT"); G1CMRefProcTaskProxy proc_task_proxy(proc_task, _g1h, _cm); @@ -2399,6 +2385,7 @@ public: void G1CMRefProcTaskExecutor::execute(EnqueueTask& enq_task) { assert(_workers != NULL, "Need parallel worker threads."); + assert(_g1h->ref_processor_cm()->processing_is_mt(), "processing is not MT"); G1CMRefEnqueueTaskProxy enq_task_proxy(enq_task); @@ -2429,59 +2416,58 @@ void ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) { // See the comment in G1CollectedHeap::ref_processing_init() // about how reference processing currently works in G1. - // Process weak references. + // Set the soft reference policy rp->setup_policy(clear_all_soft_refs); assert(_markStack.isEmpty(), "mark stack should be empty"); - G1CMKeepAliveClosure g1_keep_alive(g1h, this); - G1CMDrainMarkingStackClosure - g1_drain_mark_stack(this, &_markStack, &g1_keep_alive); + // Non-MT instances 'Keep Alive' and 'Complete GC' oop closures. + G1CMKeepAliveAndDrainClosure g1_keep_alive(this, task(0)); + G1CMDrainMarkingStackClosure g1_drain_mark_stack(this, task(0), false); + + // We need at least one active thread. If reference processing is + // not multi-threaded we use the current (ConcurrentMarkThread) thread, + // otherwise we use the work gang from the G1CollectedHeap and we + // utilize all the worker threads we can. + uint active_workers = (rp->processing_is_mt() && g1h->workers() != NULL + ? g1h->workers()->active_workers() + : 1U); - // We use the work gang from the G1CollectedHeap and we utilize all - // the worker threads. - uint active_workers = g1h->workers() ? g1h->workers()->active_workers() : 1U; active_workers = MAX2(MIN2(active_workers, _max_worker_id), 1U); G1CMRefProcTaskExecutor par_task_executor(g1h, this, g1h->workers(), active_workers); - if (rp->processing_is_mt()) { - // Set the degree of MT here. If the discovery is done MT, there - // may have been a different number of threads doing the discovery - // and a different number of discovered lists may have Ref objects. - // That is OK as long as the Reference lists are balanced (see - // balance_all_queues() and balance_queues()). - rp->set_active_mt_degree(active_workers); + AbstractRefProcTaskExecutor* executor = (rp->processing_is_mt() + ? &par_task_executor + : NULL); - rp->process_discovered_references(&g1_is_alive, + // Set the degree of MT processing here. If the discovery was done MT, + // the number of threads involved during discovery could differ from + // the number of active workers. This is OK as long as the discovered + // Reference lists are balanced (see balance_all_queues() and balance_queues()). + rp->set_active_mt_degree(active_workers); + + // Process the weak references. + rp->process_discovered_references(&g1_is_alive, &g1_keep_alive, &g1_drain_mark_stack, - &par_task_executor); + executor); - // The work routines of the parallel keep_alive and drain_marking_stack - // will set the has_overflown flag if we overflow the global marking - // stack. - } else { - rp->process_discovered_references(&g1_is_alive, - &g1_keep_alive, - &g1_drain_mark_stack, - NULL); - } + // The do_oop work routines of the keep_alive and drain_marking_stack + // oop closures will set the has_overflown flag if we overflow the + // global marking stack. assert(_markStack.overflow() || _markStack.isEmpty(), "mark stack should be empty (unless it overflowed)"); if (_markStack.overflow()) { - // Should have been done already when we tried to push an + // This should have been done already when we tried to push an // entry on to the global mark stack. But let's do it again. set_has_overflown(); } - if (rp->processing_is_mt()) { - assert(rp->num_q() == active_workers, "why not"); - rp->enqueue_discovered_references(&par_task_executor); - } else { - rp->enqueue_discovered_references(); - } + assert(rp->num_q() == active_workers, "why not"); + + rp->enqueue_discovered_references(executor); rp->verify_no_references_recorded(); assert(!rp->discovery_enabled(), "Post condition"); @@ -3242,7 +3228,9 @@ void ConcurrentMark::print_summary_info() { } void ConcurrentMark::print_worker_threads_on(outputStream* st) const { - _parallel_workers->print_worker_threads_on(st); + if (use_parallel_marking_threads()) { + _parallel_workers->print_worker_threads_on(st); + } } // We take a break if someone is trying to stop the world. diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp index 34c5601e050..6ec27c7d9fa 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp @@ -371,8 +371,8 @@ class ConcurrentMark: public CHeapObj { friend class CalcLiveObjectsClosure; friend class G1CMRefProcTaskProxy; friend class G1CMRefProcTaskExecutor; - friend class G1CMParKeepAliveAndDrainClosure; - friend class G1CMParDrainMarkingStackClosure; + friend class G1CMKeepAliveAndDrainClosure; + friend class G1CMDrainMarkingStackClosure; protected: ConcurrentMarkThread* _cmThread; // the thread doing the work @@ -499,17 +499,26 @@ protected: } // accessor methods - uint parallel_marking_threads() { return _parallel_marking_threads; } - uint max_parallel_marking_threads() { return _max_parallel_marking_threads;} - double sleep_factor() { return _sleep_factor; } - double marking_task_overhead() { return _marking_task_overhead;} - double cleanup_sleep_factor() { return _cleanup_sleep_factor; } - double cleanup_task_overhead() { return _cleanup_task_overhead;} + uint parallel_marking_threads() const { return _parallel_marking_threads; } + uint max_parallel_marking_threads() const { return _max_parallel_marking_threads;} + double sleep_factor() { return _sleep_factor; } + double marking_task_overhead() { return _marking_task_overhead;} + double cleanup_sleep_factor() { return _cleanup_sleep_factor; } + double cleanup_task_overhead() { return _cleanup_task_overhead;} - HeapWord* finger() { return _finger; } - bool concurrent() { return _concurrent; } - uint active_tasks() { return _active_tasks; } - ParallelTaskTerminator* terminator() { return &_terminator; } + bool use_parallel_marking_threads() const { + assert(parallel_marking_threads() <= + max_parallel_marking_threads(), "sanity"); + assert((_parallel_workers == NULL && parallel_marking_threads() == 0) || + parallel_marking_threads() > 0, + "parallel workers not set up correctly"); + return _parallel_workers != NULL; + } + + HeapWord* finger() { return _finger; } + bool concurrent() { return _concurrent; } + uint active_tasks() { return _active_tasks; } + ParallelTaskTerminator* terminator() { return &_terminator; } // It claims the next available region to be scanned by a marking // task/thread. It might return NULL if the next region is empty or diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp index dde3ba4be31..6f887583cab 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp @@ -28,8 +28,9 @@ #include "memory/cardTableModRefBS.hpp" #include "memory/memRegion.hpp" #include "oops/oop.inline.hpp" +#include "utilities/macros.hpp" -#ifndef SERIALGC +#if INCLUDE_ALL_GCS class DirtyCardQueueSet; @@ -120,6 +121,6 @@ class G1SATBCardTableLoggingModRefBS: public G1SATBCardTableModRefBS { }; -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1SATBCARDTABLEMODREFBS_HPP diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp index 4f1c5493fc5..7c79195d3e5 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp @@ -32,8 +32,9 @@ #include "gc_implementation/shared/spaceDecorator.hpp" #include "memory/space.inline.hpp" #include "memory/watermark.hpp" +#include "utilities/macros.hpp" -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // A HeapRegion is the smallest piece of a G1CollectedHeap that // can be collected independently. @@ -837,6 +838,6 @@ class HeapRegionClosure : public StackObj { bool complete() { return _complete; } }; -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS #endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGION_HPP diff --git a/hotspot/src/share/vm/gc_implementation/shared/allocationStats.cpp b/hotspot/src/share/vm/gc_implementation/shared/allocationStats.cpp index c24fc3bbf1a..7cc37fd9453 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/allocationStats.cpp +++ b/hotspot/src/share/vm/gc_implementation/shared/allocationStats.cpp @@ -23,10 +23,11 @@ */ #include "precompiled.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/shared/allocationStats.hpp" #include "utilities/ostream.hpp" -#endif +#endif // INCLUDE_ALL_GCS // Technically this should be derived from machine speed, and // ideally it would be dynamically adjusted. diff --git a/hotspot/src/share/vm/gc_implementation/shared/allocationStats.hpp b/hotspot/src/share/vm/gc_implementation/shared/allocationStats.hpp index df1ee1ea2e5..cf7cd3ae0f2 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/allocationStats.hpp +++ b/hotspot/src/share/vm/gc_implementation/shared/allocationStats.hpp @@ -25,11 +25,12 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_SHARED_ALLOCATIONSTATS_HPP #define SHARE_VM_GC_IMPLEMENTATION_SHARED_ALLOCATIONSTATS_HPP -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/shared/gcUtil.hpp" #include "memory/allocation.hpp" #include "utilities/globalDefinitions.hpp" -#endif +#endif // INCLUDE_ALL_GCS class AllocationStats VALUE_OBJ_CLASS_SPEC { // A duration threshold (in ms) used to filter diff --git a/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.hpp b/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.hpp index 77d041d70ca..6530d23b624 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.hpp +++ b/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.hpp @@ -25,9 +25,10 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_SHARED_CONCURRENTGCTHREAD_HPP #define SHARE_VM_GC_IMPLEMENTATION_SHARED_CONCURRENTGCTHREAD_HPP -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "runtime/thread.hpp" -#endif +#endif // INCLUDE_ALL_GCS class VoidClosure; diff --git a/hotspot/src/share/vm/gc_implementation/shared/gSpaceCounters.cpp b/hotspot/src/share/vm/gc_implementation/shared/gSpaceCounters.cpp index 4a8f85ab2a1..506322de521 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/gSpaceCounters.cpp +++ b/hotspot/src/share/vm/gc_implementation/shared/gSpaceCounters.cpp @@ -23,11 +23,12 @@ */ #include "precompiled.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/shared/gSpaceCounters.hpp" #include "memory/generation.hpp" #include "memory/resourceArea.hpp" -#endif +#endif // INCLUDE_ALL_GCS GSpaceCounters::GSpaceCounters(const char* name, int ordinal, size_t max_size, Generation* g, GenerationCounters* gc, diff --git a/hotspot/src/share/vm/gc_implementation/shared/gSpaceCounters.hpp b/hotspot/src/share/vm/gc_implementation/shared/gSpaceCounters.hpp index 745dac7417b..c54e773c364 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/gSpaceCounters.hpp +++ b/hotspot/src/share/vm/gc_implementation/shared/gSpaceCounters.hpp @@ -25,11 +25,12 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_SHARED_GSPACECOUNTERS_HPP #define SHARE_VM_GC_IMPLEMENTATION_SHARED_GSPACECOUNTERS_HPP -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/shared/generationCounters.hpp" #include "memory/generation.hpp" #include "runtime/perfData.hpp" -#endif +#endif // INCLUDE_ALL_GCS // A GSpaceCounter is a holder class for performance counters // that track a space; diff --git a/hotspot/src/share/vm/gc_implementation/shared/gcAdaptivePolicyCounters.hpp b/hotspot/src/share/vm/gc_implementation/shared/gcAdaptivePolicyCounters.hpp index c1758a2fc19..5024ab9e7ab 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/gcAdaptivePolicyCounters.hpp +++ b/hotspot/src/share/vm/gc_implementation/shared/gcAdaptivePolicyCounters.hpp @@ -25,10 +25,11 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_SHARED_GCADAPTIVEPOLICYCOUNTERS_HPP #define SHARE_VM_GC_IMPLEMENTATION_SHARED_GCADAPTIVEPOLICYCOUNTERS_HPP -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/shared/adaptiveSizePolicy.hpp" #include "gc_implementation/shared/gcPolicyCounters.hpp" -#endif +#endif // INCLUDE_ALL_GCS // This class keeps statistical information and computes the // size of the heap. diff --git a/hotspot/src/share/vm/gc_implementation/shared/hSpaceCounters.hpp b/hotspot/src/share/vm/gc_implementation/shared/hSpaceCounters.hpp index f3b956ee67a..034d319b078 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/hSpaceCounters.hpp +++ b/hotspot/src/share/vm/gc_implementation/shared/hSpaceCounters.hpp @@ -25,11 +25,12 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_SHARED_HSPACECOUNTERS_HPP #define SHARE_VM_GC_IMPLEMENTATION_SHARED_HSPACECOUNTERS_HPP -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/shared/generationCounters.hpp" #include "memory/generation.hpp" #include "runtime/perfData.hpp" -#endif +#endif // INCLUDE_ALL_GCS // A HSpaceCounter is a holder class for performance counters // that track a collections (logical spaces) in a heap; diff --git a/hotspot/src/share/vm/gc_implementation/shared/immutableSpace.cpp b/hotspot/src/share/vm/gc_implementation/shared/immutableSpace.cpp index 30eb04df6a8..c844a3e596d 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/immutableSpace.cpp +++ b/hotspot/src/share/vm/gc_implementation/shared/immutableSpace.cpp @@ -23,11 +23,12 @@ */ #include "precompiled.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/shared/immutableSpace.hpp" #include "memory/universe.hpp" #include "oops/oop.inline.hpp" -#endif +#endif // INCLUDE_ALL_GCS void ImmutableSpace::initialize(MemRegion mr) { HeapWord* bottom = mr.start(); diff --git a/hotspot/src/share/vm/gc_implementation/shared/isGCActiveMark.hpp b/hotspot/src/share/vm/gc_implementation/shared/isGCActiveMark.hpp index 4d36417244c..c56cbafeb2e 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/isGCActiveMark.hpp +++ b/hotspot/src/share/vm/gc_implementation/shared/isGCActiveMark.hpp @@ -25,9 +25,10 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_SHARED_ISGCACTIVEMARK_HPP #define SHARE_VM_GC_IMPLEMENTATION_SHARED_ISGCACTIVEMARK_HPP -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" -#endif +#endif // INCLUDE_ALL_GCS // This class provides a method for block structured setting of the // _is_gc_active state without requiring accessors in CollectedHeap diff --git a/hotspot/src/share/vm/gc_implementation/shared/markSweep.inline.hpp b/hotspot/src/share/vm/gc_implementation/shared/markSweep.inline.hpp index 3a3cbdd8c96..9752291959a 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/markSweep.inline.hpp +++ b/hotspot/src/share/vm/gc_implementation/shared/markSweep.inline.hpp @@ -28,9 +28,10 @@ #include "gc_implementation/shared/markSweep.hpp" #include "gc_interface/collectedHeap.hpp" #include "utilities/stack.inline.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/parallelScavenge/psParallelCompact.hpp" -#endif +#endif // INCLUDE_ALL_GCS inline void MarkSweep::mark_object(oop obj) { // some marks may contain information we need to preserve so we store them away diff --git a/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.hpp b/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.hpp index 8b8f8d65e21..5621c077c38 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.hpp +++ b/hotspot/src/share/vm/gc_implementation/shared/mutableNUMASpace.hpp @@ -25,10 +25,11 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_SHARED_MUTABLENUMASPACE_HPP #define SHARE_VM_GC_IMPLEMENTATION_SHARED_MUTABLENUMASPACE_HPP -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/shared/gcUtil.hpp" #include "gc_implementation/shared/mutableSpace.hpp" -#endif +#endif // INCLUDE_ALL_GCS /* * The NUMA-aware allocator (MutableNUMASpace) is basically a modification diff --git a/hotspot/src/share/vm/gc_implementation/shared/mutableSpace.cpp b/hotspot/src/share/vm/gc_implementation/shared/mutableSpace.cpp index e573e02dfd6..d50edac13ca 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/mutableSpace.cpp +++ b/hotspot/src/share/vm/gc_implementation/shared/mutableSpace.cpp @@ -23,13 +23,14 @@ */ #include "precompiled.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/shared/mutableSpace.hpp" #include "gc_implementation/shared/spaceDecorator.hpp" #include "oops/oop.inline.hpp" #include "runtime/safepoint.hpp" #include "runtime/thread.hpp" -#endif +#endif // INCLUDE_ALL_GCS MutableSpace::MutableSpace(size_t alignment): ImmutableSpace(), _top(NULL), _alignment(alignment) { assert(MutableSpace::alignment() >= 0 && diff --git a/hotspot/src/share/vm/gc_implementation/shared/spaceCounters.cpp b/hotspot/src/share/vm/gc_implementation/shared/spaceCounters.cpp index 48dddd85b9d..f606e99e9a1 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/spaceCounters.cpp +++ b/hotspot/src/share/vm/gc_implementation/shared/spaceCounters.cpp @@ -23,10 +23,11 @@ */ #include "precompiled.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/shared/spaceCounters.hpp" #include "memory/resourceArea.hpp" -#endif +#endif // INCLUDE_ALL_GCS SpaceCounters::SpaceCounters(const char* name, int ordinal, size_t max_size, MutableSpace* m, GenerationCounters* gc) : diff --git a/hotspot/src/share/vm/gc_implementation/shared/spaceCounters.hpp b/hotspot/src/share/vm/gc_implementation/shared/spaceCounters.hpp index 6b13e5acfd2..17302d420b2 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/spaceCounters.hpp +++ b/hotspot/src/share/vm/gc_implementation/shared/spaceCounters.hpp @@ -25,12 +25,13 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_SHARED_SPACECOUNTERS_HPP #define SHARE_VM_GC_IMPLEMENTATION_SHARED_SPACECOUNTERS_HPP -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/shared/generationCounters.hpp" #include "gc_implementation/shared/immutableSpace.hpp" #include "gc_implementation/shared/mutableSpace.hpp" #include "runtime/perfData.hpp" -#endif +#endif // INCLUDE_ALL_GCS // A SpaceCounter is a holder class for performance counters // that track a space; diff --git a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp index ee1be4a6490..756ed28f010 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp +++ b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.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 @@ -36,9 +36,10 @@ #include "runtime/interfaceSupport.hpp" #include "utilities/dtrace.hpp" #include "utilities/preserveException.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" -#endif +#endif // INCLUDE_ALL_GCS #ifndef USDT2 HS_DTRACE_PROBE_DECL1(hotspot, gc__begin, bool); @@ -167,7 +168,9 @@ void VM_GC_HeapInspection::doit() { ch->collect_as_vm_thread(GCCause::_heap_inspection); } } - HeapInspection::heap_inspection(_out, _need_prologue /* need_prologue */); + HeapInspection inspect(_csv_format, _print_help, _print_class_stats, + _columns); + inspect.heap_inspection(_out, _need_prologue /* need_prologue */); } diff --git a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.hpp b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.hpp index 285ef97e378..2a416f22843 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.hpp +++ b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.hpp @@ -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 @@ -130,6 +130,10 @@ class VM_GC_HeapInspection: public VM_GC_Operation { outputStream* _out; bool _full_gc; bool _need_prologue; + bool _csv_format; // "comma separated values" format for spreadsheet. + bool _print_help; + bool _print_class_stats; + const char* _columns; public: VM_GC_HeapInspection(outputStream* out, bool request_full_gc, bool need_prologue) : @@ -140,6 +144,10 @@ class VM_GC_HeapInspection: public VM_GC_Operation { _out = out; _full_gc = request_full_gc; _need_prologue = need_prologue; + _csv_format = false; + _print_help = false; + _print_class_stats = false; + _columns = NULL; } ~VM_GC_HeapInspection() {} @@ -147,6 +155,10 @@ class VM_GC_HeapInspection: public VM_GC_Operation { virtual bool skip_operation() const; virtual bool doit_prologue(); virtual void doit(); + void set_csv_format(bool value) {_csv_format = value;} + void set_print_help(bool value) {_print_help = value;} + void set_print_class_stats(bool value) {_print_class_stats = value;} + void set_columns(const char* value) {_columns = value;} }; diff --git a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp index 0d139fdf71c..55ef63ee9d0 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp @@ -3099,9 +3099,9 @@ BytecodeInterpreter::print() { tty->print_cr("&native_fresult: " INTPTR_FORMAT, (uintptr_t) &this->_native_fresult); tty->print_cr("native_lresult: " INTPTR_FORMAT, (uintptr_t) this->_native_lresult); #endif -#if defined(IA64) && !defined(ZERO) +#if !defined(ZERO) tty->print_cr("last_Java_fp: " INTPTR_FORMAT, (uintptr_t) this->_last_Java_fp); -#endif // IA64 && !ZERO +#endif // !ZERO tty->print_cr("self_link: " INTPTR_FORMAT, (uintptr_t) this->_self_link); } diff --git a/hotspot/src/share/vm/interpreter/linkResolver.cpp b/hotspot/src/share/vm/interpreter/linkResolver.cpp index 959388fc693..efb2a164fa2 100644 --- a/hotspot/src/share/vm/interpreter/linkResolver.cpp +++ b/hotspot/src/share/vm/interpreter/linkResolver.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 @@ -1241,7 +1241,7 @@ void LinkResolver::resolve_handle_call(CallInfo& result, KlassHandle resolved_kl void LinkResolver::resolve_invokedynamic(CallInfo& result, constantPoolHandle pool, int index, TRAPS) { assert(EnableInvokeDynamic, ""); - pool->set_invokedynamic(); // mark header to flag active call sites + pool->set_has_invokedynamic(); // mark header to flag active call sites //resolve_pool(, method_name, method_signature, current_klass, pool, index, CHECK); Symbol* method_name = pool->name_ref_at(index); diff --git a/hotspot/src/share/vm/memory/allocation.hpp b/hotspot/src/share/vm/memory/allocation.hpp index 3cade72c260..e1e266ec5cf 100644 --- a/hotspot/src/share/vm/memory/allocation.hpp +++ b/hotspot/src/share/vm/memory/allocation.hpp @@ -145,9 +145,10 @@ enum MemoryType { mtChunk = 0x0B00, // chunk that holds content of arenas mtJavaHeap = 0x0C00, // Java heap mtClassShared = 0x0D00, // class data sharing - mt_number_of_types = 0x000D, // number of memory types (mtDontTrack + mtTest = 0x0E00, // Test type for verifying NMT + mt_number_of_types = 0x000E, // number of memory types (mtDontTrack // is not included as validate type) - mtDontTrack = 0x0E00, // memory we do not or cannot track + mtDontTrack = 0x0F00, // memory we do not or cannot track mt_masks = 0x7F00, // object type mask diff --git a/hotspot/src/share/vm/memory/binaryTreeDictionary.cpp b/hotspot/src/share/vm/memory/binaryTreeDictionary.cpp index 725a71925dc..8ed2b61a921 100644 --- a/hotspot/src/share/vm/memory/binaryTreeDictionary.cpp +++ b/hotspot/src/share/vm/memory/binaryTreeDictionary.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "utilities/macros.hpp" #include "gc_implementation/shared/allocationStats.hpp" #include "memory/binaryTreeDictionary.hpp" #include "memory/freeList.hpp" @@ -31,12 +32,13 @@ #include "memory/metachunk.hpp" #include "runtime/globals.hpp" #include "utilities/ostream.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/adaptiveFreeList.hpp" #include "gc_implementation/concurrentMarkSweep/freeChunk.hpp" #include "gc_implementation/shared/spaceDecorator.hpp" #include "gc_implementation/concurrentMarkSweep/freeChunk.hpp" -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS //////////////////////////////////////////////////////////////////////////////// // A binary tree based search structure for free blocks. @@ -118,7 +120,7 @@ TreeList::as_TreeList(HeapWord* addr, size_t size) { } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Specialize for AdaptiveFreeList which tries to avoid // splitting a chunk of a size that is under populated in favor of // an over populated size. The general get_better_list() just returns @@ -160,7 +162,7 @@ TreeList::get_better_list( } return curTL; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS template class FreeList_t> TreeList* @@ -871,9 +873,9 @@ size_t BinaryTreeDictionary::total_nodes_in_tree(TreeList class FreeList_t> void BinaryTreeDictionary::dict_census_update(size_t size, bool split, bool birth){} -#ifndef SERIALGC +#if INCLUDE_ALL_GCS template <> -void BinaryTreeDictionary::dict_census_update(size_t size, bool split, bool birth){ +void AFLBinaryTreeDictionary::dict_census_update(size_t size, bool split, bool birth){ TreeList* nd = find_list(size); if (nd) { if (split) { @@ -900,7 +902,7 @@ void BinaryTreeDictionary::dict_census_update(size_ // This is a birth associated with a LinAB. The chunk // for the LinAB is not in the dictionary. } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS template class FreeList_t> bool BinaryTreeDictionary::coal_dict_over_populated(size_t size) { @@ -909,9 +911,9 @@ bool BinaryTreeDictionary::coal_dict_over_populated(size_t return true; } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS template <> -bool BinaryTreeDictionary::coal_dict_over_populated(size_t size) { +bool AFLBinaryTreeDictionary::coal_dict_over_populated(size_t size) { if (FLSAlwaysCoalesceLarge) return true; TreeList* list_of_size = find_list(size); @@ -919,7 +921,7 @@ bool BinaryTreeDictionary::coal_dict_over_populated return list_of_size == NULL || list_of_size->coal_desired() <= 0 || list_of_size->count() > list_of_size->coal_desired(); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // Closures for walking the binary tree. // do_list() walks the free list in a node applying the closure @@ -979,7 +981,7 @@ class BeginSweepClosure : public AscendTreeCensusClosure { void do_list(FreeList* fl) {} -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void do_list(AdaptiveFreeList* fl) { double coalSurplusPercent = _percentage; fl->compute_desired(_inter_sweep_current, _inter_sweep_estimate, _intra_sweep_estimate); @@ -987,7 +989,7 @@ class BeginSweepClosure : public AscendTreeCensusClosure { fl->set_before_sweep(fl->count()); fl->set_bfr_surp(fl->surplus()); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS }; // Used to search the tree until a condition is met. @@ -1134,13 +1136,13 @@ class setTreeSurplusClosure : public AscendTreeCensusClosure* fl) {} -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void do_list(AdaptiveFreeList* fl) { double splitSurplusPercent = percentage; fl->set_surplus(fl->count() - (ssize_t)((double)fl->desired() * splitSurplusPercent)); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS }; template class FreeList_t> @@ -1157,7 +1159,7 @@ class setTreeHintsClosure : public DescendTreeCensusClosure setTreeHintsClosure(size_t v) { hint = v; } void do_list(FreeList* fl) {} -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void do_list(AdaptiveFreeList* fl) { fl->set_hint(hint); assert(fl->hint() == 0 || fl->hint() > fl->size(), @@ -1166,7 +1168,7 @@ class setTreeHintsClosure : public DescendTreeCensusClosure hint = fl->size(); } } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS }; template class FreeList_t> @@ -1180,7 +1182,7 @@ template class FreeList_t> class clearTreeCensusClosure : public AscendTreeCensusClosure { void do_list(FreeList* fl) {} -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void do_list(AdaptiveFreeList* fl) { fl->set_prev_sweep(fl->count()); fl->set_coal_births(0); @@ -1188,7 +1190,7 @@ class clearTreeCensusClosure : public AscendTreeCensusClosureset_split_births(0); fl->set_split_deaths(0); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS }; template class FreeList_t> @@ -1252,7 +1254,7 @@ class PrintTreeCensusClosure : public AscendTreeCensusClosureset_count( total()->count() + fl->count() ); } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void do_list(AdaptiveFreeList* fl) { if (++_print_line >= 40) { FreeList_t::print_labels_on(gclog_or_tty, "size"); @@ -1271,7 +1273,7 @@ class PrintTreeCensusClosure : public AscendTreeCensusClosureset_split_births(total()->split_births() + fl->split_births()); total()->set_split_deaths(total()->split_deaths() + fl->split_deaths()); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS }; template class FreeList_t> @@ -1286,9 +1288,9 @@ void BinaryTreeDictionary::print_dict_census(void) const { FreeList_t::print_labels_on(gclog_or_tty, " "); } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS template <> -void BinaryTreeDictionary::print_dict_census(void) const { +void AFLBinaryTreeDictionary::print_dict_census(void) const { gclog_or_tty->print("\nBinaryTree\n"); AdaptiveFreeList::print_labels_on(gclog_or_tty, "size"); @@ -1308,7 +1310,7 @@ void BinaryTreeDictionary::print_dict_census(void) (double)(total->desired() - total->count()) /(total->desired() != 0 ? (double)total->desired() : 1.0)); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS template class FreeList_t> class PrintFreeListsClosure : public AscendTreeCensusClosure { @@ -1414,10 +1416,10 @@ template class BinaryTreeDictionary; template class TreeChunk; -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Explicitly instantiate these types for FreeChunk. template class TreeList; template class BinaryTreeDictionary; template class TreeChunk; -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS diff --git a/hotspot/src/share/vm/memory/binaryTreeDictionary.hpp b/hotspot/src/share/vm/memory/binaryTreeDictionary.hpp index 757eb4fdac9..460a4ea29e1 100644 --- a/hotspot/src/share/vm/memory/binaryTreeDictionary.hpp +++ b/hotspot/src/share/vm/memory/binaryTreeDictionary.hpp @@ -43,6 +43,10 @@ template class FreeList_t> class AscendTreeCens template class FreeList_t> class DescendTreeCensusClosure; template class FreeList_t> class DescendTreeSearchClosure; +class FreeChunk; +template class AdaptiveFreeList; +typedef BinaryTreeDictionary AFLBinaryTreeDictionary; + template class FreeList_t> class TreeList : public FreeList_t { friend class TreeChunk; diff --git a/hotspot/src/share/vm/memory/cardTableModRefBS.cpp b/hotspot/src/share/vm/memory/cardTableModRefBS.cpp index bd0c79ed439..d3fa82d8566 100644 --- a/hotspot/src/share/vm/memory/cardTableModRefBS.cpp +++ b/hotspot/src/share/vm/memory/cardTableModRefBS.cpp @@ -34,6 +34,7 @@ #include "runtime/mutexLocker.hpp" #include "runtime/virtualspace.hpp" #include "services/memTracker.hpp" +#include "utilities/macros.hpp" #ifdef COMPILER1 #include "c1/c1_LIR.hpp" #include "c1/c1_LIRGenerator.hpp" @@ -499,13 +500,13 @@ void CardTableModRefBS::non_clean_card_iterate_possibly_parallel(Space* sp, int n_threads = SharedHeap::heap()->n_par_threads(); bool is_par = n_threads > 0; if (is_par) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS assert(SharedHeap::heap()->n_par_threads() == SharedHeap::heap()->workers()->active_workers(), "Mismatch"); non_clean_card_iterate_parallel_work(sp, mr, cl, ct, n_threads); -#else // SERIALGC +#else // INCLUDE_ALL_GCS fatal("Parallel gc not supported here."); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS } else { // We do not call the non_clean_card_iterate_serial() version below because // we want to clear the cards (which non_clean_card_iterate_serial() does not diff --git a/hotspot/src/share/vm/memory/cardTableRS.cpp b/hotspot/src/share/vm/memory/cardTableRS.cpp index d16b3ec0be5..d92de481644 100644 --- a/hotspot/src/share/vm/memory/cardTableRS.cpp +++ b/hotspot/src/share/vm/memory/cardTableRS.cpp @@ -31,10 +31,11 @@ #include "oops/oop.inline.hpp" #include "runtime/java.hpp" #include "runtime/os.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/concurrentMark.hpp" #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" -#endif +#endif // INCLUDE_ALL_GCS CardTableRS::CardTableRS(MemRegion whole_heap, int max_covered_regions) : @@ -42,7 +43,7 @@ CardTableRS::CardTableRS(MemRegion whole_heap, _cur_youngergen_card_val(youngergenP1_card), _regions_to_iterate(max_covered_regions - 1) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS if (UseG1GC) { _ct_bs = new G1SATBCardTableLoggingModRefBS(whole_heap, max_covered_regions); diff --git a/hotspot/src/share/vm/memory/collectorPolicy.cpp b/hotspot/src/share/vm/memory/collectorPolicy.cpp index b13d9761120..2645cec46ae 100644 --- a/hotspot/src/share/vm/memory/collectorPolicy.cpp +++ b/hotspot/src/share/vm/memory/collectorPolicy.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 @@ -39,10 +39,11 @@ #include "runtime/java.hpp" #include "runtime/thread.inline.hpp" #include "runtime/vmThread.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/cmsAdaptiveSizePolicy.hpp" #include "gc_implementation/concurrentMarkSweep/cmsGCAdaptivePolicyCounters.hpp" -#endif +#endif // INCLUDE_ALL_GCS // CollectorPolicy methods. @@ -235,6 +236,18 @@ void TwoGenerationCollectorPolicy::initialize_flags() { if (NewSize + OldSize > MaxHeapSize) { MaxHeapSize = NewSize + OldSize; } + + if (FLAG_IS_CMDLINE(OldSize) && FLAG_IS_DEFAULT(NewSize)) { + // NewRatio will be used later to set the young generation size so we use + // it to calculate how big the heap should be based on the requested OldSize + // and NewRatio. + assert(NewRatio > 0, "NewRatio should have been set up earlier"); + size_t calculated_heapsize = (OldSize / NewRatio) * (NewRatio + 1); + + calculated_heapsize = align_size_up(calculated_heapsize, max_alignment()); + MaxHeapSize = calculated_heapsize; + InitialHeapSize = calculated_heapsize; + } MaxHeapSize = align_size_up(MaxHeapSize, max_alignment()); always_do_update_barrier = UseConcMarkSweepGC; @@ -384,14 +397,15 @@ void GenCollectorPolicy::initialize_size_info() { // keeping it simple also seems a worthwhile goal. bool TwoGenerationCollectorPolicy::adjust_gen0_sizes(size_t* gen0_size_ptr, size_t* gen1_size_ptr, - size_t heap_size, - size_t min_gen0_size) { + const size_t heap_size, + const size_t min_gen1_size) { bool result = false; + if ((*gen1_size_ptr + *gen0_size_ptr) > heap_size) { - if (((*gen0_size_ptr + OldSize) > heap_size) && - (heap_size - min_gen0_size) >= min_alignment()) { - // Adjust gen0 down to accomodate OldSize - *gen0_size_ptr = heap_size - min_gen0_size; + if ((heap_size < (*gen0_size_ptr + min_gen1_size)) && + (heap_size >= min_gen1_size + min_alignment())) { + // Adjust gen0 down to accommodate min_gen1_size + *gen0_size_ptr = heap_size - min_gen1_size; *gen0_size_ptr = MAX2((uintx)align_size_down(*gen0_size_ptr, min_alignment()), min_alignment()); diff --git a/hotspot/src/share/vm/memory/collectorPolicy.hpp b/hotspot/src/share/vm/memory/collectorPolicy.hpp index a079f71b95b..4acf7ba780c 100644 --- a/hotspot/src/share/vm/memory/collectorPolicy.hpp +++ b/hotspot/src/share/vm/memory/collectorPolicy.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 @@ -29,6 +29,7 @@ #include "memory/barrierSet.hpp" #include "memory/generationSpec.hpp" #include "memory/genRemSet.hpp" +#include "utilities/macros.hpp" // This class (or more correctly, subtypes of this class) // are used to define global garbage collector attributes. @@ -48,10 +49,10 @@ class GenCollectorPolicy; class TwoGenerationCollectorPolicy; class AdaptiveSizePolicy; -#ifndef SERIALGC +#if INCLUDE_ALL_GCS class ConcurrentMarkSweepPolicy; class G1CollectorPolicy; -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS class GCPolicyCounters; class MarkSweepPolicy; @@ -134,21 +135,21 @@ class CollectorPolicy : public CHeapObj { virtual GenCollectorPolicy* as_generation_policy() { return NULL; } virtual TwoGenerationCollectorPolicy* as_two_generation_policy() { return NULL; } virtual MarkSweepPolicy* as_mark_sweep_policy() { return NULL; } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS virtual ConcurrentMarkSweepPolicy* as_concurrent_mark_sweep_policy() { return NULL; } virtual G1CollectorPolicy* as_g1_policy() { return NULL; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // Note that these are not virtual. bool is_generation_policy() { return as_generation_policy() != NULL; } bool is_two_generation_policy() { return as_two_generation_policy() != NULL; } bool is_mark_sweep_policy() { return as_mark_sweep_policy() != NULL; } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS bool is_concurrent_mark_sweep_policy() { return as_concurrent_mark_sweep_policy() != NULL; } bool is_g1_policy() { return as_g1_policy() != NULL; } -#else // SERIALGC +#else // INCLUDE_ALL_GCS bool is_concurrent_mark_sweep_policy() { return false; } bool is_g1_policy() { return false; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS virtual BarrierSet::Name barrier_set_name() = 0; @@ -321,7 +322,7 @@ class TwoGenerationCollectorPolicy : public GenCollectorPolicy { // Returns true is gen0 sizes were adjusted bool adjust_gen0_sizes(size_t* gen0_size_ptr, size_t* gen1_size_ptr, - size_t heap_size, size_t min_gen1_size); + const size_t heap_size, const size_t min_gen1_size); }; class MarkSweepPolicy : public TwoGenerationCollectorPolicy { diff --git a/hotspot/src/share/vm/memory/filemap.cpp b/hotspot/src/share/vm/memory/filemap.cpp index fe0958073e3..fec0957f145 100644 --- a/hotspot/src/share/vm/memory/filemap.cpp +++ b/hotspot/src/share/vm/memory/filemap.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 @@ -210,13 +210,14 @@ void FileMapInfo::open_for_write() { tty->print_cr(" %s", _full_path); } - // Remove the existing file in case another process has it open. - remove(_full_path); -#ifdef _WINDOWS // if 0444 is used on Windows, then remove() will fail. - int fd = open(_full_path, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0744); -#else - int fd = open(_full_path, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0444); +#ifdef _WINDOWS // On Windows, need WRITE permission to remove the file. + chmod(_full_path, _S_IREAD | _S_IWRITE); #endif + + // Use remove() to delete the existing file because, on Unix, this will + // allow processes that have it open continued access to the file. + remove(_full_path); + int fd = open(_full_path, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0444); if (fd < 0) { fail_stop("Unable to create shared archive file %s.", _full_path); } diff --git a/hotspot/src/share/vm/memory/freeBlockDictionary.cpp b/hotspot/src/share/vm/memory/freeBlockDictionary.cpp index 918a80f1fb3..713036ea500 100644 --- a/hotspot/src/share/vm/memory/freeBlockDictionary.cpp +++ b/hotspot/src/share/vm/memory/freeBlockDictionary.cpp @@ -23,13 +23,15 @@ */ #include "precompiled.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/freeChunk.hpp" -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS #include "memory/freeBlockDictionary.hpp" #include "memory/metablock.hpp" #include "memory/metachunk.hpp" #include "runtime/thread.inline.hpp" +#include "utilities/macros.hpp" #ifndef PRODUCT template Mutex* FreeBlockDictionary::par_lock() const { @@ -56,7 +58,7 @@ template void FreeBlockDictionary::verify_par_locked() cons template class FreeBlockDictionary; template class FreeBlockDictionary; -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Explicitly instantiate for FreeChunk template class FreeBlockDictionary; -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS diff --git a/hotspot/src/share/vm/memory/freeList.cpp b/hotspot/src/share/vm/memory/freeList.cpp index f5cd80545c0..05e4ef0a290 100644 --- a/hotspot/src/share/vm/memory/freeList.cpp +++ b/hotspot/src/share/vm/memory/freeList.cpp @@ -31,10 +31,11 @@ #include "runtime/globals.hpp" #include "runtime/mutex.hpp" #include "runtime/vmThread.hpp" +#include "utilities/macros.hpp" -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/freeChunk.hpp" -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // Free list. A FreeList is used to access a linked list of chunks // of space in the heap. The head and tail are maintained so that @@ -341,6 +342,6 @@ void FreeList::print_on(outputStream* st, const char* c) const { template class FreeList; template class FreeList; -#ifndef SERIALGC +#if INCLUDE_ALL_GCS template class FreeList; -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS diff --git a/hotspot/src/share/vm/memory/genCollectedHeap.cpp b/hotspot/src/share/vm/memory/genCollectedHeap.cpp index 13778b06d50..9d65cc15701 100644 --- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp +++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp @@ -51,10 +51,11 @@ #include "services/memoryService.hpp" #include "utilities/vmError.hpp" #include "utilities/workgroup.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp" #include "gc_implementation/concurrentMarkSweep/vmCMSOperations.hpp" -#endif +#endif // INCLUDE_ALL_GCS GenCollectedHeap* GenCollectedHeap::_gch; NOT_PRODUCT(size_t GenCollectedHeap::_skip_header_HeapWords = 0;) @@ -141,14 +142,14 @@ jint GenCollectedHeap::initialize() { } clear_incremental_collection_failed(); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // If we are running CMS, create the collector responsible // for collecting the CMS generations. if (collector_policy()->is_concurrent_mark_sweep_policy()) { bool success = create_cms_collector(); if (!success) return JNI_ENOMEM; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS return JNI_OK; } @@ -686,12 +687,12 @@ size_t GenCollectedHeap::unsafe_max_alloc() { void GenCollectedHeap::collect(GCCause::Cause cause) { if (should_do_concurrent_full_gc(cause)) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // mostly concurrent full collection collect_mostly_concurrent(cause); -#else // SERIALGC +#else // INCLUDE_ALL_GCS ShouldNotReachHere(); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS } else { #ifdef ASSERT if (cause == GCCause::_scavenge_alot) { @@ -736,7 +737,7 @@ void GenCollectedHeap::collect_locked(GCCause::Cause cause, int max_level) { } } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS bool GenCollectedHeap::create_cms_collector() { assert(((_gens[1]->kind() == Generation::ConcurrentMarkSweep) || @@ -772,7 +773,7 @@ void GenCollectedHeap::collect_mostly_concurrent(GCCause::Cause cause) { VMThread::execute(&op); } } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS void GenCollectedHeap::do_full_collection(bool clear_all_soft_refs) { do_full_collection(clear_all_soft_refs, _n_gens - 1); @@ -1116,22 +1117,22 @@ void GenCollectedHeap::gc_threads_do(ThreadClosure* tc) const { if (workers() != NULL) { workers()->threads_do(tc); } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS if (UseConcMarkSweepGC) { ConcurrentMarkSweepThread::threads_do(tc); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS } void GenCollectedHeap::print_gc_threads_on(outputStream* st) const { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS if (UseParNewGC) { workers()->print_worker_threads_on(st); } if (UseConcMarkSweepGC) { ConcurrentMarkSweepThread::print_all_on(st); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS } void GenCollectedHeap::print_tracing_info() const { diff --git a/hotspot/src/share/vm/memory/generationSpec.cpp b/hotspot/src/share/vm/memory/generationSpec.cpp index 30c79ea6f29..d97a56fbbcc 100644 --- a/hotspot/src/share/vm/memory/generationSpec.cpp +++ b/hotspot/src/share/vm/memory/generationSpec.cpp @@ -30,11 +30,12 @@ #include "memory/generationSpec.hpp" #include "memory/tenuredGeneration.hpp" #include "runtime/java.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/parNew/asParNewGeneration.hpp" #include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp" #include "gc_implementation/parNew/parNewGeneration.hpp" -#endif +#endif // INCLUDE_ALL_GCS Generation* GenerationSpec::init(ReservedSpace rs, int level, GenRemSet* remset) { @@ -45,7 +46,7 @@ Generation* GenerationSpec::init(ReservedSpace rs, int level, case Generation::MarkSweepCompact: return new TenuredGeneration(rs, init_size(), level, remset); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS case Generation::ParNew: return new ParNewGeneration(rs, init_size(), level); @@ -94,7 +95,7 @@ Generation* GenerationSpec::init(ReservedSpace rs, int level, return g; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS default: guarantee(false, "unrecognized GenerationName"); diff --git a/hotspot/src/share/vm/memory/heapInspection.cpp b/hotspot/src/share/vm/memory/heapInspection.cpp index 71674fcb2d5..a51ea1d1561 100644 --- a/hotspot/src/share/vm/memory/heapInspection.cpp +++ b/hotspot/src/share/vm/memory/heapInspection.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 @@ -23,15 +23,17 @@ */ #include "precompiled.hpp" +#include "classfile/classLoaderData.hpp" #include "gc_interface/collectedHeap.hpp" #include "memory/genCollectedHeap.hpp" #include "memory/heapInspection.hpp" #include "memory/resourceArea.hpp" #include "runtime/os.hpp" #include "utilities/globalDefinitions.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" -#endif +#endif // INCLUDE_ALL_GCS // HeapInspection @@ -41,12 +43,24 @@ int KlassInfoEntry::compare(KlassInfoEntry* e1, KlassInfoEntry* e2) { } else if(e1->_instance_words < e2->_instance_words) { return 1; } - return 0; + // Sort alphabetically, note 'Z' < '[' < 'a', but it's better to group + // the array classes before all the instance classes. + ResourceMark rm; + const char* name1 = e1->klass()->external_name(); + const char* name2 = e2->klass()->external_name(); + bool d1 = (name1[0] == '['); + bool d2 = (name2[0] == '['); + if (d1 && !d2) { + return -1; + } else if (d2 && !d1) { + return 1; + } else { + return strcmp(name1, name2); + } } -void KlassInfoEntry::print_on(outputStream* st) const { - ResourceMark rm; - const char* name;; +const char* KlassInfoEntry::name() const { + const char* name; if (_klass->name() != NULL) { name = _klass->external_name(); } else { @@ -60,11 +74,17 @@ void KlassInfoEntry::print_on(outputStream* st) const { if (_klass == Universe::longArrayKlassObj()) name = ""; else name = ""; } + return name; +} + +void KlassInfoEntry::print_on(outputStream* st) const { + ResourceMark rm; + // simplify the formatting (ILP32 vs LP64) - always cast the numbers to 64-bit st->print_cr(INT64_FORMAT_W(13) " " UINT64_FORMAT_W(13) " %s", (jlong) _instance_count, (julong) _instance_words * HeapWordSize, - name); + name()); } KlassInfoEntry* KlassInfoBucket::lookup(Klass* const k) { @@ -101,7 +121,14 @@ void KlassInfoBucket::empty() { } } -KlassInfoTable::KlassInfoTable(int size, HeapWord* ref) { +void KlassInfoTable::AllClassesFinder::do_klass(Klass* k) { + // This has the SIDE EFFECT of creating a KlassInfoEntry + // for , if one doesn't exist yet. + _table->lookup(k); +} + +KlassInfoTable::KlassInfoTable(int size, HeapWord* ref, + bool need_class_stats) { _size = 0; _ref = ref; _buckets = NEW_C_HEAP_ARRAY(KlassInfoBucket, size, mtInternal); @@ -110,6 +137,10 @@ KlassInfoTable::KlassInfoTable(int size, HeapWord* ref) { for (int index = 0; index < _size; index++) { _buckets[index].initialize(); } + if (need_class_stats) { + AllClassesFinder finder(this); + ClassLoaderDataGraph::classes_do(&finder); + } } } @@ -165,7 +196,8 @@ int KlassInfoHisto::sort_helper(KlassInfoEntry** e1, KlassInfoEntry** e2) { return (*e1)->compare(*e1,*e2); } -KlassInfoHisto::KlassInfoHisto(const char* title, int estimatedCount) : +KlassInfoHisto::KlassInfoHisto(KlassInfoTable* cit, const char* title, int estimatedCount) : + _cit(cit), _title(title) { _elements = new (ResourceObj::C_HEAP, mtInternal) GrowableArray(estimatedCount,true); } @@ -196,9 +228,205 @@ void KlassInfoHisto::print_elements(outputStream* st) const { total, totalw * HeapWordSize); } -void KlassInfoHisto::print_on(outputStream* st) const { - st->print_cr("%s",title()); - print_elements(st); +#define MAKE_COL_NAME(field, name, help) #name, +#define MAKE_COL_HELP(field, name, help) help, + +static const char *name_table[] = { + HEAP_INSPECTION_COLUMNS_DO(MAKE_COL_NAME) +}; + +static const char *help_table[] = { + HEAP_INSPECTION_COLUMNS_DO(MAKE_COL_HELP) +}; + +bool KlassInfoHisto::is_selected(const char *col_name) { + if (_selected_columns == NULL) { + return true; + } + if (strcmp(_selected_columns, col_name) == 0) { + return true; + } + + const char *start = strstr(_selected_columns, col_name); + if (start == NULL) { + return false; + } + + // The following must be true, because _selected_columns != col_name + if (start > _selected_columns && start[-1] != ',') { + return false; + } + char x = start[strlen(col_name)]; + if (x != ',' && x != '\0') { + return false; + } + + return true; +} + +void KlassInfoHisto::print_title(outputStream* st, bool csv_format, + bool selected[], int width_table[], + const char *name_table[]) { + if (csv_format) { + st->print("Index,Super"); + for (int c=0; cprint(",%s", name_table[c]);} + } + st->print(",ClassName"); + } else { + st->print("Index Super"); + for (int c=0; cprint(str_fmt(width_table[c]), name_table[c]);} + } + st->print(" ClassName"); + } + + if (is_selected("ClassLoader")) { + st->print(",ClassLoader"); + } + st->cr(); +} + +void KlassInfoHisto::print_class_stats(outputStream* st, + bool csv_format, const char *columns) { + ResourceMark rm; + KlassSizeStats sz, sz_sum; + int i; + julong *col_table = (julong*)(&sz); + julong *colsum_table = (julong*)(&sz_sum); + int width_table[KlassSizeStats::_num_columns]; + bool selected[KlassSizeStats::_num_columns]; + + _selected_columns = columns; + + memset(&sz_sum, 0, sizeof(sz_sum)); + for (int c=0; clength(); i++) { + elements()->at(i)->set_index(i+1); + } + + for (int pass=1; pass<=2; pass++) { + if (pass == 2) { + print_title(st, csv_format, selected, width_table, name_table); + } + for(i=0; i < elements()->length(); i++) { + KlassInfoEntry* e = (KlassInfoEntry*)elements()->at(i); + const Klass* k = e->klass(); + + memset(&sz, 0, sizeof(sz)); + sz._inst_count = e->count(); + sz._inst_bytes = HeapWordSize * e->words(); + k->collect_statistics(&sz); + sz._total_bytes = sz._ro_bytes + sz._rw_bytes; + + if (pass == 1) { + for (int c=0; coop_is_instance()) { + Klass* super = ((InstanceKlass*)k)->java_super(); + if (super) { + KlassInfoEntry* super_e = _cit->lookup(super); + if (super_e) { + super_index = super_e->index(); + } + } + } + + if (csv_format) { + st->print("%d,%d", e->index(), super_index); + for (int c=0; cprint("," JULONG_FORMAT, col_table[c]);} + } + st->print(",%s",e->name()); + } else { + st->print("%5d %5d", e->index(), super_index); + for (int c=0; cprint(" %s", e->name()); + } + if (is_selected("ClassLoader")) { + ClassLoaderData* loader_data = k->class_loader_data(); + st->print(","); + loader_data->print_value_on(st); + } + st->cr(); + } + } + + if (pass == 1) { + for (int c=0; cprint(","); + for (int c=0; cprint("," JULONG_FORMAT, colsum_table[c]);} + } + } else { + st->print(" "); + for (int c=0; cprint(" Total"); + if (sz_sum._total_bytes > 0) { + st->cr(); + st->print(" "); + for (int c=0; cprint(str_fmt(width_table[c]), "-"); + break; + default: + { + double perc = (double)(100) * (double)(colsum_table[c]) / (double)sz_sum._total_bytes; + st->print(perc_fmt(width_table[c]), perc); + } + } + } + } + } + } + st->cr(); + + if (!csv_format) { + print_title(st, csv_format, selected, width_table, name_table); + } +} + +julong KlassInfoHisto::annotations_bytes(Array* p) const { + julong bytes = 0; + if (p != NULL) { + for (int i = 0; i < p->length(); i++) { + bytes += count_bytes_array(p->at(i)); + } + bytes += count_bytes_array(p); + } + return bytes; +} + +void KlassInfoHisto::print_histo_on(outputStream* st, bool print_stats, + bool csv_format, const char *columns) { + if (print_stats) { + print_class_stats(st, csv_format, columns); + } else { + st->print_cr("%s",title()); + print_elements(st); + } } class HistoClosure : public KlassInfoClosure { @@ -236,8 +464,26 @@ void HeapInspection::heap_inspection(outputStream* st, bool need_prologue) { CollectedHeap* heap = Universe::heap(); bool is_shared_heap = false; + if (_print_help) { + for (int c=0; cprint("%s:\n\t", name_table[c]); + const int max_col = 60; + int col = 0; + for (const char *p = help_table[c]; *p; p++,col++) { + if (col >= max_col && *p == ' ') { + st->print("\n\t"); + col = 0; + } else { + st->print("%c", *p); + } + } + st->print_cr(".\n"); + } + return; + } + // Collect klass instance info - KlassInfoTable cit(KlassInfoTable::cit_size, ref); + KlassInfoTable cit(KlassInfoTable::cit_size, ref, _print_class_stats); if (!cit.allocation_failed()) { // Iterate over objects in the heap RecordInstanceClosure ric(&cit); @@ -252,14 +498,14 @@ void HeapInspection::heap_inspection(outputStream* st, bool need_prologue) { missed_count); } // Sort and print klass instance info - KlassInfoHisto histo("\n" - " num #instances #bytes class name\n" - "----------------------------------------------", - KlassInfoHisto::histo_initial_size); + const char *title = "\n" + " num #instances #bytes class name\n" + "----------------------------------------------"; + KlassInfoHisto histo(&cit, title, KlassInfoHisto::histo_initial_size); HistoClosure hc(&histo); cit.iterate(&hc); histo.sort(); - histo.print_on(st); + histo.print_histo_on(st, _print_class_stats, _csv_format, _columns); } else { st->print_cr("WARNING: Ran out of C-heap; histogram not generated"); } diff --git a/hotspot/src/share/vm/memory/heapInspection.hpp b/hotspot/src/share/vm/memory/heapInspection.hpp index 72e675850d4..c080cb8425b 100644 --- a/hotspot/src/share/vm/memory/heapInspection.hpp +++ b/hotspot/src/share/vm/memory/heapInspection.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2010, 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 @@ -27,6 +27,8 @@ #include "memory/allocation.inline.hpp" #include "oops/oop.inline.hpp" +#include "oops/annotations.hpp" +#include "utilities/macros.hpp" #if INCLUDE_SERVICES @@ -44,16 +46,144 @@ // to KlassInfoEntry's and is used to sort // the entries. +#define HEAP_INSPECTION_COLUMNS_DO(f) \ + f(inst_size, InstSize, \ + "Size of each object instance of the Java class") \ + f(inst_count, InstCount, \ + "Number of object instances of the Java class") \ + f(inst_bytes, InstBytes, \ + "This is usually (InstSize * InstNum). The only exception is " \ + "java.lang.Class, whose InstBytes also includes the slots " \ + "used to store static fields. InstBytes is not counted in " \ + "ROAll, RWAll or Total") \ + f(mirror_bytes, Mirror, \ + "Size of the Klass::java_mirror() object") \ + f(klass_bytes, KlassBytes, \ + "Size of the InstanceKlass or ArrayKlass for this class. " \ + "Note that this includes VTab, ITab, OopMap") \ + f(secondary_supers_bytes, K_secondary_supers, \ + "Number of bytes used by the Klass::secondary_supers() array") \ + f(vtab_bytes, VTab, \ + "Size of the embedded vtable in InstanceKlass") \ + f(itab_bytes, ITab, \ + "Size of the embedded itable in InstanceKlass") \ + f(nonstatic_oopmap_bytes, OopMap, \ + "Size of the embedded nonstatic_oop_map in InstanceKlass") \ + f(methods_array_bytes, IK_methods, \ + "Number of bytes used by the InstanceKlass::methods() array") \ + f(method_ordering_bytes, IK_method_ordering, \ + "Number of bytes used by the InstanceKlass::method_ordering() array") \ + f(local_interfaces_bytes, IK_local_interfaces, \ + "Number of bytes used by the InstanceKlass::local_interfaces() array") \ + f(transitive_interfaces_bytes, IK_transitive_interfaces, \ + "Number of bytes used by the InstanceKlass::transitive_interfaces() array") \ + f(fields_bytes, IK_fields, \ + "Number of bytes used by the InstanceKlass::fields() array") \ + f(inner_classes_bytes, IK_inner_classes, \ + "Number of bytes used by the InstanceKlass::inner_classes() array") \ + f(signers_bytes, IK_signers, \ + "Number of bytes used by the InstanceKlass::singers() array") \ + f(class_annotations_bytes, class_annotations, \ + "Size of class annotations") \ + f(fields_annotations_bytes, fields_annotations, \ + "Size of field annotations") \ + f(methods_annotations_bytes, methods_annotations, \ + "Size of method annotations") \ + f(methods_parameter_annotations_bytes, methods_parameter_annotations, \ + "Size of method parameter annotations") \ + f(methods_default_annotations_bytes, methods_default_annotations, \ + "Size of methods default annotations") \ + f(type_annotations_bytes, type_annotations, \ + "Size of type annotations") \ + f(annotations_bytes, annotations, \ + "Size of all annotations") \ + f(cp_bytes, Cp, \ + "Size of InstanceKlass::constants()") \ + f(cp_tags_bytes, CpTags, \ + "Size of InstanceKlass::constants()->tags()") \ + f(cp_cache_bytes, CpCache, \ + "Size of InstanceKlass::constants()->cache()") \ + f(cp_operands_bytes, CpOperands, \ + "Size of InstanceKlass::constants()->operands()") \ + f(cp_refmap_bytes, CpRefMap, \ + "Size of InstanceKlass::constants()->reference_map()") \ + f(cp_all_bytes, CpAll, \ + "Sum of Cp + CpTags + CpCache + CpOperands + CpRefMap") \ + f(method_count, MethodCount, \ + "Number of methods in this class") \ + f(method_bytes, MethodBytes, \ + "Size of the Method object") \ + f(const_method_bytes, ConstMethod, \ + "Size of the ConstMethod object") \ + f(method_data_bytes, MethodData, \ + "Size of the MethodData object") \ + f(stackmap_bytes, StackMap, \ + "Size of the stackmap_data") \ + f(bytecode_bytes, Bytecodes, \ + "Of the MethodBytes column, how much are the space taken up by bytecodes") \ + f(method_all_bytes, MethodAll, \ + "Sum of MethodBytes + Constmethod + Stackmap + Methoddata") \ + f(ro_bytes, ROAll, \ + "Size of all class meta data that could (potentially) be placed " \ + "in read-only memory. (This could change with CDS design)") \ + f(rw_bytes, RWAll, \ + "Size of all class meta data that must be placed in read/write " \ + "memory. (This could change with CDS design) ") \ + f(total_bytes, Total, \ + "ROAll + RWAll. Note that this does NOT include InstBytes.") + +// Size statistics for a Klass - filled in by Klass::collect_statistics() +class KlassSizeStats { +public: +#define COUNT_KLASS_SIZE_STATS_FIELD(field, name, help) _index_ ## field, +#define DECLARE_KLASS_SIZE_STATS_FIELD(field, name, help) julong _ ## field; + + enum { + HEAP_INSPECTION_COLUMNS_DO(COUNT_KLASS_SIZE_STATS_FIELD) + _num_columns + }; + + HEAP_INSPECTION_COLUMNS_DO(DECLARE_KLASS_SIZE_STATS_FIELD) + + static int count(oop x) { + return (HeapWordSize * ((x) ? (x)->size() : 0)); + } + + static int count_array(objArrayOop x) { + return (HeapWordSize * ((x) ? (x)->size() : 0)); + } + + template static int count(T* x) { + return (HeapWordSize * ((x) ? (x)->size() : 0)); + } + + template static int count_array(T* x) { + if (x == NULL) { + return 0; + } + if (x->length() == 0) { + // This is a shared array, e.g., Universe::the_empty_int_array(). Don't + // count it to avoid double-counting. + return 0; + } + return HeapWordSize * x->size(); + } +}; + + + + class KlassInfoEntry: public CHeapObj { private: KlassInfoEntry* _next; Klass* _klass; long _instance_count; size_t _instance_words; + long _index; public: KlassInfoEntry(Klass* k, KlassInfoEntry* next) : - _klass(k), _instance_count(0), _instance_words(0), _next(next) + _klass(k), _instance_count(0), _instance_words(0), _next(next), _index(-1) {} KlassInfoEntry* next() { return _next; } bool is_equal(Klass* k) { return k == _klass; } @@ -62,8 +192,11 @@ class KlassInfoEntry: public CHeapObj { void set_count(long ct) { _instance_count = ct; } size_t words() { return _instance_words; } void set_words(size_t wds) { _instance_words = wds; } + void set_index(long index) { _index = index; } + long index() { return _index; } int compare(KlassInfoEntry* e1, KlassInfoEntry* e2); void print_on(outputStream* st) const; + const char* name() const; }; class KlassInfoClosure: public StackObj { @@ -95,45 +228,132 @@ class KlassInfoTable: public StackObj { KlassInfoBucket* _buckets; uint hash(Klass* p); - KlassInfoEntry* lookup(Klass* const k); + KlassInfoEntry* lookup(Klass* const k); // allocates if not found! + + class AllClassesFinder : public KlassClosure { + KlassInfoTable *_table; + public: + AllClassesFinder(KlassInfoTable* table) : _table(table) {} + virtual void do_klass(Klass* k); + }; public: // Table size enum { cit_size = 20011 }; - KlassInfoTable(int size, HeapWord* ref); + KlassInfoTable(int size, HeapWord* ref, bool need_class_stats); ~KlassInfoTable(); bool record_instance(const oop obj); void iterate(KlassInfoClosure* cic); bool allocation_failed() { return _buckets == NULL; } + + friend class KlassInfoHisto; }; class KlassInfoHisto : public StackObj { private: + KlassInfoTable *_cit; GrowableArray* _elements; GrowableArray* elements() const { return _elements; } const char* _title; const char* title() const { return _title; } static int sort_helper(KlassInfoEntry** e1, KlassInfoEntry** e2); void print_elements(outputStream* st) const; + void print_class_stats(outputStream* st, bool csv_format, const char *columns); + julong annotations_bytes(Array* p) const; + const char *_selected_columns; + bool is_selected(const char *col_name); + void print_title(outputStream* st, bool csv_format, + bool selected_columns_table[], int width_table[], + const char *name_table[]); + + template static int count_bytes(T* x) { + return (HeapWordSize * ((x) ? (x)->size() : 0)); + } + + template static int count_bytes_array(T* x) { + if (x == NULL) { + return 0; + } + if (x->length() == 0) { + // This is a shared array, e.g., Universe::the_empty_int_array(). Don't + // count it to avoid double-counting. + return 0; + } + return HeapWordSize * x->size(); + } + + // returns a format string to print a julong with the given width. E.g, + // printf(num_fmt(6), julong(10)) would print out the number 10 with 4 + // leading spaces. + static void print_julong(outputStream* st, int width, julong n) { + int num_spaces = width - julong_width(n); + if (num_spaces > 0) { + st->print(str_fmt(num_spaces), ""); + } + st->print(JULONG_FORMAT, n); + } + + static char* perc_fmt(int width) { + static char buf[32]; + jio_snprintf(buf, sizeof(buf), "%%%d.1f%%%%", width-1); + return buf; + } + + static char* str_fmt(int width) { + static char buf[32]; + jio_snprintf(buf, sizeof(buf), "%%%ds", width); + return buf; + } + + static int julong_width(julong n) { + if (n == 0) { + return 1; + } + int w = 0; + while (n > 0) { + n /= 10; + w += 1; + } + return w; + } + + static int col_width(julong n, const char *name) { + int w = julong_width(n); + int min = (int)(strlen(name)); + if (w < min) { + w = min; + } + // add a leading space for separation. + return w + 1; + } + public: enum { histo_initial_size = 1000 }; - KlassInfoHisto(const char* title, + KlassInfoHisto(KlassInfoTable* cit, const char* title, int estimatedCount); ~KlassInfoHisto(); void add(KlassInfoEntry* cie); - void print_on(outputStream* st) const; + void print_histo_on(outputStream* st, bool print_class_stats, bool csv_format, const char *columns); void sort(); }; #endif // INCLUDE_SERVICES -class HeapInspection : public AllStatic { +class HeapInspection : public StackObj { + bool _csv_format; // "comma separated values" format for spreadsheet. + bool _print_help; + bool _print_class_stats; + const char* _columns; public: - static void heap_inspection(outputStream* st, bool need_prologue) NOT_SERVICES_RETURN; + HeapInspection(bool csv_format, bool print_help, + bool print_class_stats, const char *columns) : + _csv_format(csv_format), _print_help(print_help), + _print_class_stats(print_class_stats), _columns(columns) {} + void heap_inspection(outputStream* st, bool need_prologue) NOT_SERVICES_RETURN; static void find_instances_at_safepoint(Klass* k, GrowableArray* result) NOT_SERVICES_RETURN; }; diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp index f54803a190f..c629e175f09 100644 --- a/hotspot/src/share/vm/memory/metaspace.cpp +++ b/hotspot/src/share/vm/memory/metaspace.cpp @@ -1737,10 +1737,10 @@ void SpaceManager::get_initial_chunk_sizes(Metaspace::MetaspaceType type, *class_chunk_word_size = ClassSmallChunk; break; } - assert(chunk_word_size != 0 && class_chunk_word_size != 0, + assert(*chunk_word_size != 0 && *class_chunk_word_size != 0, err_msg("Initial chunks sizes bad: data " SIZE_FORMAT " class " SIZE_FORMAT, - chunk_word_size, class_chunk_word_size)); + *chunk_word_size, *class_chunk_word_size)); } size_t SpaceManager::sum_free_in_chunks_in_use() const { @@ -2040,7 +2040,7 @@ SpaceManager::~SpaceManager() { align_size_up(humongous_chunks->word_size(), HumongousChunkGranularity), err_msg("Humongous chunk size is wrong: word size " SIZE_FORMAT - " granularity " SIZE_FORMAT, + " granularity %d", humongous_chunks->word_size(), HumongousChunkGranularity)); Metachunk* next_humongous_chunks = humongous_chunks->next(); chunk_manager->humongous_dictionary()->return_chunk(humongous_chunks); @@ -2264,7 +2264,8 @@ void SpaceManager::verify_allocation_total() { } MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag); assert(allocation_total() == sum_used_in_chunks_in_use(), - err_msg("allocation total is not consistent %d vs %d", + err_msg("allocation total is not consistent " SIZE_FORMAT + " vs " SIZE_FORMAT, allocation_total(), sum_used_in_chunks_in_use())); } @@ -2578,7 +2579,8 @@ void Metaspace::global_initialize() { // argument passed in is at the top of the compressed space void Metaspace::initialize_class_space(ReservedSpace rs) { // The reserved space size may be bigger because of alignment, esp with UseLargePages - assert(rs.size() >= ClassMetaspaceSize, err_msg("%d != %d", rs.size(), ClassMetaspaceSize)); + assert(rs.size() >= ClassMetaspaceSize, + err_msg(SIZE_FORMAT " != " UINTX_FORMAT, rs.size(), ClassMetaspaceSize)); _class_space_list = new VirtualSpaceList(rs); } diff --git a/hotspot/src/share/vm/memory/space.cpp b/hotspot/src/share/vm/memory/space.cpp index ca3882df0ef..7eb462ecccc 100644 --- a/hotspot/src/share/vm/memory/space.cpp +++ b/hotspot/src/share/vm/memory/space.cpp @@ -40,6 +40,7 @@ #include "runtime/safepoint.hpp" #include "utilities/copy.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" void SpaceMemRegionOopsIterClosure::do_oop(oop* p) { SpaceMemRegionOopsIterClosure::do_oop_work(p); } void SpaceMemRegionOopsIterClosure::do_oop(narrowOop* p) { SpaceMemRegionOopsIterClosure::do_oop_work(p); } @@ -658,7 +659,7 @@ void ContiguousSpace::object_iterate_mem(MemRegion mr, UpwardsObjectClosure* cl) } } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #define ContigSpace_PAR_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ \ void ContiguousSpace::par_oop_iterate(MemRegion mr, OopClosureType* blk) {\ @@ -673,7 +674,7 @@ void ContiguousSpace::object_iterate_mem(MemRegion mr, UpwardsObjectClosure* cl) ALL_PAR_OOP_ITERATE_CLOSURES(ContigSpace_PAR_OOP_ITERATE_DEFN) #undef ContigSpace_PAR_OOP_ITERATE_DEFN -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS void ContiguousSpace::oop_iterate(ExtendedOopClosure* blk) { if (is_empty()) return; diff --git a/hotspot/src/share/vm/memory/space.hpp b/hotspot/src/share/vm/memory/space.hpp index 1dade4a26ed..a434b0a337a 100644 --- a/hotspot/src/share/vm/memory/space.hpp +++ b/hotspot/src/share/vm/memory/space.hpp @@ -34,6 +34,7 @@ #include "oops/markOop.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/prefetch.hpp" +#include "utilities/macros.hpp" #include "utilities/workgroup.hpp" #ifdef TARGET_OS_FAMILY_linux # include "os_linux.inline.hpp" @@ -884,14 +885,14 @@ class ContiguousSpace: public CompactibleSpace { } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // In support of parallel oop_iterate. #define ContigSpace_PAR_OOP_ITERATE_DECL(OopClosureType, nv_suffix) \ void par_oop_iterate(MemRegion mr, OopClosureType* blk); ALL_PAR_OOP_ITERATE_CLOSURES(ContigSpace_PAR_OOP_ITERATE_DECL) #undef ContigSpace_PAR_OOP_ITERATE_DECL -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // Compaction support virtual void reset_after_compaction() { diff --git a/hotspot/src/share/vm/memory/specialized_oop_closures.hpp b/hotspot/src/share/vm/memory/specialized_oop_closures.hpp index a13660d406a..2aed587f054 100644 --- a/hotspot/src/share/vm/memory/specialized_oop_closures.hpp +++ b/hotspot/src/share/vm/memory/specialized_oop_closures.hpp @@ -26,9 +26,10 @@ #define SHARE_VM_MEMORY_SPECIALIZED_OOP_CLOSURES_HPP #include "runtime/atomic.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1_specialized_oop_closures.hpp" -#endif +#endif // INCLUDE_ALL_GCS // The following OopClosure types get specialized versions of // "oop_oop_iterate" that invoke the closures' do_oop methods @@ -80,20 +81,20 @@ class NoHeaderExtendedOopClosure; f(FastScanClosure,_nv) \ f(FilteringClosure,_nv) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_P(f) \ f(ParScanWithBarrierClosure,_nv) \ f(ParScanWithoutBarrierClosure,_nv) -#else // SERIALGC +#else // INCLUDE_ALL_GCS #define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_P(f) -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS #define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_1(f) \ f(NoHeaderExtendedOopClosure,_nv) \ SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_S(f) \ SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_P(f) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_2(f) \ f(MarkRefsIntoAndScanClosure,_nv) \ f(Par_MarkRefsIntoAndScanClosure,_nv) \ @@ -104,9 +105,9 @@ class NoHeaderExtendedOopClosure; f(CMSKeepAliveClosure,_nv) \ f(CMSInnerParMarkAndPushClosure,_nv) \ FURTHER_SPECIALIZED_OOP_OOP_ITERATE_CLOSURES(f) -#else // SERIALGC +#else // INCLUDE_ALL_GCS #define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_2(f) -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // We separate these out, because sometime the general one has @@ -120,7 +121,7 @@ class NoHeaderExtendedOopClosure; #define ALL_OOP_OOP_ITERATE_CLOSURES_2(f) \ SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_2(f) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // This macro applies an argument macro to all OopClosures for which we // want specialized bodies of a family of methods related to // "par_oop_iterate". The arguments to f are the same as above. @@ -136,7 +137,7 @@ class NoHeaderExtendedOopClosure; #define ALL_PAR_OOP_ITERATE_CLOSURES(f) \ f(ExtendedOopClosure,_v) \ SPECIALIZED_PAR_OOP_ITERATE_CLOSURES(f) -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // This macro applies an argument macro to all OopClosures for which we // want specialized bodies of a family of methods related to @@ -155,14 +156,14 @@ class NoHeaderExtendedOopClosure; f(ScanClosure,_nv) \ f(FastScanClosure,_nv) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #define SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES_YOUNG_P(f) \ f(ParScanWithBarrierClosure,_nv) \ f(ParScanWithoutBarrierClosure,_nv) \ FURTHER_SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES(f) -#else // SERIALGC +#else // INCLUDE_ALL_GCS #define SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES_YOUNG_P(f) -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS #define SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES_YOUNG(f) \ SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES_YOUNG_S(f) \ diff --git a/hotspot/src/share/vm/memory/tenuredGeneration.cpp b/hotspot/src/share/vm/memory/tenuredGeneration.cpp index f47ea307dd8..1e15d65503a 100644 --- a/hotspot/src/share/vm/memory/tenuredGeneration.cpp +++ b/hotspot/src/share/vm/memory/tenuredGeneration.cpp @@ -33,6 +33,7 @@ #include "memory/tenuredGeneration.hpp" #include "oops/oop.inline.hpp" #include "runtime/java.hpp" +#include "utilities/macros.hpp" TenuredGeneration::TenuredGeneration(ReservedSpace rs, size_t initial_byte_size, int level, @@ -61,7 +62,7 @@ TenuredGeneration::TenuredGeneration(ReservedSpace rs, _space_counters = new CSpaceCounters(gen_name, 0, _virtual_space.reserved_size(), _the_space, _gen_counters); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS if (UseParNewGC) { typedef ParGCAllocBufferWithBOT* ParGCAllocBufferWithBOTPtr; _alloc_buffers = NEW_C_HEAP_ARRAY(ParGCAllocBufferWithBOTPtr, @@ -77,7 +78,7 @@ TenuredGeneration::TenuredGeneration(ReservedSpace rs, } else { _alloc_buffers = NULL; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS } @@ -339,7 +340,7 @@ void TenuredGeneration::update_counters() { } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS oop TenuredGeneration::par_promote(int thread_num, oop old, markOop m, size_t word_sz) { @@ -423,10 +424,10 @@ void TenuredGeneration::verify_alloc_buffers_clean() { } } -#else // SERIALGC +#else // INCLUDE_ALL_GCS void TenuredGeneration::retire_alloc_buffers_before_full_gc() {} void TenuredGeneration::verify_alloc_buffers_clean() {} -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS bool TenuredGeneration::promotion_attempt_is_safe(size_t max_promotion_in_bytes) const { size_t available = max_contiguous_available(); diff --git a/hotspot/src/share/vm/memory/tenuredGeneration.hpp b/hotspot/src/share/vm/memory/tenuredGeneration.hpp index 3a1541e7923..b948a1b0b94 100644 --- a/hotspot/src/share/vm/memory/tenuredGeneration.hpp +++ b/hotspot/src/share/vm/memory/tenuredGeneration.hpp @@ -29,6 +29,7 @@ #include "gc_implementation/shared/gcStats.hpp" #include "gc_implementation/shared/generationCounters.hpp" #include "memory/generation.hpp" +#include "utilities/macros.hpp" // TenuredGeneration models the heap containing old (promoted/tenured) objects. @@ -45,11 +46,11 @@ class TenuredGeneration: public OneContigSpaceCardGeneration { size_t _capacity_at_prologue; size_t _used_at_prologue; -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // To support parallel promotion: an array of parallel allocation // buffers, one per thread, initially NULL. ParGCAllocBufferWithBOT** _alloc_buffers; -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // Retire all alloc buffers before a full GC, so that they will be // re-allocated at the start of the next young GC. @@ -93,14 +94,14 @@ class TenuredGeneration: public OneContigSpaceCardGeneration { size_t size, bool is_tlab); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Overrides. virtual oop par_promote(int thread_num, oop obj, markOop m, size_t word_sz); virtual void par_promote_alloc_undo(int thread_num, HeapWord* obj, size_t word_sz); virtual void par_promote_alloc_done(int thread_num); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // Performance Counter support void update_counters(); diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp index c9199228cb9..a7a6c24bfd2 100644 --- a/hotspot/src/share/vm/memory/universe.cpp +++ b/hotspot/src/share/vm/memory/universe.cpp @@ -70,13 +70,14 @@ #include "utilities/events.hpp" #include "utilities/hashtable.inline.hpp" #include "utilities/preserveException.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/cmsAdaptiveSizePolicy.hpp" #include "gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1CollectorPolicy.hpp" #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" -#endif +#endif // INCLUDE_ALL_GCS // Known objects Klass* Universe::_boolArrayKlassObj = NULL; @@ -144,6 +145,7 @@ NarrowPtrStruct Universe::_narrow_oop = { NULL, 0, true }; NarrowPtrStruct Universe::_narrow_klass = { NULL, 0, true }; address Universe::_narrow_ptrs_base; +size_t Universe::_class_metaspace_size; void Universe::basic_type_classes_do(void f(Klass*)) { f(boolArrayKlassObj()); @@ -689,8 +691,15 @@ char* Universe::preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode) { // Return specified base for the first request. if (!FLAG_IS_DEFAULT(HeapBaseMinAddress) && (mode == UnscaledNarrowOop)) { base = HeapBaseMinAddress; - } else if (total_size <= OopEncodingHeapMax && (mode != HeapBasedNarrowOop)) { - if (total_size <= NarrowOopHeapMax && (mode == UnscaledNarrowOop) && + + // If the total size and the metaspace size are small enough to allow + // UnscaledNarrowOop then just use UnscaledNarrowOop. + } else if ((total_size <= OopEncodingHeapMax) && (mode != HeapBasedNarrowOop) && + (!UseCompressedKlassPointers || + (((OopEncodingHeapMax - heap_size) + Universe::class_metaspace_size()) <= KlassEncodingMetaspaceMax))) { + // We don't need to check the metaspace size here because it is always smaller + // than total_size. + if ((total_size <= NarrowOopHeapMax) && (mode == UnscaledNarrowOop) && (Universe::narrow_oop_shift() == 0)) { // Use 32-bits oops without encoding and // place heap's top on the 4Gb boundary @@ -706,14 +715,24 @@ char* Universe::preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode) { base = (OopEncodingHeapMax - heap_size); } } + + // See if ZeroBaseNarrowOop encoding will work for a heap based at + // (KlassEncodingMetaspaceMax - class_metaspace_size()). + } else if (UseCompressedKlassPointers && (mode != HeapBasedNarrowOop) && + (Universe::class_metaspace_size() + HeapBaseMinAddress <= KlassEncodingMetaspaceMax) && + (KlassEncodingMetaspaceMax + heap_size - Universe::class_metaspace_size() <= OopEncodingHeapMax)) { + base = (KlassEncodingMetaspaceMax - Universe::class_metaspace_size()); } else { - // Can't reserve below 32Gb. + // UnscaledNarrowOop encoding didn't work, and no base was found for ZeroBasedOops or + // HeapBasedNarrowOop encoding was requested. So, can't reserve below 32Gb. Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); } + // Set narrow_oop_base and narrow_oop_use_implicit_null_checks // used in ReservedHeapSpace() constructors. // The final values will be set in initialize_heap() below. - if (base != 0 && (base + heap_size) <= OopEncodingHeapMax) { + if ((base != 0) && ((base + heap_size) <= OopEncodingHeapMax) && + (!UseCompressedKlassPointers || (base + Universe::class_metaspace_size()) <= KlassEncodingMetaspaceMax)) { // Use zero based compressed oops Universe::set_narrow_oop_base(NULL); // Don't need guard page for implicit checks in indexed @@ -740,20 +759,20 @@ char* Universe::preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode) { jint Universe::initialize_heap() { if (UseParallelGC) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS Universe::_collectedHeap = new ParallelScavengeHeap(); -#else // SERIALGC +#else // INCLUDE_ALL_GCS fatal("UseParallelGC not supported in this VM."); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS } else if (UseG1GC) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS G1CollectorPolicy* g1p = new G1CollectorPolicy(); G1CollectedHeap* g1h = new G1CollectedHeap(g1p); Universe::_collectedHeap = g1h; -#else // SERIALGC +#else // INCLUDE_ALL_GCS fatal("UseG1GC not supported in java kernel vm."); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS } else { GenCollectorPolicy *gc_policy; @@ -761,15 +780,15 @@ jint Universe::initialize_heap() { if (UseSerialGC) { gc_policy = new MarkSweepPolicy(); } else if (UseConcMarkSweepGC) { -#ifndef SERIALGC +#if INCLUDE_ALL_GCS if (UseAdaptiveSizePolicy) { gc_policy = new ASConcurrentMarkSweepPolicy(); } else { gc_policy = new ConcurrentMarkSweepPolicy(); } -#else // SERIALGC +#else // INCLUDE_ALL_GCS fatal("UseConcMarkSweepGC not supported in this VM."); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS } else { // default old generation gc_policy = new MarkSweepPolicy(); } @@ -796,7 +815,9 @@ jint Universe::initialize_heap() { tty->print("heap address: " PTR_FORMAT ", size: " SIZE_FORMAT " MB", Universe::heap()->base(), Universe::heap()->reserved_region().byte_size()/M); } - if ((uint64_t)Universe::heap()->reserved_region().end() > OopEncodingHeapMax) { + if (((uint64_t)Universe::heap()->reserved_region().end() > OopEncodingHeapMax) || + (UseCompressedKlassPointers && + ((uint64_t)Universe::heap()->base() + Universe::class_metaspace_size() > KlassEncodingMetaspaceMax))) { // Can't reserve heap below 32Gb. // keep the Universe::narrow_oop_base() set in Universe::reserve_heap() Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); @@ -862,8 +883,8 @@ ReservedSpace Universe::reserve_heap(size_t heap_size, size_t alignment) { // be compressed the same as instances. // Need to round class space size up because it's below the heap and // the actual alignment depends on its size. - size_t metaspace_size = align_size_up(ClassMetaspaceSize, alignment); - size_t total_reserved = align_size_up(heap_size + metaspace_size, alignment); + Universe::set_class_metaspace_size(align_size_up(ClassMetaspaceSize, alignment)); + size_t total_reserved = align_size_up(heap_size + Universe::class_metaspace_size(), alignment); char* addr = Universe::preferred_heap_base(total_reserved, Universe::UnscaledNarrowOop); ReservedHeapSpace total_rs(total_reserved, alignment, UseLargePages, addr); @@ -904,8 +925,8 @@ ReservedSpace Universe::reserve_heap(size_t heap_size, size_t alignment) { // compressed oops is greater than the one used for compressed klass // ptrs, a metadata space on top of the heap could become // unreachable. - ReservedSpace class_rs = total_rs.first_part(metaspace_size); - ReservedSpace heap_rs = total_rs.last_part(metaspace_size, alignment); + ReservedSpace class_rs = total_rs.first_part(Universe::class_metaspace_size()); + ReservedSpace heap_rs = total_rs.last_part(Universe::class_metaspace_size(), alignment); Metaspace::initialize_class_space(class_rs); if (UseCompressedOops) { diff --git a/hotspot/src/share/vm/memory/universe.hpp b/hotspot/src/share/vm/memory/universe.hpp index ca7b09c7b19..2bf0b653f58 100644 --- a/hotspot/src/share/vm/memory/universe.hpp +++ b/hotspot/src/share/vm/memory/universe.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 @@ -211,6 +211,9 @@ class Universe: AllStatic { static struct NarrowPtrStruct _narrow_klass; static address _narrow_ptrs_base; + // Aligned size of the metaspace. + static size_t _class_metaspace_size; + // array of dummy objects used with +FullGCAlot debug_only(static objArrayOop _fullgc_alot_dummy_array;) // index of next entry to clear @@ -278,6 +281,13 @@ class Universe: AllStatic { static bool reserve_metaspace_helper(bool with_base = false); static ReservedHeapSpace reserve_heap_metaspace(size_t heap_size, size_t alignment, bool& contiguous); + static size_t class_metaspace_size() { + return _class_metaspace_size; + } + static void set_class_metaspace_size(size_t metaspace_size) { + _class_metaspace_size = metaspace_size; + } + // Debugging static int _verify_count; // number of verifies done // True during call to verify(). Should only be set/cleared in verify(). diff --git a/hotspot/src/share/vm/oops/annotations.cpp b/hotspot/src/share/vm/oops/annotations.cpp index 72c5737f056..9e5d6ef3701 100644 --- a/hotspot/src/share/vm/oops/annotations.cpp +++ b/hotspot/src/share/vm/oops/annotations.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 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "classfile/classLoaderData.hpp" +#include "memory/heapInspection.hpp" #include "memory/metadataFactory.hpp" #include "memory/oopFactory.hpp" #include "oops/annotations.hpp" @@ -114,6 +115,50 @@ void Annotations::print_value_on(outputStream* st) const { st->print("Anotations(" INTPTR_FORMAT ")", this); } +#if INCLUDE_SERVICES +// Size Statistics + +julong Annotations::count_bytes(Array* p) { + julong bytes = 0; + if (p != NULL) { + for (int i = 0; i < p->length(); i++) { + bytes += KlassSizeStats::count_array(p->at(i)); + } + bytes += KlassSizeStats::count_array(p); + } + return bytes; +} + +void Annotations::collect_statistics(KlassSizeStats *sz) const { + sz->_annotations_bytes = sz->count(this); + sz->_class_annotations_bytes = sz->count(class_annotations()); + sz->_fields_annotations_bytes = count_bytes(fields_annotations()); + sz->_methods_annotations_bytes = count_bytes(methods_annotations()); + sz->_methods_parameter_annotations_bytes = + count_bytes(methods_parameter_annotations()); + sz->_methods_default_annotations_bytes = + count_bytes(methods_default_annotations()); + + const Annotations* type_anno = type_annotations(); + if (type_anno != NULL) { + sz->_type_annotations_bytes = sz->count(type_anno); + sz->_type_annotations_bytes += sz->count(type_anno->class_annotations()); + sz->_type_annotations_bytes += count_bytes(type_anno->fields_annotations()); + sz->_type_annotations_bytes += count_bytes(type_anno->methods_annotations()); + } + + sz->_annotations_bytes += + sz->_class_annotations_bytes + + sz->_fields_annotations_bytes + + sz->_methods_annotations_bytes + + sz->_methods_parameter_annotations_bytes + + sz->_methods_default_annotations_bytes + + sz->_type_annotations_bytes; + + sz->_ro_bytes += sz->_annotations_bytes; +} +#endif // INCLUDE_SERVICES + #define BULLET " - " #ifndef PRODUCT diff --git a/hotspot/src/share/vm/oops/annotations.hpp b/hotspot/src/share/vm/oops/annotations.hpp index 07d05467ba1..82d701ac584 100644 --- a/hotspot/src/share/vm/oops/annotations.hpp +++ b/hotspot/src/share/vm/oops/annotations.hpp @@ -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 @@ -34,6 +34,7 @@ class ClassLoaderData; class outputStream; +class KlassSizeStats; typedef Array AnnotationArray; @@ -82,7 +83,12 @@ class Annotations: public MetaspaceObj { Array* mda, TRAPS); void deallocate_contents(ClassLoaderData* loader_data); DEBUG_ONLY(bool on_stack() { return false; }) // for template + + // Sizing (in words) static int size() { return sizeof(Annotations) / wordSize; } +#if INCLUDE_SERVICES + void collect_statistics(KlassSizeStats *sz) const; +#endif // Constructor to initialize to null Annotations() : _class_annotations(NULL), @@ -142,7 +148,7 @@ class Annotations: public MetaspaceObj { void set_methods_annotations_of(instanceKlassHandle ik, int idnum, AnnotationArray* anno, Array** md_p, TRAPS); - + static julong count_bytes(Array* p); public: const char* internal_name() const { return "{constant pool}"; } #ifndef PRODUCT diff --git a/hotspot/src/share/vm/oops/arrayKlass.hpp b/hotspot/src/share/vm/oops/arrayKlass.hpp index 38a5340e366..f37a4d500ae 100644 --- a/hotspot/src/share/vm/oops/arrayKlass.hpp +++ b/hotspot/src/share/vm/oops/arrayKlass.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 @@ -106,6 +106,14 @@ class ArrayKlass: public Klass { static int header_size() { return sizeof(ArrayKlass)/HeapWordSize; } static int static_size(int header_size); +#if INCLUDE_SERVICES + virtual void collect_statistics(KlassSizeStats *sz) const { + Klass::collect_statistics(sz); + // Do nothing for now, but remember to modify if you add new + // stuff to ArrayKlass. + } +#endif + // Java vtable klassVtable* vtable() const; // return new klassVtable int vtable_length() const { return _vtable_len; } diff --git a/hotspot/src/share/vm/oops/constMethod.cpp b/hotspot/src/share/vm/oops/constMethod.cpp index 79c10c0e62a..3358d225e2a 100644 --- a/hotspot/src/share/vm/oops/constMethod.cpp +++ b/hotspot/src/share/vm/oops/constMethod.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 @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "interpreter/interpreter.hpp" #include "memory/gcLocker.hpp" +#include "memory/heapInspection.hpp" #include "memory/metadataFactory.hpp" #include "oops/constMethod.hpp" #include "oops/method.hpp" @@ -330,6 +331,18 @@ void ConstMethod::print_value_on(outputStream* st) const { method()->print_value_on(st); } +#if INCLUDE_SERVICES +// Size Statistics +void ConstMethod::collect_statistics(KlassSizeStats *sz) const { + int n1, n2, n3; + sz->_const_method_bytes += (n1 = sz->count(this)); + sz->_bytecode_bytes += (n2 = code_size()); + sz->_stackmap_bytes += (n3 = sz->count_array(stackmap_data())); + + sz->_method_all_bytes += n1 + n3; // note: n2 is part of n3 + sz->_ro_bytes += n1 + n3; +} +#endif // INCLUDE_SERVICES // Verification diff --git a/hotspot/src/share/vm/oops/constMethod.hpp b/hotspot/src/share/vm/oops/constMethod.hpp index 8b593982140..12a36c24470 100644 --- a/hotspot/src/share/vm/oops/constMethod.hpp +++ b/hotspot/src/share/vm/oops/constMethod.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 @@ -122,14 +122,10 @@ class ExceptionTableElement VALUE_OBJ_CLASS_SPEC { class MethodParametersElement VALUE_OBJ_CLASS_SPEC { public: u2 name_cp_index; - // 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; + u2 flags; }; +class KlassSizeStats; class ConstMethod : public MetaspaceObj { friend class VMStructs; @@ -320,6 +316,9 @@ public: int size() const { return _constMethod_size;} void set_constMethod_size(int size) { _constMethod_size = size; } +#if INCLUDE_SERVICES + void collect_statistics(KlassSizeStats *sz) const; +#endif // code size int code_size() const { return _code_size; } diff --git a/hotspot/src/share/vm/oops/constantPool.cpp b/hotspot/src/share/vm/oops/constantPool.cpp index 770510c7880..1c21420c29a 100644 --- a/hotspot/src/share/vm/oops/constantPool.cpp +++ b/hotspot/src/share/vm/oops/constantPool.cpp @@ -25,16 +25,17 @@ #include "precompiled.hpp" #include "classfile/classLoaderData.hpp" #include "classfile/javaClasses.hpp" +#include "classfile/metadataOnStackMark.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" #include "interpreter/linkResolver.hpp" +#include "memory/heapInspection.hpp" #include "memory/metadataFactory.hpp" #include "memory/oopFactory.hpp" #include "oops/constantPool.hpp" #include "oops/instanceKlass.hpp" #include "oops/objArrayKlass.hpp" -#include "prims/jvmtiRedefineClasses.hpp" #include "runtime/fieldType.hpp" #include "runtime/init.hpp" #include "runtime/javaCalls.hpp" @@ -65,11 +66,10 @@ ConstantPool::ConstantPool(Array* tags) { set_operands(NULL); set_pool_holder(NULL); set_flags(0); + // only set to non-zero if constant pool is merged by RedefineClasses 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); // initialize tag array int length = tags->length(); @@ -100,18 +100,6 @@ void ConstantPool::release_C_heap_structures() { set_lock(NULL); } -void ConstantPool::set_flag_at(FlagBit fb) { - const int MAX_STATE_CHANGES = 2; - for (int i = MAX_STATE_CHANGES + 10; i > 0; i--) { - int oflags = _flags; - int nflags = oflags | (1 << (int)fb); - if (Atomic::cmpxchg(nflags, &_flags, oflags) == oflags) - return; - } - assert(false, "failed to cmpxchg flags"); - _flags |= (1 << (int)fb); // better than nothing -} - objArrayOop ConstantPool::resolved_references() const { return (objArrayOop)JNIHandles::resolve(_resolved_references); } @@ -1111,32 +1099,9 @@ bool ConstantPool::compare_entry_to(int index1, constantPoolHandle cp2, } // end compare_entry_to() -// Copy this constant pool's entries at start_i to end_i (inclusive) -// to the constant pool to_cp's entries starting at to_i. A total of -// (end_i - start_i) + 1 entries are copied. -void ConstantPool::copy_cp_to_impl(constantPoolHandle from_cp, int start_i, int end_i, - constantPoolHandle to_cp, int to_i, TRAPS) { - - int dest_i = to_i; // leave original alone for debug purposes - - for (int src_i = start_i; src_i <= end_i; /* see loop bottom */ ) { - copy_entry_to(from_cp, src_i, to_cp, dest_i, CHECK); - - switch (from_cp->tag_at(src_i).value()) { - case JVM_CONSTANT_Double: - case JVM_CONSTANT_Long: - // double and long take two constant pool entries - src_i += 2; - dest_i += 2; - break; - - default: - // all others take one constant pool entry - src_i++; - dest_i++; - break; - } - } +void ConstantPool::copy_operands(constantPoolHandle from_cp, + constantPoolHandle to_cp, + TRAPS) { int from_oplen = operand_array_length(from_cp->operands()); int old_oplen = operand_array_length(to_cp->operands()); @@ -1164,7 +1129,7 @@ void ConstantPool::copy_cp_to_impl(constantPoolHandle from_cp, int start_i, int (len = old_off) * sizeof(u2)); fillp += len; // first part of src - Copy::conjoint_memory_atomic(to_cp->operands()->adr_at(0), + Copy::conjoint_memory_atomic(from_cp->operands()->adr_at(0), new_operands->adr_at(fillp), (len = from_off) * sizeof(u2)); fillp += len; @@ -1174,7 +1139,7 @@ void ConstantPool::copy_cp_to_impl(constantPoolHandle from_cp, int start_i, int (len = old_len - old_off) * sizeof(u2)); fillp += len; // second part of src - Copy::conjoint_memory_atomic(to_cp->operands()->adr_at(from_off), + Copy::conjoint_memory_atomic(from_cp->operands()->adr_at(from_off), new_operands->adr_at(fillp), (len = from_len - from_off) * sizeof(u2)); fillp += len; @@ -1192,8 +1157,39 @@ void ConstantPool::copy_cp_to_impl(constantPoolHandle from_cp, int start_i, int to_cp->set_operands(new_operands); } } +} // end copy_operands() -} // end copy_cp_to() + +// Copy this constant pool's entries at start_i to end_i (inclusive) +// to the constant pool to_cp's entries starting at to_i. A total of +// (end_i - start_i) + 1 entries are copied. +void ConstantPool::copy_cp_to_impl(constantPoolHandle from_cp, int start_i, int end_i, + constantPoolHandle to_cp, int to_i, TRAPS) { + + + int dest_i = to_i; // leave original alone for debug purposes + + for (int src_i = start_i; src_i <= end_i; /* see loop bottom */ ) { + copy_entry_to(from_cp, src_i, to_cp, dest_i, CHECK); + + switch (from_cp->tag_at(src_i).value()) { + case JVM_CONSTANT_Double: + case JVM_CONSTANT_Long: + // double and long take two constant pool entries + src_i += 2; + dest_i += 2; + break; + + default: + // all others take one constant pool entry + src_i++; + dest_i++; + break; + } + } + copy_operands(from_cp, to_cp, CHECK); + +} // end copy_cp_to_impl() // Copy this constant pool's entry at from_i to the constant pool @@ -1755,7 +1751,11 @@ int ConstantPool::copy_cpool_bytes(int cpool_size, void ConstantPool::set_on_stack(const bool value) { - _on_stack = value; + if (value) { + _flags |= _on_stack; + } else { + _flags &= ~_on_stack; + } if (value) MetadataOnStackMark::record(this); } @@ -1827,6 +1827,7 @@ void ConstantPool::print_on(outputStream* st) const { if (has_pseudo_string()) st->print(" has_pseudo_string"); if (has_invokedynamic()) st->print(" has_invokedynamic"); if (has_preresolution()) st->print(" has_preresolution"); + if (on_stack()) st->print(" on_stack"); st->cr(); } if (pool_holder() != NULL) { @@ -1954,6 +1955,20 @@ void ConstantPool::print_value_on(outputStream* st) const { } } +#if INCLUDE_SERVICES +// Size Statistics +void ConstantPool::collect_statistics(KlassSizeStats *sz) const { + sz->_cp_all_bytes += (sz->_cp_bytes = sz->count(this)); + sz->_cp_all_bytes += (sz->_cp_tags_bytes = sz->count_array(tags())); + sz->_cp_all_bytes += (sz->_cp_cache_bytes = sz->count(cache())); + sz->_cp_all_bytes += (sz->_cp_operands_bytes = sz->count_array(operands())); + sz->_cp_all_bytes += (sz->_cp_refmap_bytes = sz->count_array(reference_map())); + + sz->_ro_bytes += sz->_cp_operands_bytes + sz->_cp_tags_bytes + + sz->_cp_refmap_bytes; + sz->_rw_bytes += sz->_cp_bytes + sz->_cp_cache_bytes; +} +#endif // INCLUDE_SERVICES // Verification diff --git a/hotspot/src/share/vm/oops/constantPool.hpp b/hotspot/src/share/vm/oops/constantPool.hpp index 65546021553..92ae90f20a6 100644 --- a/hotspot/src/share/vm/oops/constantPool.hpp +++ b/hotspot/src/share/vm/oops/constantPool.hpp @@ -80,6 +80,7 @@ class CPSlot VALUE_OBJ_CLASS_SPEC { } }; +class KlassSizeStats; class ConstantPool : public Metadata { friend class VMStructs; friend class BytecodeInterpreter; // Directly extracts an oop in the pool for fast instanceof/checkcast @@ -95,10 +96,15 @@ class ConstantPool : public Metadata { jobject _resolved_references; Array* _reference_map; - int _flags; // a few header bits to describe contents for GC - int _length; // number of elements in the array + enum { + _has_invokedynamic = 1, // Flags + _has_pseudo_string = 2, + _has_preresolution = 4, + _on_stack = 8 + }; - bool _on_stack; // Redefined method still executing refers to this constant pool. + int _flags; // old fashioned bit twiddling + int _length; // number of elements in the array union { // set for CDS to restore resolved references @@ -115,17 +121,8 @@ class ConstantPool : public Metadata { void set_operands(Array* operands) { _operands = operands; } - enum FlagBit { - FB_has_invokedynamic = 1, - FB_has_pseudo_string = 2, - FB_has_preresolution = 3 - }; - - int flags() const { return _flags; } - void set_flags(int f) { _flags = f; } - bool flag_at(FlagBit fb) const { return (_flags & (1 << (int)fb)) != 0; } - void set_flag_at(FlagBit fb); - // no clear_flag_at function; they only increase + int flags() const { return _flags; } + void set_flags(int f) { _flags = f; } private: intptr_t* base() const { return (intptr_t*) (((char*) this) + sizeof(ConstantPool)); } @@ -178,18 +175,20 @@ class ConstantPool : public Metadata { Array* tags() const { return _tags; } Array* operands() const { return _operands; } - bool has_pseudo_string() const { return flag_at(FB_has_pseudo_string); } - bool has_invokedynamic() const { return flag_at(FB_has_invokedynamic); } - bool has_preresolution() const { return flag_at(FB_has_preresolution); } - void set_pseudo_string() { set_flag_at(FB_has_pseudo_string); } - void set_invokedynamic() { set_flag_at(FB_has_invokedynamic); } - void set_preresolution() { set_flag_at(FB_has_preresolution); } + bool has_invokedynamic() const { return (_flags & _has_invokedynamic) != 0; } + void set_has_invokedynamic() { _flags |= _has_invokedynamic; } + + bool has_pseudo_string() const { return (_flags & _has_pseudo_string) != 0; } + void set_has_pseudo_string() { _flags |= _has_pseudo_string; } + + bool has_preresolution() const { return (_flags & _has_preresolution) != 0; } + void set_has_preresolution() { _flags |= _has_preresolution; } // Redefine classes support. If a method refering to this constant pool // is on the executing stack, or as a handle in vm code, this constant pool // can't be removed from the set of previous versions saved in the instance // class. - bool on_stack() const { return _on_stack; } + bool on_stack() const { return (_flags &_on_stack) != 0; } void set_on_stack(const bool value); // Klass holding pool @@ -457,7 +456,7 @@ class ConstantPool : public Metadata { void pseudo_string_at_put(int which, int obj_index, oop x) { assert(EnableInvokeDynamic, ""); - set_pseudo_string(); // mark header + set_has_pseudo_string(); // mark header assert(tag_at(which).is_string(), "Corrupted constant pool"); string_at_put(which, obj_index, x); // this works just fine } @@ -686,9 +685,13 @@ class ConstantPool : public Metadata { return 0 <= index && index < length(); } + // Sizing (in words) static int header_size() { return sizeof(ConstantPool)/HeapWordSize; } static int size(int length) { return align_object_size(header_size() + length); } int size() const { return size(length()); } +#if INCLUDE_SERVICES + void collect_statistics(KlassSizeStats *sz) const; +#endif friend class ClassFileParser; friend class SystemDictionary; @@ -783,6 +786,7 @@ 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); + static void copy_operands(constantPoolHandle from_cp, constantPoolHandle to_cp, TRAPS); int find_matching_entry(int pattern_i, constantPoolHandle search_cp, TRAPS); int version() const { return _saved._version; } void set_version(int version) { _saved._version = version; } diff --git a/hotspot/src/share/vm/oops/cpCache.cpp b/hotspot/src/share/vm/oops/cpCache.cpp index 06c70cd02e3..7d6d36b6881 100644 --- a/hotspot/src/share/vm/oops/cpCache.cpp +++ b/hotspot/src/share/vm/oops/cpCache.cpp @@ -33,9 +33,10 @@ #include "prims/jvmtiRedefineClassesTrace.hpp" #include "prims/methodHandles.hpp" #include "runtime/handles.inline.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS # include "gc_implementation/parallelScavenge/psPromotionManager.hpp" -#endif +#endif // INCLUDE_ALL_GCS // Implememtation of ConstantPoolCacheEntry diff --git a/hotspot/src/share/vm/oops/instanceClassLoaderKlass.cpp b/hotspot/src/share/vm/oops/instanceClassLoaderKlass.cpp index def7d10e595..507206fc854 100644 --- a/hotspot/src/share/vm/oops/instanceClassLoaderKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceClassLoaderKlass.cpp @@ -36,12 +36,13 @@ #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" #include "runtime/handles.inline.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/parNew/parOopClosures.inline.hpp" #include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" #include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" #include "oops/oop.pcgc.inline.hpp" -#endif +#endif // INCLUDE_ALL_GCS #define if_do_metadata_checked(closure, nv_suffix) \ /* Make sure the non-virtual and the virtual versions match. */ \ @@ -73,7 +74,7 @@ oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) { return size; \ } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #define InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ \ int InstanceClassLoaderKlass:: \ @@ -83,7 +84,7 @@ oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) { int size = InstanceKlass::oop_oop_iterate_backwards##nv_suffix(obj, closure); \ return size; \ } -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS #define InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ @@ -111,10 +112,10 @@ oop_oop_iterate##nv_suffix##_m(oop obj, ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN_m) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN_m) @@ -129,7 +130,7 @@ void InstanceClassLoaderKlass::oop_follow_contents(oop obj) { } } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void InstanceClassLoaderKlass::oop_follow_contents(ParCompactionManager* cm, oop obj) { InstanceKlass::oop_follow_contents(cm, obj); @@ -155,5 +156,5 @@ int InstanceClassLoaderKlass::oop_update_pointers(ParCompactionManager* cm, oop } return size_helper(); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS diff --git a/hotspot/src/share/vm/oops/instanceClassLoaderKlass.hpp b/hotspot/src/share/vm/oops/instanceClassLoaderKlass.hpp index c9f7f026a0e..d93f2a5c32a 100644 --- a/hotspot/src/share/vm/oops/instanceClassLoaderKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceClassLoaderKlass.hpp @@ -26,6 +26,7 @@ #define SHARE_VM_OOPS_INSTANCECLASSLOADERKLASS_HPP #include "oops/instanceKlass.hpp" +#include "utilities/macros.hpp" // An InstanceClassLoaderKlass is a specialization of the InstanceKlass. It does // not add any field. It is added to walk the dependencies for the class loader @@ -61,13 +62,13 @@ public: ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceClassLoaderKlass_OOP_OOP_ITERATE_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceClassLoaderKlass_OOP_OOP_ITERATE_DECL) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #define InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* blk); ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS // Garbage collection void oop_follow_contents(oop obj); diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp index b0b7038e35b..4af6e32063d 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlass.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 @@ -34,6 +34,7 @@ #include "interpreter/rewriter.hpp" #include "jvmtifiles/jvmti.h" #include "memory/genOopClosures.inline.hpp" +#include "memory/heapInspection.hpp" #include "memory/metadataFactory.hpp" #include "memory/oopFactory.hpp" #include "oops/fieldStreams.hpp" @@ -55,7 +56,8 @@ #include "runtime/thread.inline.hpp" #include "services/threadService.hpp" #include "utilities/dtrace.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/cmsOopClosures.inline.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1OopClosures.inline.hpp" @@ -66,7 +68,7 @@ #include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" #include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" #include "oops/oop.pcgc.inline.hpp" -#endif +#endif // INCLUDE_ALL_GCS #ifdef COMPILER1 #include "c1/c1_Compiler.hpp" #endif @@ -2042,7 +2044,7 @@ void InstanceKlass::oop_follow_contents(oop obj) { assert_is_in_closed_subset) } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void InstanceKlass::oop_follow_contents(ParCompactionManager* cm, oop obj) { assert(obj != NULL, "can't follow the content of NULL object"); @@ -2054,7 +2056,7 @@ void InstanceKlass::oop_follow_contents(ParCompactionManager* cm, PSParallelCompact::mark_and_push(cm, p), \ assert_is_in) } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // closure's do_metadata() method dictates whether the given closure should be // applied to the klass ptr in the object header. @@ -2082,7 +2084,7 @@ int InstanceKlass::oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) return size_helper(); \ } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #define InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ \ int InstanceKlass::oop_oop_iterate_backwards##nv_suffix(oop obj, \ @@ -2100,7 +2102,7 @@ int InstanceKlass::oop_oop_iterate_backwards##nv_suffix(oop obj, assert_is_in_closed_subset) \ return size_helper(); \ } -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS #define InstanceKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ \ @@ -2124,10 +2126,10 @@ ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceKlass_OOP_OOP_ITERATE_DEFN) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceKlass_OOP_OOP_ITERATE_DEFN) ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceKlass_OOP_OOP_ITERATE_DEFN_m) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceKlass_OOP_OOP_ITERATE_DEFN_m) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS int InstanceKlass::oop_adjust_pointers(oop obj) { int size = size_helper(); @@ -2139,7 +2141,7 @@ int InstanceKlass::oop_adjust_pointers(oop obj) { return size; } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void InstanceKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { InstanceKlass_OOP_MAP_REVERSE_ITERATE( \ obj, \ @@ -2159,7 +2161,7 @@ int InstanceKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) { return size; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS void InstanceKlass::clean_implementors_list(BoolObjectClosure* is_alive) { assert(is_loader_alive(is_alive), "this klass should be live"); @@ -2960,6 +2962,52 @@ const char* InstanceKlass::internal_name() const { return external_name(); } +#if INCLUDE_SERVICES +// Size Statistics +void InstanceKlass::collect_statistics(KlassSizeStats *sz) const { + Klass::collect_statistics(sz); + + sz->_inst_size = HeapWordSize * size_helper(); + sz->_vtab_bytes = HeapWordSize * align_object_offset(vtable_length()); + sz->_itab_bytes = HeapWordSize * align_object_offset(itable_length()); + sz->_nonstatic_oopmap_bytes = HeapWordSize * + ((is_interface() || is_anonymous()) ? + align_object_offset(nonstatic_oop_map_size()) : + nonstatic_oop_map_size()); + + int n = 0; + n += (sz->_methods_array_bytes = sz->count_array(methods())); + n += (sz->_method_ordering_bytes = sz->count_array(method_ordering())); + n += (sz->_local_interfaces_bytes = sz->count_array(local_interfaces())); + n += (sz->_transitive_interfaces_bytes = sz->count_array(transitive_interfaces())); + n += (sz->_signers_bytes = sz->count_array(signers())); + n += (sz->_fields_bytes = sz->count_array(fields())); + n += (sz->_inner_classes_bytes = sz->count_array(inner_classes())); + sz->_ro_bytes += n; + + const ConstantPool* cp = constants(); + if (cp) { + cp->collect_statistics(sz); + } + + const Annotations* anno = annotations(); + if (anno) { + anno->collect_statistics(sz); + } + + const Array* methods_array = methods(); + if (methods()) { + for (int i = 0; i < methods_array->length(); i++) { + Method* method = methods_array->at(i); + if (method) { + sz->_method_count ++; + method->collect_statistics(sz); + } + } + } +} +#endif // INCLUDE_SERVICES + // Verification class VerifyFieldClosure: public OopClosure { diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp index 97b3dd23313..025da12825d 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceKlass.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 @@ -36,6 +36,7 @@ #include "runtime/os.hpp" #include "utilities/accessFlags.hpp" #include "utilities/bitMap.inline.hpp" +#include "utilities/macros.hpp" // An InstanceKlass is the VM level representation of a Java class. // It contains all information needed for at class at execution runtime. @@ -256,6 +257,16 @@ class InstanceKlass: public Klass { // JVMTI fields can be moved to their own structure - see 6315920 unsigned char * _cached_class_file_bytes; // JVMTI: cached class file, before retransformable agent modified it in CFLH jint _cached_class_file_len; // JVMTI: length of above + + 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. + u1 _init_state; // state of class + u1 _reference_type; // reference type + + JvmtiCachedClassFieldMap* _jvmti_cached_class_field_map; // JVMTI: used during heap iteration // Method array. @@ -281,15 +292,6 @@ 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. - u1 _init_state; // state of class - - u1 _reference_type; // reference type - // embedded Java vtable follows here // embedded Java itables follows here // embedded static fields follows here @@ -826,6 +828,9 @@ class InstanceKlass: public Klass { is_interface(), is_anonymous()); } +#if INCLUDE_SERVICES + virtual void collect_statistics(KlassSizeStats *sz) const; +#endif static int vtable_start_offset() { return header_size(); } static int vtable_length_offset() { return offset_of(InstanceKlass, _vtable_len) / HeapWordSize; } @@ -932,13 +937,13 @@ class InstanceKlass: public Klass { ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceKlass_OOP_OOP_ITERATE_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceKlass_OOP_OOP_ITERATE_DECL) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #define InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* blk); ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS u2 idnum_allocated_count() const { return _idnum_allocated_count; } private: diff --git a/hotspot/src/share/vm/oops/instanceMirrorKlass.cpp b/hotspot/src/share/vm/oops/instanceMirrorKlass.cpp index 4e63075c423..3eabba70a1a 100644 --- a/hotspot/src/share/vm/oops/instanceMirrorKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceMirrorKlass.cpp @@ -35,7 +35,8 @@ #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" #include "runtime/handles.inline.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/cmsOopClosures.inline.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1OopClosures.inline.hpp" @@ -45,7 +46,7 @@ #include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" #include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" #include "oops/oop.pcgc.inline.hpp" -#endif +#endif // INCLUDE_ALL_GCS int InstanceMirrorKlass::_offset_of_static_fields = 0; @@ -168,7 +169,7 @@ void InstanceMirrorKlass::oop_follow_contents(oop obj) { assert_is_in_closed_subset) } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void InstanceMirrorKlass::oop_follow_contents(ParCompactionManager* cm, oop obj) { InstanceKlass::oop_follow_contents(cm, obj); @@ -189,7 +190,7 @@ void InstanceMirrorKlass::oop_follow_contents(ParCompactionManager* cm, PSParallelCompact::mark_and_push(cm, p), \ assert_is_in) } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS int InstanceMirrorKlass::oop_adjust_pointers(oop obj) { int size = oop_size(obj); @@ -262,7 +263,7 @@ oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) { } \ } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #define InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ \ int InstanceMirrorKlass:: \ @@ -278,7 +279,7 @@ oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) { InstanceMirrorKlass_SPECIALIZED_OOP_ITERATE_DEFN(oop, nv_suffix); \ } \ } -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS #define InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ @@ -310,14 +311,14 @@ oop_oop_iterate##nv_suffix##_m(oop obj, ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN_m) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN_m) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void InstanceMirrorKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { // Note that we don't have to follow the mirror -> klass pointer, since all // klasses that are dirty will be scavenged when we iterate over the @@ -353,7 +354,7 @@ int InstanceMirrorKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) assert_nothing) return size; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS int InstanceMirrorKlass::instance_size(KlassHandle k) { if (k() != NULL && k->oop_is_instance()) { diff --git a/hotspot/src/share/vm/oops/instanceMirrorKlass.hpp b/hotspot/src/share/vm/oops/instanceMirrorKlass.hpp index db1d8de2565..38f2dc81787 100644 --- a/hotspot/src/share/vm/oops/instanceMirrorKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceMirrorKlass.hpp @@ -28,6 +28,7 @@ #include "classfile/systemDictionary.hpp" #include "oops/instanceKlass.hpp" #include "runtime/handles.hpp" +#include "utilities/macros.hpp" // An InstanceMirrorKlass is a specialized InstanceKlass for // java.lang.Class instances. These instances are special because @@ -107,13 +108,13 @@ class InstanceMirrorKlass: public InstanceKlass { ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceMirrorKlass_OOP_OOP_ITERATE_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceMirrorKlass_OOP_OOP_ITERATE_DECL) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #define InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* blk); ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS }; #endif // SHARE_VM_OOPS_INSTANCEMIRRORKLASS_HPP diff --git a/hotspot/src/share/vm/oops/instanceRefKlass.cpp b/hotspot/src/share/vm/oops/instanceRefKlass.cpp index 1784609e3f2..cb5f8965521 100644 --- a/hotspot/src/share/vm/oops/instanceRefKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceRefKlass.cpp @@ -33,7 +33,8 @@ #include "oops/instanceRefKlass.hpp" #include "oops/oop.inline.hpp" #include "utilities/preserveException.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1OopClosures.inline.hpp" #include "gc_implementation/g1/g1RemSet.inline.hpp" @@ -42,7 +43,7 @@ #include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" #include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" #include "oops/oop.pcgc.inline.hpp" -#endif +#endif // INCLUDE_ALL_GCS template void specialized_oop_follow_contents(InstanceRefKlass* ref, oop obj) { @@ -120,7 +121,7 @@ void InstanceRefKlass::oop_follow_contents(oop obj) { } } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS template void specialized_oop_follow_contents(InstanceRefKlass* ref, ParCompactionManager* cm, @@ -194,7 +195,7 @@ void InstanceRefKlass::oop_follow_contents(ParCompactionManager* cm, specialized_oop_follow_contents(this, cm, obj); } } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS #ifdef ASSERT template void trace_reference_gc(const char *s, oop obj, @@ -317,7 +318,7 @@ oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) { } \ } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #define InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ \ int InstanceRefKlass:: \ @@ -333,7 +334,7 @@ oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) { InstanceRefKlass_SPECIALIZED_OOP_ITERATE(oop, nv_suffix, contains); \ } \ } -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS #define InstanceRefKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ @@ -354,14 +355,14 @@ oop_oop_iterate##nv_suffix##_m(oop obj, ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceRefKlass_OOP_OOP_ITERATE_DEFN) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceRefKlass_OOP_OOP_ITERATE_DEFN) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceRefKlass_OOP_OOP_ITERATE_DEFN_m) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceRefKlass_OOP_OOP_ITERATE_DEFN_m) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS template void specialized_oop_push_contents(InstanceRefKlass *ref, PSPromotionManager* pm, oop obj) { @@ -444,7 +445,7 @@ int InstanceRefKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) { } return size_helper(); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS void InstanceRefKlass::update_nonstatic_oop_maps(Klass* k) { // Clear the nonstatic oop-map entries corresponding to referent diff --git a/hotspot/src/share/vm/oops/instanceRefKlass.hpp b/hotspot/src/share/vm/oops/instanceRefKlass.hpp index fd565ecd823..d8771608f73 100644 --- a/hotspot/src/share/vm/oops/instanceRefKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceRefKlass.hpp @@ -26,6 +26,7 @@ #define SHARE_VM_OOPS_INSTANCEREFKLASS_HPP #include "oops/instanceKlass.hpp" +#include "utilities/macros.hpp" // An InstanceRefKlass is a specialized InstanceKlass for Java // classes that are subclasses of java/lang/ref/Reference. @@ -83,13 +84,13 @@ class InstanceRefKlass: public InstanceKlass { ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceRefKlass_OOP_OOP_ITERATE_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceRefKlass_OOP_OOP_ITERATE_DECL) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #define InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* blk); ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS static void release_and_notify_pending_list_lock(BasicLock *pending_list_basic_lock); static void acquire_pending_list_lock(BasicLock *pending_list_basic_lock); diff --git a/hotspot/src/share/vm/oops/klass.cpp b/hotspot/src/share/vm/oops/klass.cpp index 21bfb6bda69..341f60c3fe8 100644 --- a/hotspot/src/share/vm/oops/klass.cpp +++ b/hotspot/src/share/vm/oops/klass.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 @@ -29,6 +29,7 @@ #include "classfile/vmSymbols.hpp" #include "gc_implementation/shared/markSweep.inline.hpp" #include "gc_interface/collectedHeap.inline.hpp" +#include "memory/heapInspection.hpp" #include "memory/metadataFactory.hpp" #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" @@ -37,11 +38,12 @@ #include "oops/oop.inline2.hpp" #include "runtime/atomic.hpp" #include "utilities/stack.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/parallelScavenge/psParallelCompact.hpp" #include "gc_implementation/parallelScavenge/psPromotionManager.hpp" #include "gc_implementation/parallelScavenge/psScavenge.hpp" -#endif +#endif // INCLUDE_ALL_GCS void Klass::set_name(Symbol* n) { _name = n; @@ -624,6 +626,17 @@ void Klass::oop_print_value_on(oop obj, outputStream* st) { obj->print_address_on(st); } +#if INCLUDE_SERVICES +// Size Statistics +void Klass::collect_statistics(KlassSizeStats *sz) const { + sz->_klass_bytes = sz->count(this); + sz->_mirror_bytes = sz->count(java_mirror()); + sz->_secondary_supers_bytes = sz->count_array(secondary_supers()); + + sz->_ro_bytes += sz->_secondary_supers_bytes; + sz->_rw_bytes += sz->_klass_bytes + sz->_mirror_bytes; +} +#endif // INCLUDE_SERVICES // Verification diff --git a/hotspot/src/share/vm/oops/klass.hpp b/hotspot/src/share/vm/oops/klass.hpp index be5d0c5293d..803f4da2737 100644 --- a/hotspot/src/share/vm/oops/klass.hpp +++ b/hotspot/src/share/vm/oops/klass.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 @@ -35,11 +35,12 @@ #include "runtime/orderAccess.hpp" #include "trace/traceMacros.hpp" #include "utilities/accessFlags.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/cmsOopClosures.hpp" #include "gc_implementation/g1/g1OopClosures.hpp" #include "gc_implementation/parNew/parOopClosures.hpp" -#endif +#endif // INCLUDE_ALL_GCS // // A Klass provides: @@ -75,11 +76,11 @@ // [class_loader_data] // [modifier_flags] // [access_flags ] -// [verify_count ] - not in product -// [alloc_count ] // [last_biased_lock_bulk_revocation_time] (64 bits) // [prototype_header] // [biased_lock_revocation_count] +// [verify_count ] - not in product +// [alloc_count ] // [_modified_oops] // [_accumulated_modified_oops] // [trace_id] @@ -91,6 +92,7 @@ template class GrowableArray; class ClassLoaderData; class klassVtable; class ParCompactionManager; +class KlassSizeStats; class Klass : public Metadata { friend class VMStructs; @@ -164,18 +166,18 @@ class Klass : public Metadata { jint _modifier_flags; // Processed access flags, for use by Class.getModifiers. AccessFlags _access_flags; // Access flags. The class/interface distinction is stored here. -#ifndef PRODUCT - int _verify_count; // to avoid redundant verifies -#endif - - juint _alloc_count; // allocation profiling support - // Biased locking implementation and statistics // (the 64-bit chunk goes first, to avoid some fragmentation) jlong _last_biased_lock_bulk_revocation_time; markOop _prototype_header; // Used when biased locking is both enabled and disabled for this type jint _biased_lock_revocation_count; +#ifndef PRODUCT + int _verify_count; // to avoid redundant verifies +#endif + + juint _alloc_count; // allocation profiling support + TRACE_DEFINE_KLASS_TRACE_ID; // Remembered sets support for the oops in the klasses. @@ -477,6 +479,9 @@ class Klass : public Metadata { // Size of klass in word size. virtual int size() const = 0; +#if INCLUDE_SERVICES + virtual void collect_statistics(KlassSizeStats *sz) const; +#endif // Returns the Java name for a class (Resource allocated) // For arrays, this returns the name of the element with a leading '['. @@ -625,13 +630,13 @@ class Klass : public Metadata { return oop_oop_iterate(obj, blk); } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // In case we don't have a specialized backward scanner use forward // iteration. virtual int oop_oop_iterate_backwards_v(oop obj, ExtendedOopClosure* blk) { return oop_oop_iterate_v(obj, blk); } -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS // Iterates "blk" over all the oops in "obj" (of type "this") within "mr". // (I don't see why the _m should be required, but without it the Solaris @@ -663,7 +668,7 @@ class Klass : public Metadata { SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_1(Klass_OOP_OOP_ITERATE_DECL) SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_2(Klass_OOP_OOP_ITERATE_DECL) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #define Klass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ virtual int oop_oop_iterate_backwards##nv_suffix(oop obj, \ OopClosureType* blk) { \ @@ -673,7 +678,7 @@ class Klass : public Metadata { SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_1(Klass_OOP_OOP_ITERATE_BACKWARDS_DECL) SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_2(Klass_OOP_OOP_ITERATE_BACKWARDS_DECL) -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS virtual void array_klasses_do(void f(Klass* k)) {} virtual void with_array_klasses_do(void f(Klass* k)); diff --git a/hotspot/src/share/vm/oops/klassPS.hpp b/hotspot/src/share/vm/oops/klassPS.hpp index 0aa7a580d4c..5fb17b6e801 100644 --- a/hotspot/src/share/vm/oops/klassPS.hpp +++ b/hotspot/src/share/vm/oops/klassPS.hpp @@ -27,7 +27,9 @@ // Expands to Parallel Scavenge and Parallel Old declarations -#ifndef SERIALGC +#include "utilities/macros.hpp" + +#if INCLUDE_ALL_GCS #define PARALLEL_GC_DECLS \ virtual void oop_push_contents(PSPromotionManager* pm, oop obj); \ /* Parallel Old GC support \ @@ -44,9 +46,9 @@ virtual void oop_push_contents(PSPromotionManager* pm, oop obj) = 0; \ virtual void oop_follow_contents(ParCompactionManager* cm, oop obj) = 0; \ virtual int oop_update_pointers(ParCompactionManager* cm, oop obj) = 0; -#else // SERIALGC +#else // INCLUDE_ALL_GCS #define PARALLEL_GC_DECLS #define PARALLEL_GC_DECLS_PV -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS #endif // SHARE_VM_OOPS_KLASSPS_HPP diff --git a/hotspot/src/share/vm/oops/method.cpp b/hotspot/src/share/vm/oops/method.cpp index 936090f50c0..110148a72d5 100644 --- a/hotspot/src/share/vm/oops/method.cpp +++ b/hotspot/src/share/vm/oops/method.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 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/metadataOnStackMark.hpp" #include "classfile/systemDictionary.hpp" #include "code/debugInfoRec.hpp" #include "gc_interface/collectedHeap.inline.hpp" @@ -33,6 +34,7 @@ #include "interpreter/oopMapCache.hpp" #include "memory/gcLocker.hpp" #include "memory/generation.hpp" +#include "memory/heapInspection.hpp" #include "memory/metadataFactory.hpp" #include "memory/oopFactory.hpp" #include "oops/constMethod.hpp" @@ -41,7 +43,6 @@ #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" #include "prims/jvmtiExport.hpp" -#include "prims/jvmtiRedefineClasses.hpp" #include "prims/methodHandles.hpp" #include "prims/nativeLookup.hpp" #include "runtime/arguments.hpp" @@ -699,7 +700,7 @@ void Method::set_signature_handler(address handler) { } -void Method::print_made_not_compilable(int comp_level, bool is_osr, bool report) { +void Method::print_made_not_compilable(int comp_level, bool is_osr, bool report, const char* reason) { if (PrintCompilation && report) { ttyLocker ttyl; tty->print("made not %scompilable on ", is_osr ? "OSR " : ""); @@ -713,14 +714,21 @@ void Method::print_made_not_compilable(int comp_level, bool is_osr, bool report) } this->print_short_name(tty); int size = this->code_size(); - if (size > 0) + if (size > 0) { tty->print(" (%d bytes)", size); + } + if (reason != NULL) { + tty->print(" %s", reason); + } tty->cr(); } if ((TraceDeoptimization || LogCompilation) && (xtty != NULL)) { ttyLocker ttyl; xtty->begin_elem("make_not_%scompilable thread='" UINTX_FORMAT "'", is_osr ? "osr_" : "", os::current_thread_id()); + if (reason != NULL) { + xtty->print(" reason=\'%s\'", reason); + } xtty->method(this); xtty->stamp(); xtty->end_elem(); @@ -742,8 +750,8 @@ bool Method::is_not_compilable(int comp_level) const { } // call this when compiler finds that this method is not compilable -void Method::set_not_compilable(int comp_level, bool report) { - print_made_not_compilable(comp_level, /*is_osr*/ false, report); +void Method::set_not_compilable(int comp_level, bool report, const char* reason) { + print_made_not_compilable(comp_level, /*is_osr*/ false, report, reason); if (comp_level == CompLevel_all) { set_not_c1_compilable(); set_not_c2_compilable(); @@ -768,8 +776,8 @@ bool Method::is_not_osr_compilable(int comp_level) const { return false; } -void Method::set_not_osr_compilable(int comp_level, bool report) { - print_made_not_compilable(comp_level, /*is_osr*/ true, report); +void Method::set_not_osr_compilable(int comp_level, bool report, const char* reason) { + print_made_not_compilable(comp_level, /*is_osr*/ true, report, reason); if (comp_level == CompLevel_all) { set_not_c1_osr_compilable(); set_not_c2_osr_compilable(); @@ -1027,7 +1035,7 @@ methodHandle Method::make_method_handle_intrinsic(vmIntrinsics::ID iid, cp->set_pool_holder(InstanceKlass::cast(holder())); cp->symbol_at_put(_imcp_invoke_name, name); cp->symbol_at_put(_imcp_invoke_signature, signature); - cp->set_preresolution(); + cp->set_has_preresolution(); // decide on access bits: public or not? int flags_bits = (JVM_ACC_NATIVE | JVM_ACC_SYNTHETIC | JVM_ACC_FINAL); @@ -1954,6 +1962,22 @@ void Method::print_value_on(outputStream* st) const { if (WizardMode && code() != NULL) st->print(" ((nmethod*)%p)", code()); } +#if INCLUDE_SERVICES +// Size Statistics +void Method::collect_statistics(KlassSizeStats *sz) const { + int mysize = sz->count(this); + sz->_method_bytes += mysize; + sz->_method_all_bytes += mysize; + sz->_rw_bytes += mysize; + + if (constMethod()) { + constMethod()->collect_statistics(sz); + } + if (method_data()) { + method_data()->collect_statistics(sz); + } +} +#endif // INCLUDE_SERVICES // Verification diff --git a/hotspot/src/share/vm/oops/method.hpp b/hotspot/src/share/vm/oops/method.hpp index 72a4faf11d7..339380f6735 100644 --- a/hotspot/src/share/vm/oops/method.hpp +++ b/hotspot/src/share/vm/oops/method.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 @@ -101,6 +101,7 @@ class LocalVariableTableElement; class AdapterHandlerEntry; class MethodData; class ConstMethod; +class KlassSizeStats; class Method : public Metadata { friend class VMStructs; @@ -127,8 +128,8 @@ class Method : public Metadata { InvocationCounter _backedge_counter; // Incremented before each backedge taken - used to trigger frequencey-based optimizations #ifdef TIERED - jlong _prev_time; // Previous time the rate was acquired float _rate; // Events (invocation and backedge counter increments) per millisecond + jlong _prev_time; // Previous time the rate was acquired #endif #ifndef PRODUCT @@ -593,6 +594,9 @@ class Method : public Metadata { static int header_size() { return sizeof(Method)/HeapWordSize; } static int size(bool is_native); int size() const { return method_size(); } +#if INCLUDE_SERVICES + void collect_statistics(KlassSizeStats *sz) const; +#endif // interpreter support static ByteSize const_offset() { return byte_offset_of(Method, _constMethod ); } @@ -760,18 +764,18 @@ class Method : public Metadata { // whether it is not compilable for another reason like having a // breakpoint set in it. bool is_not_compilable(int comp_level = CompLevel_any) const; - void set_not_compilable(int comp_level = CompLevel_all, bool report = true); + void set_not_compilable(int comp_level = CompLevel_all, bool report = true, const char* reason = NULL); void set_not_compilable_quietly(int comp_level = CompLevel_all) { set_not_compilable(comp_level, false); } bool is_not_osr_compilable(int comp_level = CompLevel_any) const; - void set_not_osr_compilable(int comp_level = CompLevel_all, bool report = true); + void set_not_osr_compilable(int comp_level = CompLevel_all, bool report = true, const char* reason = NULL); void set_not_osr_compilable_quietly(int comp_level = CompLevel_all) { set_not_osr_compilable(comp_level, false); } private: - void print_made_not_compilable(int comp_level, bool is_osr, bool report); + void print_made_not_compilable(int comp_level, bool is_osr, bool report, const char* reason); public: bool is_not_c1_compilable() const { return access_flags().is_not_c1_compilable(); } diff --git a/hotspot/src/share/vm/oops/methodData.cpp b/hotspot/src/share/vm/oops/methodData.cpp index 71d9649c268..c7a200f9e47 100644 --- a/hotspot/src/share/vm/oops/methodData.cpp +++ b/hotspot/src/share/vm/oops/methodData.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 @@ -27,6 +27,7 @@ #include "interpreter/bytecode.hpp" #include "interpreter/bytecodeStream.hpp" #include "interpreter/linkResolver.hpp" +#include "memory/heapInspection.hpp" #include "oops/methodData.hpp" #include "prims/jvmtiRedefineClasses.hpp" #include "runtime/compilationPolicy.hpp" @@ -859,6 +860,15 @@ void MethodData::print_data_on(outputStream* st) const { } #endif +#if INCLUDE_SERVICES +// Size Statistics +void MethodData::collect_statistics(KlassSizeStats *sz) const { + int n = sz->count(this); + sz->_method_data_bytes += n; + sz->_method_all_bytes += n; + sz->_rw_bytes += n; +} +#endif // INCLUDE_SERVICES // Verification diff --git a/hotspot/src/share/vm/oops/methodData.hpp b/hotspot/src/share/vm/oops/methodData.hpp index 133278878ef..2f45870f3d2 100644 --- a/hotspot/src/share/vm/oops/methodData.hpp +++ b/hotspot/src/share/vm/oops/methodData.hpp @@ -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 @@ -32,6 +32,7 @@ #include "runtime/orderAccess.hpp" class BytecodeStream; +class KlassSizeStats; // The MethodData object collects counts and other profile information // during zeroth-tier (interpretive) and first-tier execution. @@ -1289,6 +1290,9 @@ public: // My size int size_in_bytes() const { return _size; } int size() const { return align_object_size(align_size_up(_size, BytesPerWord)/BytesPerWord); } +#if INCLUDE_SERVICES + void collect_statistics(KlassSizeStats *sz) const; +#endif int creation_mileage() const { return _creation_mileage; } void set_creation_mileage(int x) { _creation_mileage = x; } @@ -1465,7 +1469,7 @@ public: void inc_decompile_count() { _nof_decompiles += 1; if (decompile_count() > (uint)PerMethodRecompilationCutoff) { - method()->set_not_compilable(CompLevel_full_optimization); + method()->set_not_compilable(CompLevel_full_optimization, true, "decompile_count > PerMethodRecompilationCutoff"); } } diff --git a/hotspot/src/share/vm/oops/objArrayKlass.cpp b/hotspot/src/share/vm/oops/objArrayKlass.cpp index 434fb74abcf..f040206391e 100644 --- a/hotspot/src/share/vm/oops/objArrayKlass.cpp +++ b/hotspot/src/share/vm/oops/objArrayKlass.cpp @@ -43,7 +43,8 @@ #include "runtime/handles.inline.hpp" #include "runtime/mutexLocker.hpp" #include "utilities/copy.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/cmsOopClosures.inline.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1OopClosures.inline.hpp" @@ -54,7 +55,7 @@ #include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" #include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" #include "oops/oop.pcgc.inline.hpp" -#endif +#endif // INCLUDE_ALL_GCS ObjArrayKlass* ObjArrayKlass::allocate(ClassLoaderData* loader_data, int n, KlassHandle klass_handle, Symbol* name, TRAPS) { assert(ObjArrayKlass::header_size() <= InstanceKlass::header_size(), @@ -461,7 +462,7 @@ void ObjArrayKlass::oop_follow_contents(oop obj) { } } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void ObjArrayKlass::oop_follow_contents(ParCompactionManager* cm, oop obj) { assert(obj->is_array(), "obj must be array"); @@ -472,7 +473,7 @@ void ObjArrayKlass::oop_follow_contents(ParCompactionManager* cm, objarray_follow_contents(cm, obj, 0); } } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS #define if_do_metadata_checked(closure, nv_suffix) \ /* Make sure the non-virtual and the virtual versions match. */ \ @@ -573,7 +574,7 @@ int ObjArrayKlass::oop_adjust_pointers(oop obj) { return size; } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void ObjArrayKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { assert(obj->is_objArray(), "obj must be obj array"); ObjArrayKlass_OOP_ITERATE( \ @@ -591,7 +592,7 @@ int ObjArrayKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) { ObjArrayKlass_OOP_ITERATE(a, p, PSParallelCompact::adjust_pointer(p)) return size; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // JVM support diff --git a/hotspot/src/share/vm/oops/objArrayKlass.hpp b/hotspot/src/share/vm/oops/objArrayKlass.hpp index 2234aa8314d..74aa4f8d76d 100644 --- a/hotspot/src/share/vm/oops/objArrayKlass.hpp +++ b/hotspot/src/share/vm/oops/objArrayKlass.hpp @@ -28,6 +28,7 @@ #include "classfile/classLoaderData.hpp" #include "memory/specialized_oop_closures.hpp" #include "oops/arrayKlass.hpp" +#include "utilities/macros.hpp" // ObjArrayKlass is the klass for objArrays @@ -111,11 +112,11 @@ class ObjArrayKlass : public ArrayKlass { // Parallel Scavenge and Parallel Old PARALLEL_GC_DECLS -#ifndef SERIALGC +#if INCLUDE_ALL_GCS inline void oop_follow_contents(ParCompactionManager* cm, oop obj, int index); template inline void objarray_follow_contents(ParCompactionManager* cm, oop obj, int index); -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS // Iterators int oop_oop_iterate(oop obj, ExtendedOopClosure* blk) { diff --git a/hotspot/src/share/vm/oops/objArrayKlass.inline.hpp b/hotspot/src/share/vm/oops/objArrayKlass.inline.hpp index 4a948d82eac..23e809a7e0f 100644 --- a/hotspot/src/share/vm/oops/objArrayKlass.inline.hpp +++ b/hotspot/src/share/vm/oops/objArrayKlass.inline.hpp @@ -27,10 +27,11 @@ #include "gc_implementation/shared/markSweep.inline.hpp" #include "oops/objArrayKlass.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/parallelScavenge/psCompactionManager.inline.hpp" #include "gc_implementation/parallelScavenge/psParallelCompact.hpp" -#endif +#endif // INCLUDE_ALL_GCS void ObjArrayKlass::oop_follow_contents(oop obj, int index) { if (UseCompressedOops) { @@ -63,7 +64,7 @@ void ObjArrayKlass::objarray_follow_contents(oop obj, int index) { } } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void ObjArrayKlass::oop_follow_contents(ParCompactionManager* cm, oop obj, int index) { if (UseCompressedOops) { @@ -96,6 +97,6 @@ void ObjArrayKlass::objarray_follow_contents(ParCompactionManager* cm, oop obj, cm->push_objarray(a, end_index); // Push the continuation. } } -#endif // #ifndef SERIALGC +#endif // INCLUDE_ALL_GCS #endif // SHARE_VM_OOPS_OBJARRAYKLASS_INLINE_HPP diff --git a/hotspot/src/share/vm/oops/oop.hpp b/hotspot/src/share/vm/oops/oop.hpp index 7cb04ff4c00..94e68ed3263 100644 --- a/hotspot/src/share/vm/oops/oop.hpp +++ b/hotspot/src/share/vm/oops/oop.hpp @@ -29,6 +29,7 @@ #include "memory/memRegion.hpp" #include "memory/specialized_oop_closures.hpp" #include "oops/metadata.hpp" +#include "utilities/macros.hpp" #include "utilities/top.hpp" // oopDesc is the top baseclass for objects classes. The {name}Desc classes describe @@ -298,7 +299,7 @@ class oopDesc { // reference field in "this". void follow_contents(void); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Parallel Scavenge void push_contents(PSPromotionManager* pm); @@ -306,7 +307,7 @@ class oopDesc { void update_contents(ParCompactionManager* cm); void follow_contents(ParCompactionManager* cm); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS bool is_scavengable() const; @@ -316,13 +317,13 @@ class oopDesc { void forward_to(oop p); bool cas_forward_to(oop p, markOop compare); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Like "forward_to", but inserts the forwarding pointer atomically. // Exactly one thread succeeds in inserting the forwarding pointer, and // this call returns "NULL" for that thread; any other thread has the // value of the forwarding pointer returned and does not modify "this". oop forward_to_atomic(oop p); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS oop forwardee() const; @@ -334,10 +335,10 @@ class oopDesc { // return the size of this oop. This is used by the MarkSweep collector. int adjust_pointers(); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Parallel old void update_header(ParCompactionManager* cm); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // mark-sweep support void follow_body(int begin, int end); @@ -354,7 +355,7 @@ class oopDesc { ALL_OOP_OOP_ITERATE_CLOSURES_1(OOP_ITERATE_DECL) ALL_OOP_OOP_ITERATE_CLOSURES_2(OOP_ITERATE_DECL) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #define OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ int oop_iterate_backwards(OopClosureType* blk); diff --git a/hotspot/src/share/vm/oops/oop.inline.hpp b/hotspot/src/share/vm/oops/oop.inline.hpp index c097617478d..3c71e15f87c 100644 --- a/hotspot/src/share/vm/oops/oop.inline.hpp +++ b/hotspot/src/share/vm/oops/oop.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 @@ -40,6 +40,7 @@ #include "oops/oop.hpp" #include "runtime/atomic.hpp" #include "runtime/os.hpp" +#include "utilities/macros.hpp" #ifdef TARGET_ARCH_x86 # include "bytes_x86.hpp" #endif @@ -227,12 +228,12 @@ inline oop oopDesc::decode_heap_oop(oop v) { return v; } // might not be the same as oop. inline narrowOop oopDesc::encode_klass_not_null(Klass* v) { - assert(!is_null(v), "oop value can never be zero"); + assert(!is_null(v), "klass value can never be zero"); assert(check_klass_alignment(v), "Address not aligned"); address base = Universe::narrow_klass_base(); int shift = Universe::narrow_klass_shift(); uint64_t pd = (uint64_t)(pointer_delta((void*)v, (void*)base, 1)); - assert(OopEncodingHeapMax > pd, "change encoding max if new encoding"); + assert(KlassEncodingMetaspaceMax > pd, "change encoding max if new encoding"); uint64_t result = pd >> shift; assert((result & CONST64(0xffffffff00000000)) == 0, "narrow klass pointer overflow"); assert(decode_klass(result) == v, "reversibility"); @@ -760,7 +761,7 @@ inline int oopDesc::oop_iterate_no_header(OopClosure* blk, MemRegion mr) { ALL_OOP_OOP_ITERATE_CLOSURES_1(OOP_ITERATE_DEFN) ALL_OOP_OOP_ITERATE_CLOSURES_2(OOP_ITERATE_DEFN) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #define OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ \ inline int oopDesc::oop_iterate_backwards(OopClosureType* blk) { \ @@ -770,6 +771,6 @@ inline int oopDesc::oop_iterate_backwards(OopClosureType* blk) { \ ALL_OOP_OOP_ITERATE_CLOSURES_1(OOP_ITERATE_BACKWARDS_DEFN) ALL_OOP_OOP_ITERATE_CLOSURES_2(OOP_ITERATE_BACKWARDS_DEFN) -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS #endif // SHARE_VM_OOPS_OOP_INLINE_HPP diff --git a/hotspot/src/share/vm/oops/oop.pcgc.inline.hpp b/hotspot/src/share/vm/oops/oop.pcgc.inline.hpp index 050678185f3..d8e40477f79 100644 --- a/hotspot/src/share/vm/oops/oop.pcgc.inline.hpp +++ b/hotspot/src/share/vm/oops/oop.pcgc.inline.hpp @@ -25,14 +25,15 @@ #ifndef SHARE_VM_OOPS_OOP_PCGC_INLINE_HPP #define SHARE_VM_OOPS_OOP_PCGC_INLINE_HPP -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/parNew/parNewGeneration.hpp" #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" #include "gc_implementation/parallelScavenge/psCompactionManager.hpp" #include "gc_implementation/parallelScavenge/psParallelCompact.hpp" #include "gc_implementation/parallelScavenge/psScavenge.hpp" #include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" -#endif +#endif // INCLUDE_ALL_GCS inline void oopDesc::update_contents(ParCompactionManager* cm) { // The klass field must be updated before anything else diff --git a/hotspot/src/share/vm/oops/oop.psgc.inline.hpp b/hotspot/src/share/vm/oops/oop.psgc.inline.hpp index 4d8c3d63da0..ea184f36339 100644 --- a/hotspot/src/share/vm/oops/oop.psgc.inline.hpp +++ b/hotspot/src/share/vm/oops/oop.psgc.inline.hpp @@ -25,11 +25,12 @@ #ifndef SHARE_VM_OOPS_OOP_PSGC_INLINE_HPP #define SHARE_VM_OOPS_OOP_PSGC_INLINE_HPP -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" #include "gc_implementation/parallelScavenge/psScavenge.hpp" #include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" -#endif +#endif // INCLUDE_ALL_GCS // ParallelScavengeHeap methods diff --git a/hotspot/src/share/vm/oops/symbol.cpp b/hotspot/src/share/vm/oops/symbol.cpp index f2253dbcce0..54601899287 100644 --- a/hotspot/src/share/vm/oops/symbol.cpp +++ b/hotspot/src/share/vm/oops/symbol.cpp @@ -152,6 +152,7 @@ char* Symbol::as_C_string_flexible_buffer(Thread* t, } void Symbol::print_symbol_on(outputStream* st) const { + ResourceMark rm; st = st ? st : tty; st->print("%s", as_quoted_ascii()); } diff --git a/hotspot/src/share/vm/oops/typeArrayKlass.cpp b/hotspot/src/share/vm/oops/typeArrayKlass.cpp index 9b6ec260cda..56863a02469 100644 --- a/hotspot/src/share/vm/oops/typeArrayKlass.cpp +++ b/hotspot/src/share/vm/oops/typeArrayKlass.cpp @@ -39,6 +39,7 @@ #include "oops/typeArrayKlass.hpp" #include "oops/typeArrayOop.hpp" #include "runtime/handles.inline.hpp" +#include "utilities/macros.hpp" bool TypeArrayKlass::compute_is_subtype_of(Klass* k) { if (!k->oop_is_typeArray()) { @@ -208,13 +209,13 @@ void TypeArrayKlass::oop_follow_contents(oop obj) { // know that Universe::TypeArrayKlass never moves. } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void TypeArrayKlass::oop_follow_contents(ParCompactionManager* cm, oop obj) { assert(obj->is_typeArray(),"must be a type array"); // Performance tweak: We skip iterating over the klass pointer since we // know that Universe::TypeArrayKlass never moves. } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS int TypeArrayKlass::oop_adjust_pointers(oop obj) { assert(obj->is_typeArray(),"must be a type array"); @@ -240,7 +241,7 @@ int TypeArrayKlass::oop_oop_iterate_m(oop obj, ExtendedOopClosure* blk, MemRegio return t->object_size(); } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void TypeArrayKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { ShouldNotReachHere(); assert(obj->is_typeArray(),"must be a type array"); @@ -251,7 +252,7 @@ TypeArrayKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) { assert(obj->is_typeArray(),"must be a type array"); return typeArrayOop(obj)->object_size(); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS void TypeArrayKlass::initialize(TRAPS) { // Nothing to do. Having this function is handy since objArrayKlasses can be diff --git a/hotspot/src/share/vm/opto/bytecodeInfo.cpp b/hotspot/src/share/vm/opto/bytecodeInfo.cpp index 5b80bd75c4b..3da308c27b2 100644 --- a/hotspot/src/share/vm/opto/bytecodeInfo.cpp +++ b/hotspot/src/share/vm/opto/bytecodeInfo.cpp @@ -420,14 +420,24 @@ const char* InlineTree::check_can_parse(ciMethod* callee) { } //------------------------------print_inlining--------------------------------- -// Really, the failure_msg can be a success message also. -void InlineTree::print_inlining(ciMethod* callee_method, int caller_bci, const char* failure_msg) const { - C->print_inlining(callee_method, inline_level(), caller_bci, failure_msg ? failure_msg : "inline"); - if (callee_method == NULL) tty->print(" callee not monotonic or profiled"); - if (Verbose && callee_method) { - const InlineTree *top = this; - while( top->caller_tree() != NULL ) { top = top->caller_tree(); } - //tty->print(" bcs: %d+%d invoked: %d", top->count_inline_bcs(), callee_method->code_size(), callee_method->interpreter_invocation_count()); +void InlineTree::print_inlining(ciMethod* callee_method, int caller_bci, + const char* msg, bool success) const { + assert(msg != NULL, "just checking"); + if (C->log() != NULL) { + if (success) { + C->log()->inline_success(msg); + } else { + C->log()->inline_fail(msg); + } + } + if (PrintInlining) { + C->print_inlining(callee_method, inline_level(), caller_bci, msg); + if (callee_method == NULL) tty->print(" callee not monotonic or profiled"); + if (Verbose && callee_method) { + const InlineTree *top = this; + while( top->caller_tree() != NULL ) { top = top->caller_tree(); } + //tty->print(" bcs: %d+%d invoked: %d", top->count_inline_bcs(), callee_method->code_size(), callee_method->interpreter_invocation_count()); + } } } @@ -451,23 +461,23 @@ WarmCallInfo* InlineTree::ok_to_inline(ciMethod* callee_method, JVMState* jvms, // Do some initial checks. if (!pass_initial_checks(caller_method, caller_bci, callee_method)) { - if (PrintInlining) print_inlining(callee_method, caller_bci, "failed initial checks"); + print_inlining(callee_method, caller_bci, "failed initial checks", + false /* !success */); return NULL; } // Do some parse checks. failure_msg = check_can_parse(callee_method); if (failure_msg != NULL) { - if (PrintInlining) print_inlining(callee_method, caller_bci, failure_msg); + print_inlining(callee_method, caller_bci, failure_msg, + false /* !success */); return NULL; } // Check if inlining policy says no. WarmCallInfo wci = *(initial_wci); - failure_msg = try_to_inline(callee_method, caller_method, caller_bci, profile, &wci, should_delay); - if (failure_msg != NULL && C->log() != NULL) { - C->log()->inline_fail(failure_msg); - } + failure_msg = try_to_inline(callee_method, caller_method, caller_bci, profile, + &wci, should_delay); #ifndef PRODUCT if (UseOldInlining && InlineWarmCalls @@ -487,7 +497,7 @@ WarmCallInfo* InlineTree::ok_to_inline(ciMethod* callee_method, JVMState* jvms, wci = *(WarmCallInfo::always_hot()); else wci = *(WarmCallInfo::always_cold()); - } + } if (!InlineWarmCalls) { if (!wci.is_cold() && !wci.is_hot()) { // Do not inline the warm calls. @@ -496,11 +506,10 @@ WarmCallInfo* InlineTree::ok_to_inline(ciMethod* callee_method, JVMState* jvms, } if (!wci.is_cold()) { - // In -UseOldInlining, the failure_msg may also be a success message. - if (failure_msg == NULL) failure_msg = "inline (hot)"; - // Inline! - if (PrintInlining) print_inlining(callee_method, caller_bci, failure_msg); + print_inlining(callee_method, caller_bci, + failure_msg ? failure_msg : "inline (hot)", + true /* success */); if (UseOldInlining) build_inline_tree_for_callee(callee_method, jvms, caller_bci); if (InlineWarmCalls && !wci.is_hot()) @@ -509,8 +518,9 @@ WarmCallInfo* InlineTree::ok_to_inline(ciMethod* callee_method, JVMState* jvms, } // Do not inline - if (failure_msg == NULL) failure_msg = "too cold to inline"; - if (PrintInlining) print_inlining(callee_method, caller_bci, failure_msg); + print_inlining(callee_method, caller_bci, + failure_msg ? failure_msg : "too cold to inline", + false /* !success */ ); return NULL; } diff --git a/hotspot/src/share/vm/opto/callGenerator.cpp b/hotspot/src/share/vm/opto/callGenerator.cpp index 89a7c46f6ed..8cac8ee769b 100644 --- a/hotspot/src/share/vm/opto/callGenerator.cpp +++ b/hotspot/src/share/vm/opto/callGenerator.cpp @@ -305,11 +305,13 @@ class LateInlineCallGenerator : public DirectCallGenerator { void LateInlineCallGenerator::do_late_inline() { // Can't inline it if (call_node() == NULL || call_node()->outcnt() == 0 || - call_node()->in(0) == NULL || call_node()->in(0)->is_top()) + call_node()->in(0) == NULL || call_node()->in(0)->is_top()) { return; + } + const TypeTuple *r = call_node()->tf()->domain(); for (int i1 = 0; i1 < method()->arg_size(); i1++) { - if (call_node()->in(TypeFunc::Parms + i1)->is_top()) { + if (call_node()->in(TypeFunc::Parms + i1)->is_top() && r->field_at(TypeFunc::Parms + i1) != Type::HALF) { assert(Compile::current()->inlining_incrementally(), "shouldn't happen during parsing"); return; } diff --git a/hotspot/src/share/vm/opto/generateOptoStub.cpp b/hotspot/src/share/vm/opto/generateOptoStub.cpp index 56fc759f2d2..c5ebd5ad524 100644 --- a/hotspot/src/share/vm/opto/generateOptoStub.cpp +++ b/hotspot/src/share/vm/opto/generateOptoStub.cpp @@ -88,12 +88,12 @@ void GraphKit::gen_stub(address C_function, thread, in_bytes(JavaThread::frame_anchor_offset()) + in_bytes(JavaFrameAnchor::last_Java_pc_offset())); -#if defined(SPARC) || defined(IA64) +#if defined(SPARC) Node* adr_flags = basic_plus_adr(top(), thread, in_bytes(JavaThread::frame_anchor_offset()) + in_bytes(JavaFrameAnchor::flags_offset())); -#endif /* defined(SPARC) || defined(IA64) */ +#endif /* defined(SPARC) */ // Drop in the last_Java_sp. last_Java_fp is not touched. @@ -102,10 +102,8 @@ void GraphKit::gen_stub(address C_function, // users will look at the other fields. // Node *adr_sp = basic_plus_adr(top(), thread, in_bytes(JavaThread::last_Java_sp_offset())); -#ifndef IA64 Node *last_sp = basic_plus_adr(top(), frameptr(), (intptr_t) STACK_BIAS); store_to_memory(NULL, adr_sp, last_sp, T_ADDRESS, NoAlias); -#endif // Set _thread_in_native // The order of stores into TLS is critical! Setting _thread_in_native MUST @@ -210,19 +208,12 @@ void GraphKit::gen_stub(address C_function, //----------------------------- // Clear last_Java_sp -#ifdef IA64 - if( os::is_MP() ) insert_mem_bar(Op_MemBarRelease); -#endif - store_to_memory(NULL, adr_sp, null(), T_ADDRESS, NoAlias); -#ifdef IA64 - if (os::is_MP() && UseMembar) insert_mem_bar(new MemBarVolatileNode()); -#endif // def IA64 // Clear last_Java_pc and (optionally)_flags store_to_memory(NULL, adr_last_Java_pc, null(), T_ADDRESS, NoAlias); -#if defined(SPARC) || defined(IA64) +#if defined(SPARC) store_to_memory(NULL, adr_flags, intcon(0), T_INT, NoAlias); -#endif /* defined(SPARC) || defined(IA64) */ +#endif /* defined(SPARC) */ #ifdef IA64 Node* adr_last_Java_fp = basic_plus_adr(top(), thread, in_bytes(JavaThread::last_Java_fp_offset())); if( os::is_MP() ) insert_mem_bar(Op_MemBarRelease); diff --git a/hotspot/src/share/vm/opto/parse.hpp b/hotspot/src/share/vm/opto/parse.hpp index c880832a446..2cf487f8ad6 100644 --- a/hotspot/src/share/vm/opto/parse.hpp +++ b/hotspot/src/share/vm/opto/parse.hpp @@ -73,7 +73,8 @@ protected: const char* try_to_inline(ciMethod* callee_method, ciMethod* caller_method, int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result, bool& should_delay); const char* should_inline(ciMethod* callee_method, ciMethod* caller_method, int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result) const; const char* should_not_inline(ciMethod* callee_method, ciMethod* caller_method, WarmCallInfo* wci_result) const; - void print_inlining(ciMethod *callee_method, int caller_bci, const char *failure_msg) const; + void print_inlining(ciMethod* callee_method, int caller_bci, + const char* msg, bool success) const; InlineTree *caller_tree() const { return _caller_tree; } InlineTree* callee_at(int bci, ciMethod* m) const; diff --git a/hotspot/src/share/vm/opto/parse3.cpp b/hotspot/src/share/vm/opto/parse3.cpp index ac6f4ec8f76..9de92a2ae54 100644 --- a/hotspot/src/share/vm/opto/parse3.cpp +++ b/hotspot/src/share/vm/opto/parse3.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 @@ -487,7 +487,8 @@ void Parse::do_multianewarray() { fun, NULL, TypeRawPtr::BOTTOM, makecon(TypeKlassPtr::make(array_klass)), length[0], length[1], length[2], - length[3], length[4]); + (ndimensions > 2) ? length[3] : NULL, + (ndimensions > 3) ? length[4] : NULL); } else { // Create a java array for dimension sizes Node* dims = NULL; diff --git a/hotspot/src/share/vm/precompiled/precompiled.hpp b/hotspot/src/share/vm/precompiled/precompiled.hpp index 1bbc5599b75..118fe9c1bde 100644 --- a/hotspot/src/share/vm/precompiled/precompiled.hpp +++ b/hotspot/src/share/vm/precompiled/precompiled.hpp @@ -24,6 +24,7 @@ // Precompiled headers are turned off for Sun Studion, // or if the user passes USE_PRECOMPILED_HEADER=0 to the makefiles. + #ifndef DONT_USE_PRECOMPILED_HEADER # include "asm/assembler.hpp" @@ -285,7 +286,7 @@ # include "c1/c1_ValueType.hpp" # include "c1/c1_globals.hpp" #endif // COMPILER1 -#ifndef SERIALGC +#if INCLUDE_ALL_GCS # include "gc_implementation/concurrentMarkSweep/cmsOopClosures.hpp" # include "gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp" # include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp" @@ -314,6 +315,6 @@ # include "gc_implementation/shared/gcAdaptivePolicyCounters.hpp" # include "gc_implementation/shared/gcPolicyCounters.hpp" # include "gc_implementation/shared/parGCAllocBuffer.hpp" -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS #endif // !DONT_USE_PRECOMPILED_HEADER diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp index ddbde753f1c..f45568a7ca7 100644 --- a/hotspot/src/share/vm/prims/jni.cpp +++ b/hotspot/src/share/vm/prims/jni.cpp @@ -32,9 +32,10 @@ #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" #include "interpreter/linkResolver.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS #include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" #include "memory/gcLocker.inline.hpp" @@ -2641,7 +2642,7 @@ JNI_ENTRY(jobject, jni_GetObjectField(JNIEnv *env, jobject obj, jfieldID fieldID o = JvmtiExport::jni_GetField_probe(thread, obj, o, k, fieldID, false); } jobject ret = JNIHandles::make_local(env, o->obj_field(offset)); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // If G1 is enabled and we are accessing the value of the referent // field in a reference object then we need to register a non-null // referent with the SATB barrier. @@ -2660,7 +2661,7 @@ JNI_ENTRY(jobject, jni_GetObjectField(JNIEnv *env, jobject obj, jfieldID fieldID G1SATBCardTableModRefBS::enqueue(referent); } } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS #ifndef USDT2 DTRACE_PROBE1(hotspot_jni, GetObjectField__return, ret); #else /* USDT2 */ diff --git a/hotspot/src/share/vm/prims/jniCheck.hpp b/hotspot/src/share/vm/prims/jniCheck.hpp index e5f5071b3a3..169ab7be3f4 100644 --- a/hotspot/src/share/vm/prims/jniCheck.hpp +++ b/hotspot/src/share/vm/prims/jniCheck.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 @@ -25,9 +25,7 @@ #ifndef SHARE_VM_PRIMS_JNICHECK_HPP #define SHARE_VM_PRIMS_JNICHECK_HPP -#ifndef KERNEL #include "runtime/thread.hpp" -#endif extern "C" { // Report a JNI failure caught by -Xcheck:jni. Perform a core dump. diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp index f5d126368ff..84ab5f04828 100644 --- a/hotspot/src/share/vm/prims/jvm.cpp +++ b/hotspot/src/share/vm/prims/jvm.cpp @@ -1620,7 +1620,7 @@ JVM_ENTRY(jobjectArray, JVM_GetMethodParameters(JNIEnv *env, jobject method)) // 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); + int flags = params[i].flags; oop param = Reflection::new_parameter(reflected_method, i, sym, flags, CHECK_NULL); result->obj_at_put(i, param); @@ -2302,6 +2302,15 @@ JVM_QUICK_ENTRY(jboolean, JVM_IsConstructorIx(JNIEnv *env, jclass cls, int metho JVM_END +JVM_QUICK_ENTRY(jboolean, JVM_IsVMGeneratedMethodIx(JNIEnv *env, jclass cls, int method_index)) + JVMWrapper("JVM_IsVMGeneratedMethodIx"); + ResourceMark rm(THREAD); + Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(cls)); + k = JvmtiThreadState::class_to_verify_considering_redefinition(k, thread); + Method* method = InstanceKlass::cast(k)->methods()->at(method_index); + return method->is_overpass(); +JVM_END + JVM_ENTRY(const char*, JVM_GetMethodIxNameUTF(JNIEnv *env, jclass cls, jint method_index)) JVMWrapper("JVM_GetMethodIxIxUTF"); Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(cls)); @@ -4519,10 +4528,6 @@ JVM_ENTRY(void, JVM_GetVersionInfo(JNIEnv* env, jvm_version_info* info, size_t i // consider to expose this new capability in the sun.rt.jvmCapabilities jvmstat // counter defined in runtimeService.cpp. info->is_attachable = AttachListener::is_attach_supported(); -#ifdef KERNEL - info->is_kernel_jvm = 1; // true; -#else // KERNEL info->is_kernel_jvm = 0; // false; -#endif // KERNEL } JVM_END diff --git a/hotspot/src/share/vm/prims/jvm.h b/hotspot/src/share/vm/prims/jvm.h index c081f872afa..dea46d126eb 100644 --- a/hotspot/src/share/vm/prims/jvm.h +++ b/hotspot/src/share/vm/prims/jvm.h @@ -859,6 +859,13 @@ JVM_GetMethodIxMaxStack(JNIEnv *env, jclass cb, int index); JNIEXPORT jboolean JNICALL JVM_IsConstructorIx(JNIEnv *env, jclass cb, int index); +/* + * Is the given method generated by the VM. + * The method is identified by method_index. + */ +JNIEXPORT jboolean JNICALL +JVM_IsVMGeneratedMethodIx(JNIEnv *env, jclass cb, int index); + /* * Returns the name of a given method in UTF format. * The result remains valid until JVM_ReleaseUTF is called. diff --git a/hotspot/src/share/vm/prims/jvmtiCodeBlobEvents.hpp b/hotspot/src/share/vm/prims/jvmtiCodeBlobEvents.hpp index 92adaaf80e8..00da7ca6ca1 100644 --- a/hotspot/src/share/vm/prims/jvmtiCodeBlobEvents.hpp +++ b/hotspot/src/share/vm/prims/jvmtiCodeBlobEvents.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,9 +25,7 @@ #ifndef SHARE_VM_PRIMS_JVMTICODEBLOBEVENTS_HPP #define SHARE_VM_PRIMS_JVMTICODEBLOBEVENTS_HPP -#ifndef JVMTI_KERNEL #include "jvmtifiles/jvmti.h" -#endif // forward declaration class JvmtiEnv; diff --git a/hotspot/src/share/vm/prims/jvmtiEnv.cpp b/hotspot/src/share/vm/prims/jvmtiEnv.cpp index cb3b3db1e1c..318fe4e0b7e 100644 --- a/hotspot/src/share/vm/prims/jvmtiEnv.cpp +++ b/hotspot/src/share/vm/prims/jvmtiEnv.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 @@ -647,8 +647,6 @@ JvmtiEnv::GetJLocationFormat(jvmtiJlocationFormat* format_ptr) { return JVMTI_ERROR_NONE; } /* end GetJLocationFormat */ -#ifndef JVMTI_KERNEL - // // Thread functions // @@ -3436,5 +3434,3 @@ JvmtiEnv::SetSystemProperty(const char* property, const char* value_ptr) { } return err; } /* end SetSystemProperty */ - -#endif // !JVMTI_KERNEL diff --git a/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp b/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp index eed31268141..56387634179 100644 --- a/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp +++ b/hotspot/src/share/vm/prims/jvmtiEnvBase.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 @@ -74,10 +74,8 @@ JvmtiEnvBase::globally_initialize() { JvmtiManageCapabilities::initialize(); -#ifndef JVMTI_KERNEL // register extension functions and events JvmtiExtensions::register_extensions(); -#endif // !JVMTI_KERNEL #ifdef JVMTI_TRACE JvmtiTrace::initialize(); @@ -236,14 +234,12 @@ JvmtiEnvBase::env_dispose() { // Same situation as with events (see above) set_native_method_prefixes(0, NULL); -#ifndef JVMTI_KERNEL JvmtiTagMap* tag_map_to_deallocate = _tag_map; set_tag_map(NULL); // A tag map can be big, deallocate it now if (tag_map_to_deallocate != NULL) { delete tag_map_to_deallocate; } -#endif // !JVMTI_KERNEL _needs_clean_up = true; } @@ -255,14 +251,12 @@ JvmtiEnvBase::~JvmtiEnvBase() { // There is a small window of time during which the tag map of a // disposed environment could have been reallocated. // Make sure it is gone. -#ifndef JVMTI_KERNEL JvmtiTagMap* tag_map_to_deallocate = _tag_map; set_tag_map(NULL); // A tag map can be big, deallocate it now if (tag_map_to_deallocate != NULL) { delete tag_map_to_deallocate; } -#endif // !JVMTI_KERNEL _magic = BAD_MAGIC; } @@ -593,8 +587,6 @@ JvmtiEnvBase::get_jni_class_non_null(Klass* k) { return (jclass)jni_reference(k->java_mirror()); } -#ifndef JVMTI_KERNEL - // // Field Information // @@ -1482,5 +1474,3 @@ JvmtiMonitorClosure::do_monitor(ObjectMonitor* mon) { } } } - -#endif // !JVMTI_KERNEL diff --git a/hotspot/src/share/vm/prims/jvmtiEnvBase.hpp b/hotspot/src/share/vm/prims/jvmtiEnvBase.hpp index d7b7d7cf63c..929dcf22260 100644 --- a/hotspot/src/share/vm/prims/jvmtiEnvBase.hpp +++ b/hotspot/src/share/vm/prims/jvmtiEnvBase.hpp @@ -35,6 +35,7 @@ #include "runtime/thread.hpp" #include "runtime/vm_operations.hpp" #include "utilities/growableArray.hpp" +#include "utilities/macros.hpp" // // Forward Declarations diff --git a/hotspot/src/share/vm/prims/jvmtiExport.cpp b/hotspot/src/share/vm/prims/jvmtiExport.cpp index cb5a1f454d9..ab66dca33d6 100644 --- a/hotspot/src/share/vm/prims/jvmtiExport.cpp +++ b/hotspot/src/share/vm/prims/jvmtiExport.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 @@ -50,9 +50,10 @@ #include "runtime/vframe.hpp" #include "services/attachListener.hpp" #include "services/serviceUtil.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/parallelScavenge/psMarkSweep.hpp" -#endif +#endif // INCLUDE_ALL_GCS #ifdef JVMTI_TRACE #define EVT_TRACE(evt,out) if ((JvmtiTrace::event_trace_flags(evt) & JvmtiTrace::SHOW_EVENT_SENT) != 0) { SafeResourceMark rm; tty->print_cr out; } @@ -677,7 +678,6 @@ void JvmtiExport::report_unsupported(bool on) { } -#ifndef JVMTI_KERNEL static inline Klass* oop_to_klass(oop obj) { Klass* k = obj->klass(); @@ -2178,7 +2178,6 @@ extern "C" { typedef jint (JNICALL *OnAttachEntry_t)(JavaVM*, char *, void *); } -#ifndef SERVICES_KERNEL jint JvmtiExport::load_agent_library(AttachOperation* op, outputStream* st) { char ebuf[1024]; char buffer[JVM_MAXPATHLEN]; @@ -2259,7 +2258,6 @@ jint JvmtiExport::load_agent_library(AttachOperation* op, outputStream* st) { } return result; } -#endif // SERVICES_KERNEL //////////////////////////////////////////////////////////////////////////////////////////////// @@ -2457,4 +2455,3 @@ JvmtiGCMarker::~JvmtiGCMarker() { JvmtiExport::post_garbage_collection_finish(); } } -#endif // JVMTI_KERNEL diff --git a/hotspot/src/share/vm/prims/jvmtiExport.hpp b/hotspot/src/share/vm/prims/jvmtiExport.hpp index 1100d526995..a1e0e0bd44a 100644 --- a/hotspot/src/share/vm/prims/jvmtiExport.hpp +++ b/hotspot/src/share/vm/prims/jvmtiExport.hpp @@ -34,6 +34,7 @@ #include "runtime/handles.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/growableArray.hpp" +#include "utilities/macros.hpp" // Must be included after jvmti.h. #include "code/jvmticmlr.h" diff --git a/hotspot/src/share/vm/prims/jvmtiExtensions.hpp b/hotspot/src/share/vm/prims/jvmtiExtensions.hpp index a5e3433315e..f85003f6bf6 100644 --- a/hotspot/src/share/vm/prims/jvmtiExtensions.hpp +++ b/hotspot/src/share/vm/prims/jvmtiExtensions.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,11 +25,9 @@ #ifndef SHARE_VM_PRIMS_JVMTIEXTENSIONS_HPP #define SHARE_VM_PRIMS_JVMTIEXTENSIONS_HPP -#ifndef JVMTI_KERNEL #include "jvmtifiles/jvmti.h" #include "jvmtifiles/jvmtiEnv.hpp" #include "memory/allocation.hpp" -#endif // JvmtiExtensions // diff --git a/hotspot/src/share/vm/prims/jvmtiImpl.cpp b/hotspot/src/share/vm/prims/jvmtiImpl.cpp index bb7714d4932..4a1747e1bd2 100644 --- a/hotspot/src/share/vm/prims/jvmtiImpl.cpp +++ b/hotspot/src/share/vm/prims/jvmtiImpl.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 @@ -905,8 +905,6 @@ void JvmtiSuspendControl::print() { #endif } -#ifndef KERNEL - JvmtiDeferredEvent JvmtiDeferredEvent::compiled_method_load_event( nmethod* nm) { JvmtiDeferredEvent event = JvmtiDeferredEvent(TYPE_COMPILED_METHOD_LOAD); @@ -1098,5 +1096,3 @@ void JvmtiDeferredEventQueue::process_pending_events() { } } } - -#endif // ndef KERNEL diff --git a/hotspot/src/share/vm/prims/jvmtiImpl.hpp b/hotspot/src/share/vm/prims/jvmtiImpl.hpp index d785930be0d..204bd83f124 100644 --- a/hotspot/src/share/vm/prims/jvmtiImpl.hpp +++ b/hotspot/src/share/vm/prims/jvmtiImpl.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 @@ -25,8 +25,6 @@ #ifndef SHARE_VM_PRIMS_JVMTIIMPL_HPP #define SHARE_VM_PRIMS_JVMTIIMPL_HPP -#ifndef JVMTI_KERNEL - #include "classfile/systemDictionary.hpp" #include "jvmtifiles/jvmti.h" #include "oops/objArrayOop.hpp" @@ -435,7 +433,6 @@ public: static void print(); }; -#endif // !JVMTI_KERNEL /** * When a thread (such as the compiler thread or VM thread) cannot post a diff --git a/hotspot/src/share/vm/prims/jvmtiRawMonitor.hpp b/hotspot/src/share/vm/prims/jvmtiRawMonitor.hpp index e5b25fa3a82..8c182f318ec 100644 --- a/hotspot/src/share/vm/prims/jvmtiRawMonitor.hpp +++ b/hotspot/src/share/vm/prims/jvmtiRawMonitor.hpp @@ -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 @@ -25,10 +25,8 @@ #ifndef SHARE_VM_PRIMS_JVMTIRAWMONITOR_HPP #define SHARE_VM_PRIMS_JVMTIRAWMONITOR_HPP -#ifndef JVMTI_KERNEL #include "runtime/objectMonitor.hpp" #include "utilities/growableArray.hpp" -#endif // // class JvmtiRawMonitor diff --git a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp index 7e68f2b1059..ce1ec56ef65 100644 --- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp +++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/metadataOnStackMark.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/verifier.hpp" #include "code/codeCache.hpp" @@ -115,43 +116,6 @@ bool VM_RedefineClasses::doit_prologue() { return true; } -// Keep track of marked on-stack metadata so it can be cleared. -GrowableArray* _marked_objects = NULL; -NOT_PRODUCT(bool MetadataOnStackMark::_is_active = false;) - -// Walk metadata on the stack and mark it so that redefinition doesn't delete -// it. Class unloading also walks the previous versions and might try to -// delete it, so this class is used by class unloading also. -MetadataOnStackMark::MetadataOnStackMark() { - assert(SafepointSynchronize::is_at_safepoint(), "sanity check"); - NOT_PRODUCT(_is_active = true;) - if (_marked_objects == NULL) { - _marked_objects = new (ResourceObj::C_HEAP, mtClass) GrowableArray(1000, true); - } - Threads::metadata_do(Metadata::mark_on_stack); - CodeCache::alive_nmethods_do(nmethod::mark_on_stack); - CompileBroker::mark_on_stack(); -} - -MetadataOnStackMark::~MetadataOnStackMark() { - assert(SafepointSynchronize::is_at_safepoint(), "sanity check"); - // Unmark everything that was marked. Can't do the same walk because - // redefine classes messes up the code cache so the set of methods - // might not be the same. - for (int i = 0; i< _marked_objects->length(); i++) { - _marked_objects->at(i)->set_on_stack(false); - } - _marked_objects->clear(); // reuse growable array for next time. - NOT_PRODUCT(_is_active = false;) -} - -// Record which objects are marked so we can unmark the same objects. -void MetadataOnStackMark::record(Metadata* m) { - assert(_is_active, "metadata on stack marking is active"); - _marked_objects->push(m); -} - - void VM_RedefineClasses::doit() { Thread *thread = Thread::current(); @@ -314,76 +278,23 @@ void VM_RedefineClasses::append_entry(constantPoolHandle scratch_cp, case JVM_CONSTANT_NameAndType: { int name_ref_i = scratch_cp->name_ref_index_at(scratch_i); - int new_name_ref_i = 0; - bool match = (name_ref_i < *merge_cp_length_p) && - scratch_cp->compare_entry_to(name_ref_i, *merge_cp_p, name_ref_i, - THREAD); - if (!match) { - // forward reference in *merge_cp_p or not a direct match - - int found_i = scratch_cp->find_matching_entry(name_ref_i, *merge_cp_p, - THREAD); - if (found_i != 0) { - guarantee(found_i != name_ref_i, - "compare_entry_to() and find_matching_entry() do not agree"); - - // Found a matching entry somewhere else in *merge_cp_p so - // just need a mapping entry. - new_name_ref_i = found_i; - map_index(scratch_cp, name_ref_i, found_i); - } else { - // no match found so we have to append this entry to *merge_cp_p - append_entry(scratch_cp, name_ref_i, merge_cp_p, merge_cp_length_p, - THREAD); - // The above call to append_entry() can only append one entry - // so the post call query of *merge_cp_length_p is only for - // the sake of consistency. - new_name_ref_i = *merge_cp_length_p - 1; - } - } + int new_name_ref_i = find_or_append_indirect_entry(scratch_cp, name_ref_i, merge_cp_p, + merge_cp_length_p, THREAD); int signature_ref_i = scratch_cp->signature_ref_index_at(scratch_i); - int new_signature_ref_i = 0; - match = (signature_ref_i < *merge_cp_length_p) && - scratch_cp->compare_entry_to(signature_ref_i, *merge_cp_p, - signature_ref_i, THREAD); - if (!match) { - // forward reference in *merge_cp_p or not a direct match - - int found_i = scratch_cp->find_matching_entry(signature_ref_i, - *merge_cp_p, THREAD); - if (found_i != 0) { - guarantee(found_i != signature_ref_i, - "compare_entry_to() and find_matching_entry() do not agree"); - - // Found a matching entry somewhere else in *merge_cp_p so - // just need a mapping entry. - new_signature_ref_i = found_i; - map_index(scratch_cp, signature_ref_i, found_i); - } else { - // no match found so we have to append this entry to *merge_cp_p - append_entry(scratch_cp, signature_ref_i, merge_cp_p, - merge_cp_length_p, THREAD); - // The above call to append_entry() can only append one entry - // so the post call query of *merge_cp_length_p is only for - // the sake of consistency. - new_signature_ref_i = *merge_cp_length_p - 1; - } - } + int new_signature_ref_i = find_or_append_indirect_entry(scratch_cp, signature_ref_i, + merge_cp_p, merge_cp_length_p, + THREAD); // If the referenced entries already exist in *merge_cp_p, then // both new_name_ref_i and new_signature_ref_i will both be 0. // In that case, all we are appending is the current entry. - if (new_name_ref_i == 0) { - new_name_ref_i = name_ref_i; - } else { + if (new_name_ref_i != name_ref_i) { RC_TRACE(0x00080000, ("NameAndType entry@%d name_ref_index change: %d to %d", *merge_cp_length_p, name_ref_i, new_name_ref_i)); } - if (new_signature_ref_i == 0) { - new_signature_ref_i = signature_ref_i; - } else { + if (new_signature_ref_i != signature_ref_i) { RC_TRACE(0x00080000, ("NameAndType entry@%d signature_ref_index change: %d to %d", *merge_cp_length_p, signature_ref_i, new_signature_ref_i)); @@ -405,76 +316,12 @@ void VM_RedefineClasses::append_entry(constantPoolHandle scratch_cp, case JVM_CONSTANT_Methodref: { int klass_ref_i = scratch_cp->uncached_klass_ref_index_at(scratch_i); - int new_klass_ref_i = 0; - bool match = (klass_ref_i < *merge_cp_length_p) && - scratch_cp->compare_entry_to(klass_ref_i, *merge_cp_p, klass_ref_i, - THREAD); - if (!match) { - // forward reference in *merge_cp_p or not a direct match + int new_klass_ref_i = find_or_append_indirect_entry(scratch_cp, klass_ref_i, + merge_cp_p, merge_cp_length_p, THREAD); - int found_i = scratch_cp->find_matching_entry(klass_ref_i, *merge_cp_p, - THREAD); - if (found_i != 0) { - guarantee(found_i != klass_ref_i, - "compare_entry_to() and find_matching_entry() do not agree"); - - // Found a matching entry somewhere else in *merge_cp_p so - // just need a mapping entry. - new_klass_ref_i = found_i; - map_index(scratch_cp, klass_ref_i, found_i); - } else { - // no match found so we have to append this entry to *merge_cp_p - append_entry(scratch_cp, klass_ref_i, merge_cp_p, merge_cp_length_p, - THREAD); - // The above call to append_entry() can only append one entry - // so the post call query of *merge_cp_length_p is only for - // the sake of consistency. Without the optimization where we - // use JVM_CONSTANT_UnresolvedClass, then up to two entries - // could be appended. - new_klass_ref_i = *merge_cp_length_p - 1; - } - } - - int name_and_type_ref_i = - scratch_cp->uncached_name_and_type_ref_index_at(scratch_i); - int new_name_and_type_ref_i = 0; - match = (name_and_type_ref_i < *merge_cp_length_p) && - scratch_cp->compare_entry_to(name_and_type_ref_i, *merge_cp_p, - name_and_type_ref_i, THREAD); - if (!match) { - // forward reference in *merge_cp_p or not a direct match - - int found_i = scratch_cp->find_matching_entry(name_and_type_ref_i, - *merge_cp_p, THREAD); - if (found_i != 0) { - guarantee(found_i != name_and_type_ref_i, - "compare_entry_to() and find_matching_entry() do not agree"); - - // Found a matching entry somewhere else in *merge_cp_p so - // just need a mapping entry. - new_name_and_type_ref_i = found_i; - map_index(scratch_cp, name_and_type_ref_i, found_i); - } else { - // no match found so we have to append this entry to *merge_cp_p - append_entry(scratch_cp, name_and_type_ref_i, merge_cp_p, - merge_cp_length_p, THREAD); - // The above call to append_entry() can append more than - // one entry so the post call query of *merge_cp_length_p - // is required in order to get the right index for the - // JVM_CONSTANT_NameAndType entry. - new_name_and_type_ref_i = *merge_cp_length_p - 1; - } - } - - // If the referenced entries already exist in *merge_cp_p, then - // both new_klass_ref_i and new_name_and_type_ref_i will both be - // 0. In that case, all we are appending is the current entry. - if (new_klass_ref_i == 0) { - new_klass_ref_i = klass_ref_i; - } - if (new_name_and_type_ref_i == 0) { - new_name_and_type_ref_i = name_and_type_ref_i; - } + int name_and_type_ref_i = scratch_cp->uncached_name_and_type_ref_index_at(scratch_i); + int new_name_and_type_ref_i = find_or_append_indirect_entry(scratch_cp, name_and_type_ref_i, + merge_cp_p, merge_cp_length_p, THREAD); const char *entry_name; switch (scratch_cp->tag_at(scratch_i).value()) { @@ -517,6 +364,72 @@ void VM_RedefineClasses::append_entry(constantPoolHandle scratch_cp, (*merge_cp_length_p)++; } break; + // this is an indirect CP entry so it needs special handling + case JVM_CONSTANT_MethodType: + { + int ref_i = scratch_cp->method_type_index_at(scratch_i); + int new_ref_i = find_or_append_indirect_entry(scratch_cp, ref_i, merge_cp_p, + merge_cp_length_p, THREAD); + if (new_ref_i != ref_i) { + RC_TRACE(0x00080000, + ("MethodType entry@%d ref_index change: %d to %d", + *merge_cp_length_p, ref_i, new_ref_i)); + } + (*merge_cp_p)->method_type_index_at_put(*merge_cp_length_p, new_ref_i); + if (scratch_i != *merge_cp_length_p) { + // The new entry in *merge_cp_p is at a different index than + // the new entry in scratch_cp so we need to map the index values. + map_index(scratch_cp, scratch_i, *merge_cp_length_p); + } + (*merge_cp_length_p)++; + } break; + + // this is an indirect CP entry so it needs special handling + case JVM_CONSTANT_MethodHandle: + { + int ref_kind = scratch_cp->method_handle_ref_kind_at(scratch_i); + int ref_i = scratch_cp->method_handle_index_at(scratch_i); + int new_ref_i = find_or_append_indirect_entry(scratch_cp, ref_i, merge_cp_p, + merge_cp_length_p, THREAD); + if (new_ref_i != ref_i) { + RC_TRACE(0x00080000, + ("MethodHandle entry@%d ref_index change: %d to %d", + *merge_cp_length_p, ref_i, new_ref_i)); + } + (*merge_cp_p)->method_handle_index_at_put(*merge_cp_length_p, ref_kind, new_ref_i); + if (scratch_i != *merge_cp_length_p) { + // The new entry in *merge_cp_p is at a different index than + // the new entry in scratch_cp so we need to map the index values. + map_index(scratch_cp, scratch_i, *merge_cp_length_p); + } + (*merge_cp_length_p)++; + } break; + + // this is an indirect CP entry so it needs special handling + case JVM_CONSTANT_InvokeDynamic: + { + // TBD: cross-checks and possible extra appends into CP and bsm operands + // are needed as well. This issue is tracked by a separate bug 8007037. + int bss_idx = scratch_cp->invoke_dynamic_bootstrap_specifier_index(scratch_i); + + int ref_i = scratch_cp->invoke_dynamic_name_and_type_ref_index_at(scratch_i); + int new_ref_i = find_or_append_indirect_entry(scratch_cp, ref_i, merge_cp_p, + merge_cp_length_p, THREAD); + if (new_ref_i != ref_i) { + RC_TRACE(0x00080000, + ("InvokeDynamic entry@%d name_and_type ref_index change: %d to %d", + *merge_cp_length_p, ref_i, new_ref_i)); + } + + (*merge_cp_p)->invoke_dynamic_at_put(*merge_cp_length_p, bss_idx, new_ref_i); + if (scratch_i != *merge_cp_length_p) { + // The new entry in *merge_cp_p is at a different index than + // the new entry in scratch_cp so we need to map the index values. + map_index(scratch_cp, scratch_i, *merge_cp_length_p); + } + (*merge_cp_length_p)++; + } break; + // At this stage, Class or UnresolvedClass could be here, but not // ClassIndex case JVM_CONSTANT_ClassIndex: // fall through @@ -543,6 +456,35 @@ void VM_RedefineClasses::append_entry(constantPoolHandle scratch_cp, } // end append_entry() +int VM_RedefineClasses::find_or_append_indirect_entry(constantPoolHandle scratch_cp, + int ref_i, constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS) { + + int new_ref_i = ref_i; + bool match = (ref_i < *merge_cp_length_p) && + scratch_cp->compare_entry_to(ref_i, *merge_cp_p, ref_i, THREAD); + + if (!match) { + // forward reference in *merge_cp_p or not a direct match + int found_i = scratch_cp->find_matching_entry(ref_i, *merge_cp_p, THREAD); + if (found_i != 0) { + guarantee(found_i != ref_i, "compare_entry_to() and find_matching_entry() do not agree"); + // Found a matching entry somewhere else in *merge_cp_p so just need a mapping entry. + new_ref_i = found_i; + map_index(scratch_cp, ref_i, found_i); + } else { + // no match found so we have to append this entry to *merge_cp_p + append_entry(scratch_cp, ref_i, merge_cp_p, merge_cp_length_p, THREAD); + // The above call to append_entry() can only append one entry + // so the post call query of *merge_cp_length_p is only for + // the sake of consistency. + new_ref_i = *merge_cp_length_p - 1; + } + } + + return new_ref_i; +} // end find_or_append_indirect_entry() + + void VM_RedefineClasses::swap_all_method_annotations(int i, int j, instanceKlassHandle scratch_class, TRAPS) { AnnotationArray* save; @@ -1158,6 +1100,8 @@ bool VM_RedefineClasses::merge_constant_pools(constantPoolHandle old_cp, } } // end for each old_cp entry + ConstantPool::copy_operands(old_cp, *merge_cp_p, CHECK_0); + // We don't need to sanity check that *merge_cp_length_p is within // *merge_cp_p bounds since we have the minimum on-entry check above. (*merge_cp_length_p) = old_i; @@ -1341,8 +1285,12 @@ jvmtiError VM_RedefineClasses::merge_cp_and_rewrite( _index_map_count = 0; _index_map_p = new intArray(scratch_cp->length(), -1); + // reference to the cp holder is needed for copy_operands() + merge_cp->set_pool_holder(scratch_class()); bool result = merge_constant_pools(old_cp, scratch_cp, &merge_cp, &merge_cp_length, THREAD); + merge_cp->set_pool_holder(NULL); + if (!result) { // The merge can fail due to memory allocation failure or due // to robustness checks. @@ -1594,6 +1542,7 @@ void VM_RedefineClasses::rewrite_cp_refs_in_method(methodHandle method, case Bytecodes::_getfield : // fall through case Bytecodes::_getstatic : // fall through case Bytecodes::_instanceof : // fall through + case Bytecodes::_invokedynamic : // fall through case Bytecodes::_invokeinterface: // fall through case Bytecodes::_invokespecial : // fall through case Bytecodes::_invokestatic : // fall through @@ -2416,13 +2365,14 @@ void VM_RedefineClasses::set_new_constant_pool( assert(version != 0, "sanity check"); smaller_cp->set_version(version); + // attach klass to new constant pool + // reference to the cp holder is needed for copy_operands() + smaller_cp->set_pool_holder(scratch_class()); + 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()); - - // attach klass to new constant pool scratch_class->set_constants(scratch_cp()); int i; // for portability @@ -3140,11 +3090,9 @@ void VM_RedefineClasses::redefine_single_class(jclass the_jclass, Klass* the_class_oop = java_lang_Class::as_Klass(the_class_mirror); instanceKlassHandle the_class = instanceKlassHandle(THREAD, the_class_oop); -#ifndef JVMTI_KERNEL // Remove all breakpoints in methods of this class JvmtiBreakpoints& jvmti_breakpoints = JvmtiCurrentBreakpoints::get_jvmti_breakpoints(); jvmti_breakpoints.clearall_in_class_at_safepoint(the_class_oop); -#endif // !JVMTI_KERNEL if (the_class_oop == Universe::reflect_invoke_cache()->klass()) { // We are redefining java.lang.reflect.Method. Method.invoke() is diff --git a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.hpp b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.hpp index 7164413c8fa..d348ed2c759 100644 --- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.hpp +++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.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 @@ -421,10 +421,11 @@ class VM_RedefineClasses: public VM_Operation { // and in all direct and indirect subclasses. void increment_class_counter(InstanceKlass *ik, TRAPS); - // Support for constant pool merging (these routines are in alpha - // order): + // Support for constant pool merging (these routines are in alpha order): void append_entry(constantPoolHandle scratch_cp, int scratch_i, constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS); + int find_or_append_indirect_entry(constantPoolHandle scratch_cp, int scratch_i, + constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS); int find_new_index(int old_index); bool is_unresolved_class_mismatch(constantPoolHandle cp1, int index1, constantPoolHandle cp2, int index2); @@ -487,17 +488,4 @@ class VM_RedefineClasses: public VM_Operation { // and redefine implementation static bool is_modifiable_class(oop klass_mirror); }; - - -// Helper class to mark and unmark metadata used on the stack as either handles -// or executing methods, so that it can't be deleted during class redefinition -// and class unloading. -class MetadataOnStackMark : public StackObj { - NOT_PRODUCT(static bool _is_active;) - public: - MetadataOnStackMark() NOT_JVMTI_RETURN; - ~MetadataOnStackMark() NOT_JVMTI_RETURN; - static void record(Metadata* m) NOT_JVMTI_RETURN; -}; - #endif // SHARE_VM_PRIMS_JVMTIREDEFINECLASSES_HPP diff --git a/hotspot/src/share/vm/prims/jvmtiTagMap.cpp b/hotspot/src/share/vm/prims/jvmtiTagMap.cpp index 3dbc70adf62..5d72029d264 100644 --- a/hotspot/src/share/vm/prims/jvmtiTagMap.cpp +++ b/hotspot/src/share/vm/prims/jvmtiTagMap.cpp @@ -45,9 +45,10 @@ #include "runtime/vmThread.hpp" #include "runtime/vm_operations.hpp" #include "services/serviceUtil.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" -#endif +#endif // INCLUDE_ALL_GCS // JvmtiTagHashmapEntry // diff --git a/hotspot/src/share/vm/prims/jvmtiTagMap.hpp b/hotspot/src/share/vm/prims/jvmtiTagMap.hpp index 6435f6251c7..89e3947807d 100644 --- a/hotspot/src/share/vm/prims/jvmtiTagMap.hpp +++ b/hotspot/src/share/vm/prims/jvmtiTagMap.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 @@ -27,14 +27,12 @@ #ifndef SHARE_VM_PRIMS_JVMTITAGMAP_HPP #define SHARE_VM_PRIMS_JVMTITAGMAP_HPP -#ifndef JVMTI_KERNEL #include "gc_interface/collectedHeap.hpp" #include "jvmtifiles/jvmti.h" #include "jvmtifiles/jvmtiEnv.hpp" #include "memory/allocation.hpp" #include "memory/genCollectedHeap.hpp" #include "memory/universe.hpp" -#endif // forward references class JvmtiTagHashmap; diff --git a/hotspot/src/share/vm/prims/nativeLookup.cpp b/hotspot/src/share/vm/prims/nativeLookup.cpp index 5fdd070aaa4..6162ae85032 100644 --- a/hotspot/src/share/vm/prims/nativeLookup.cpp +++ b/hotspot/src/share/vm/prims/nativeLookup.cpp @@ -40,6 +40,7 @@ #include "runtime/javaCalls.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/signature.hpp" +#include "utilities/macros.hpp" #ifdef TARGET_OS_FAMILY_linux # include "os_linux.inline.hpp" #endif diff --git a/hotspot/src/share/vm/prims/unsafe.cpp b/hotspot/src/share/vm/prims/unsafe.cpp index e56277b65d7..18252c15453 100644 --- a/hotspot/src/share/vm/prims/unsafe.cpp +++ b/hotspot/src/share/vm/prims/unsafe.cpp @@ -24,9 +24,10 @@ #include "precompiled.hpp" #include "classfile/vmSymbols.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS #include "memory/allocation.inline.hpp" #include "prims/jni.h" #include "prims/jvm.h" @@ -189,7 +190,7 @@ UNSAFE_ENTRY(jobject, Unsafe_GetObject140(JNIEnv *env, jobject unsafe, jobject o if (obj == NULL) THROW_0(vmSymbols::java_lang_NullPointerException()); GET_OOP_FIELD(obj, offset, v) jobject ret = JNIHandles::make_local(env, v); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // We could be accessing the referent field in a reference // object. If G1 is enabled then we need to register a non-null // referent with the SATB barrier. @@ -212,7 +213,7 @@ UNSAFE_ENTRY(jobject, Unsafe_GetObject140(JNIEnv *env, jobject unsafe, jobject o G1SATBCardTableModRefBS::enqueue(referent); } } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS return ret; UNSAFE_END @@ -247,7 +248,7 @@ UNSAFE_ENTRY(jobject, Unsafe_GetObject(JNIEnv *env, jobject unsafe, jobject obj, UnsafeWrapper("Unsafe_GetObject"); GET_OOP_FIELD(obj, offset, v) jobject ret = JNIHandles::make_local(env, v); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // We could be accessing the referent field in a reference // object. If G1 is enabled then we need to register non-null // referent with the SATB barrier. @@ -270,7 +271,7 @@ UNSAFE_ENTRY(jobject, Unsafe_GetObject(JNIEnv *env, jobject unsafe, jobject obj, G1SATBCardTableModRefBS::enqueue(referent); } } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS return ret; UNSAFE_END diff --git a/hotspot/src/share/vm/prims/whitebox.cpp b/hotspot/src/share/vm/prims/whitebox.cpp index 6c60be19f10..7bbec834e70 100644 --- a/hotspot/src/share/vm/prims/whitebox.cpp +++ b/hotspot/src/share/vm/prims/whitebox.cpp @@ -36,12 +36,17 @@ #include "runtime/interfaceSupport.hpp" #include "runtime/os.hpp" #include "utilities/debug.hpp" +#include "utilities/macros.hpp" -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/concurrentMark.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/heapRegionRemSet.hpp" -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS + +#ifdef INCLUDE_NMT +#include "services/memTracker.hpp" +#endif // INCLUDE_NMT bool WhiteBox::_used = false; @@ -85,7 +90,7 @@ WB_ENTRY(jboolean, WB_IsClassAlive(JNIEnv* env, jobject target, jstring name)) return closure.found(); WB_END -#ifndef SERIALGC +#if INCLUDE_ALL_GCS WB_ENTRY(jboolean, WB_G1IsHumongous(JNIEnv* env, jobject o, jobject obj)) G1CollectedHeap* g1 = G1CollectedHeap::heap(); oop result = JNIHandles::resolve(obj); @@ -108,7 +113,61 @@ WB_END WB_ENTRY(jint, WB_G1RegionSize(JNIEnv* env, jobject o)) return (jint)HeapRegion::GrainBytes; WB_END -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS + +#ifdef INCLUDE_NMT +// Keep track of the 3 allocations in NMTAllocTest so we can free them later +// on and verify that they're not visible anymore +static void* nmtMtTest1 = NULL, *nmtMtTest2 = NULL, *nmtMtTest3 = NULL; + +// Alloc memory using the test memory type so that we can use that to see if +// NMT picks it up correctly +WB_ENTRY(jboolean, WB_NMTAllocTest(JNIEnv* env)) + void *mem; + + if (!MemTracker::is_on() || MemTracker::shutdown_in_progress()) { + return false; + } + + // Allocate 2 * 128k + 256k + 1024k and free the 1024k one to make sure we track + // everything correctly. Total should be 512k held alive. + nmtMtTest1 = os::malloc(128 * 1024, mtTest); + mem = os::malloc(1024 * 1024, mtTest); + nmtMtTest2 = os::malloc(256 * 1024, mtTest); + os::free(mem, mtTest); + nmtMtTest3 = os::malloc(128 * 1024, mtTest); + + return true; +WB_END + +// Free the memory allocated by NMTAllocTest +WB_ENTRY(jboolean, WB_NMTFreeTestMemory(JNIEnv* env)) + + if (nmtMtTest1 == NULL || nmtMtTest2 == NULL || nmtMtTest3 == NULL) { + return false; + } + + os::free(nmtMtTest1, mtTest); + nmtMtTest1 = NULL; + os::free(nmtMtTest2, mtTest); + nmtMtTest2 = NULL; + os::free(nmtMtTest3, mtTest); + nmtMtTest3 = NULL; + + return true; +WB_END + +// Block until the current generation of NMT data to be merged, used to reliably test the NMT feature +WB_ENTRY(jboolean, WB_NMTWaitForDataMerge(JNIEnv* env)) + + if (!MemTracker::is_on() || MemTracker::shutdown_in_progress()) { + return false; + } + + return MemTracker::wbtest_wait_for_data_merge(); +WB_END + +#endif // INCLUDE_NMT //Some convenience methods to deal with objects from java int WhiteBox::offset_for_field(const char* field_name, oop object, @@ -171,12 +230,17 @@ static JNINativeMethod methods[] = { CC "(Ljava/lang/String;[Lsun/hotspot/parser/DiagnosticCommand;)[Ljava/lang/Object;", (void*) &WB_ParseCommandLine }, -#ifndef SERIALGC +#if INCLUDE_ALL_GCS {CC"g1InConcurrentMark", CC"()Z", (void*)&WB_G1InConcurrentMark}, {CC"g1IsHumongous", CC"(Ljava/lang/Object;)Z", (void*)&WB_G1IsHumongous }, {CC"g1NumFreeRegions", CC"()J", (void*)&WB_G1NumFreeRegions }, {CC"g1RegionSize", CC"()I", (void*)&WB_G1RegionSize }, -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS +#ifdef INCLUDE_NMT + {CC"NMTAllocTest", CC"()Z", (void*)&WB_NMTAllocTest }, + {CC"NMTFreeTestMemory", CC"()Z", (void*)&WB_NMTFreeTestMemory }, + {CC"NMTWaitForDataMerge",CC"()Z", (void*)&WB_NMTWaitForDataMerge}, +#endif // INCLUDE_NMT }; #undef CC diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 9b5d7f9122d..de596c1a8ba 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -38,6 +38,7 @@ #include "services/management.hpp" #include "services/memTracker.hpp" #include "utilities/defaultStream.hpp" +#include "utilities/macros.hpp" #include "utilities/taskqueue.hpp" #ifdef TARGET_OS_FAMILY_linux # include "os_linux.inline.hpp" @@ -51,9 +52,9 @@ #ifdef TARGET_OS_FAMILY_bsd # include "os_bsd.inline.hpp" #endif -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp" -#endif +#endif // INCLUDE_ALL_GCS // Note: This is a special bug reporting site for the JVM #define DEFAULT_VENDOR_URL_BUG "http://bugreport.sun.com/bugreport/crash.jsp" @@ -827,7 +828,8 @@ bool Arguments::process_argument(const char* arg, return true; } - const char * const argname = *arg == '+' || *arg == '-' ? arg + 1 : arg; + bool has_plus_minus = (*arg == '+' || *arg == '-'); + const char* const argname = has_plus_minus ? arg + 1 : arg; if (is_newly_obsolete(arg, &since)) { char version[256]; since.to_string(version, sizeof(version)); @@ -838,13 +840,29 @@ bool Arguments::process_argument(const char* arg, // For locked flags, report a custom error message if available. // Otherwise, report the standard unrecognized VM option. - Flag* locked_flag = Flag::find_flag((char*)argname, strlen(argname), true); - if (locked_flag != NULL) { + size_t arg_len; + const char* equal_sign = strchr(argname, '='); + if (equal_sign == NULL) { + arg_len = strlen(argname); + } else { + arg_len = equal_sign - argname; + } + + Flag* found_flag = Flag::find_flag((char*)argname, arg_len, true); + if (found_flag != NULL) { char locked_message_buf[BUFLEN]; - locked_flag->get_locked_message(locked_message_buf, BUFLEN); + found_flag->get_locked_message(locked_message_buf, BUFLEN); if (strlen(locked_message_buf) == 0) { - jio_fprintf(defaultStream::error_stream(), - "Unrecognized VM option '%s'\n", argname); + if (found_flag->is_bool() && !has_plus_minus) { + jio_fprintf(defaultStream::error_stream(), + "Missing +/- setting for VM option '%s'\n", argname); + } else if (!found_flag->is_bool() && has_plus_minus) { + jio_fprintf(defaultStream::error_stream(), + "Unexpected +/- setting in VM option '%s'\n", argname); + } else { + jio_fprintf(defaultStream::error_stream(), + "Improperly specified VM option '%s'\n", argname); + } } else { jio_fprintf(defaultStream::error_stream(), "%s", locked_message_buf); } @@ -1072,7 +1090,7 @@ void Arguments::set_tiered_flags() { } } -#if INCLUDE_ALTERNATE_GCS +#if INCLUDE_ALL_GCS static void disable_adaptive_size_policy(const char* collector_name) { if (UseAdaptiveSizePolicy) { if (FLAG_IS_CMDLINE(UseAdaptiveSizePolicy)) { @@ -1284,7 +1302,7 @@ void Arguments::set_cms_and_parnew_gc_flags() { tty->print_cr("ConcGCThreads: %u", ConcGCThreads); } } -#endif // INCLUDE_ALTERNATE_GCS +#endif // INCLUDE_ALL_GCS void set_object_alignment() { // Object alignment. @@ -1301,10 +1319,10 @@ void set_object_alignment() { // Oop encoding heap max OopEncodingHeapMax = (uint64_t(max_juint) + 1) << LogMinObjAlignmentInBytes; -#if INCLUDE_ALTERNATE_GCS +#if INCLUDE_ALL_GCS // Set CMS global values CompactibleFreeListSpace::set_cms_values(); -#endif // INCLUDE_ALTERNATE_GCS +#endif // INCLUDE_ALL_GCS } bool verify_object_alignment() { @@ -1429,13 +1447,18 @@ void Arguments::set_ergonomics_flags() { } // Set the ClassMetaspaceSize to something that will not need to be // expanded, since it cannot be expanded. - if (UseCompressedKlassPointers && FLAG_IS_DEFAULT(ClassMetaspaceSize)) { - // 100,000 classes seems like a good size, so 100M assumes around 1K - // per klass. The vtable and oopMap is embedded so we don't have a fixed - // size per klass. Eventually, this will be parameterized because it - // would also be useful to determine the optimal size of the - // systemDictionary. - FLAG_SET_ERGO(uintx, ClassMetaspaceSize, 100*M); + if (UseCompressedKlassPointers) { + if (ClassMetaspaceSize > KlassEncodingMetaspaceMax) { + warning("Class metaspace size is too large for UseCompressedKlassPointers"); + FLAG_SET_DEFAULT(UseCompressedKlassPointers, false); + } else if (FLAG_IS_DEFAULT(ClassMetaspaceSize)) { + // 100,000 classes seems like a good size, so 100M assumes around 1K + // per klass. The vtable and oopMap is embedded so we don't have a fixed + // size per klass. Eventually, this will be parameterized because it + // would also be useful to determine the optimal size of the + // systemDictionary. + FLAG_SET_ERGO(uintx, ClassMetaspaceSize, 100*M); + } } } // Also checks that certain machines are slower with compressed oops @@ -1976,7 +1999,7 @@ bool Arguments::check_vm_args_consistency() { status = status && verify_min_value(ParGCArrayScanChunk, 1, "ParGCArrayScanChunk"); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS if (UseG1GC) { status = status && verify_percentage(InitiatingHeapOccupancyPercent, "InitiatingHeapOccupancyPercent"); @@ -1985,7 +2008,7 @@ bool Arguments::check_vm_args_consistency() { status = status && verify_min_value((intx)G1ConcMarkStepDurationMillis, 1, "G1ConcMarkStepDurationMillis"); } -#endif +#endif // INCLUDE_ALL_GCS status = status && verify_interval(RefDiscoveryPolicy, ReferenceProcessor::DiscoveryPolicyMin, @@ -2472,10 +2495,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, // -Xshare:dump } else if (match_option(option, "-Xshare:dump", &tail)) { -#if defined(KERNEL) - vm_exit_during_initialization( - "Dumping a shared archive is not supported on the Kernel JVM.", NULL); -#elif !INCLUDE_CDS +#if !INCLUDE_CDS vm_exit_during_initialization( "Dumping a shared archive is not supported in this VM.", NULL); #else @@ -3157,7 +3177,7 @@ jint Arguments::parse(const JavaVMInitArgs* args) { UNSUPPORTED_OPTION(UseLargePages, "-XX:+UseLargePages"); #endif -#if !INCLUDE_ALTERNATE_GCS +#if !INCLUDE_ALL_GCS if (UseParallelGC) { warning("Parallel GC is not supported in this VM. Using Serial GC."); } @@ -3170,7 +3190,7 @@ jint Arguments::parse(const JavaVMInitArgs* args) { if (UseParNewGC) { warning("Par New GC is not supported in this VM. Using Serial GC."); } -#endif // INCLUDE_ALTERNATE_GCS +#endif // INCLUDE_ALL_GCS #ifndef PRODUCT if (TraceBytecodesAt != 0) { @@ -3217,9 +3237,9 @@ jint Arguments::parse(const JavaVMInitArgs* args) { // Set object alignment values. set_object_alignment(); -#ifdef SERIALGC +#if !INCLUDE_ALL_GCS force_serial_gc(); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS #if !INCLUDE_CDS no_shared_spaces(); #endif // INCLUDE_CDS @@ -3247,7 +3267,7 @@ jint Arguments::parse(const JavaVMInitArgs* args) { // Set heap size based on available physical memory set_heap_size(); -#if INCLUDE_ALTERNATE_GCS +#if INCLUDE_ALL_GCS // Set per-collector flags if (UseParallelGC || UseParallelOldGC) { set_parallel_gc_flags(); @@ -3259,11 +3279,9 @@ jint Arguments::parse(const JavaVMInitArgs* args) { set_g1_gc_flags(); } check_deprecated_gcs(); -#endif // INCLUDE_ALTERNATE_GCS - -#ifdef SERIALGC +#else // INCLUDE_ALL_GCS assert(verify_serial_gc_flags(), "SerialGC unset"); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // Set bytecode rewriting flags set_bytecode_flags(); @@ -3357,7 +3375,7 @@ jint Arguments::parse(const JavaVMInitArgs* args) { } jint Arguments::adjust_after_os() { -#if INCLUDE_ALTERNATE_GCS +#if INCLUDE_ALL_GCS if (UseParallelGC || UseParallelOldGC) { if (UseNUMA) { if (FLAG_IS_DEFAULT(MinHeapDeltaBytes)) { @@ -3368,7 +3386,7 @@ jint Arguments::adjust_after_os() { UseNUMAInterleaving = true; } } -#endif +#endif // INCLUDE_ALL_GCS return JNI_OK; } @@ -3463,36 +3481,6 @@ void Arguments::PropertyList_unique_add(SystemProperty** plist, const char* k, c PropertyList_add(plist, k, v); } -#ifdef KERNEL -char *Arguments::get_kernel_properties() { - // Find properties starting with kernel and append them to string - // We need to find out how long they are first because the URL's that they - // might point to could get long. - int length = 0; - SystemProperty* prop; - for (prop = _system_properties; prop != NULL; prop = prop->next()) { - if (strncmp(prop->key(), "kernel.", 7 ) == 0) { - length += (strlen(prop->key()) + strlen(prop->value()) + 5); // "-D =" - } - } - // Add one for null terminator. - char *props = AllocateHeap(length + 1, mtInternal); - if (length != 0) { - int pos = 0; - for (prop = _system_properties; prop != NULL; prop = prop->next()) { - if (strncmp(prop->key(), "kernel.", 7 ) == 0) { - jio_snprintf(&props[pos], length-pos, - "-D%s=%s ", prop->key(), prop->value()); - pos = strlen(props); - } - } - } - // null terminate props in case of null - props[length] = '\0'; - return props; -} -#endif // KERNEL - // Copies src into buf, replacing "%%" with "%" and "%p" with pid // Returns true if all of the source pointed by src has been copied over to // the destination buffer pointed by buf. Otherwise, returns false. diff --git a/hotspot/src/share/vm/runtime/arguments.hpp b/hotspot/src/share/vm/runtime/arguments.hpp index 71e6e3001e9..c116e2028bb 100644 --- a/hotspot/src/share/vm/runtime/arguments.hpp +++ b/hotspot/src/share/vm/runtime/arguments.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 @@ -540,11 +540,6 @@ class Arguments : AllStatic { // Utility: copies src into buf, replacing "%%" with "%" and "%p" with pid. static bool copy_expand_pid(const char* src, size_t srclen, char* buf, size_t buflen); - -#ifdef KERNEL - // For java kernel vm, return property string for kernel properties. - static char *get_kernel_properties(); -#endif // KERNEL }; #endif // SHARE_VM_RUNTIME_ARGUMENTS_HPP diff --git a/hotspot/src/share/vm/runtime/deoptimization.cpp b/hotspot/src/share/vm/runtime/deoptimization.cpp index 63df5aa5f88..8f735b7d6fb 100644 --- a/hotspot/src/share/vm/runtime/deoptimization.cpp +++ b/hotspot/src/share/vm/runtime/deoptimization.cpp @@ -1559,7 +1559,7 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra if (trap_method() == nm->method()) { make_not_compilable = true; } else { - trap_method->set_not_compilable(CompLevel_full_optimization); + trap_method->set_not_compilable(CompLevel_full_optimization, true, "overflow_recompile_count > PerBytecodeRecompilationCutoff"); // But give grace to the enclosing nm->method(). } } diff --git a/hotspot/src/share/vm/runtime/fprofiler.hpp b/hotspot/src/share/vm/runtime/fprofiler.hpp index c06a505630b..429b32e7f33 100644 --- a/hotspot/src/share/vm/runtime/fprofiler.hpp +++ b/hotspot/src/share/vm/runtime/fprofiler.hpp @@ -25,6 +25,7 @@ #ifndef SHARE_VM_RUNTIME_FPROFILER_HPP #define SHARE_VM_RUNTIME_FPROFILER_HPP +#include "utilities/macros.hpp" #include "runtime/timer.hpp" // a simple flat profiler for Java diff --git a/hotspot/src/share/vm/runtime/globals.cpp b/hotspot/src/share/vm/runtime/globals.cpp index 569a3f4bef8..dd32cb3754c 100644 --- a/hotspot/src/share/vm/runtime/globals.cpp +++ b/hotspot/src/share/vm/runtime/globals.cpp @@ -29,10 +29,11 @@ #include "runtime/globals.hpp" #include "runtime/globals_extension.hpp" #include "utilities/ostream.hpp" +#include "utilities/macros.hpp" #include "utilities/top.hpp" -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1_globals.hpp" -#endif +#endif // INCLUDE_ALL_GCS #ifdef COMPILER1 #include "c1/c1_globals.hpp" #endif @@ -256,9 +257,9 @@ void Flag::print_as_flag(outputStream* st) { static Flag flagTable[] = { RUNTIME_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, RUNTIME_PD_DEVELOP_FLAG_STRUCT, RUNTIME_PRODUCT_FLAG_STRUCT, RUNTIME_PD_PRODUCT_FLAG_STRUCT, RUNTIME_DIAGNOSTIC_FLAG_STRUCT, RUNTIME_EXPERIMENTAL_FLAG_STRUCT, RUNTIME_NOTPRODUCT_FLAG_STRUCT, RUNTIME_MANAGEABLE_FLAG_STRUCT, RUNTIME_PRODUCT_RW_FLAG_STRUCT, RUNTIME_LP64_PRODUCT_FLAG_STRUCT) RUNTIME_OS_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, RUNTIME_PD_DEVELOP_FLAG_STRUCT, RUNTIME_PRODUCT_FLAG_STRUCT, RUNTIME_PD_PRODUCT_FLAG_STRUCT, RUNTIME_DIAGNOSTIC_FLAG_STRUCT, RUNTIME_NOTPRODUCT_FLAG_STRUCT) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS G1_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, RUNTIME_PD_DEVELOP_FLAG_STRUCT, RUNTIME_PRODUCT_FLAG_STRUCT, RUNTIME_PD_PRODUCT_FLAG_STRUCT, RUNTIME_DIAGNOSTIC_FLAG_STRUCT, RUNTIME_EXPERIMENTAL_FLAG_STRUCT, RUNTIME_NOTPRODUCT_FLAG_STRUCT, RUNTIME_MANAGEABLE_FLAG_STRUCT, RUNTIME_PRODUCT_RW_FLAG_STRUCT) -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS #ifdef COMPILER1 C1_FLAGS(C1_DEVELOP_FLAG_STRUCT, C1_PD_DEVELOP_FLAG_STRUCT, C1_PRODUCT_FLAG_STRUCT, C1_PD_PRODUCT_FLAG_STRUCT, C1_NOTPRODUCT_FLAG_STRUCT) #endif diff --git a/hotspot/src/share/vm/runtime/globals_extension.hpp b/hotspot/src/share/vm/runtime/globals_extension.hpp index 4d8666821a3..00d06fe276c 100644 --- a/hotspot/src/share/vm/runtime/globals_extension.hpp +++ b/hotspot/src/share/vm/runtime/globals_extension.hpp @@ -26,6 +26,7 @@ #define SHARE_VM_RUNTIME_GLOBALS_EXTENSION_HPP #include "runtime/globals.hpp" +#include "utilities/macros.hpp" #include "utilities/top.hpp" // Construct enum of Flag_ constants. @@ -94,9 +95,9 @@ typedef enum { RUNTIME_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER, RUNTIME_PD_DEVELOP_FLAG_MEMBER, RUNTIME_PRODUCT_FLAG_MEMBER, RUNTIME_PD_PRODUCT_FLAG_MEMBER, RUNTIME_DIAGNOSTIC_FLAG_MEMBER, RUNTIME_EXPERIMENTAL_FLAG_MEMBER, RUNTIME_NOTPRODUCT_FLAG_MEMBER, RUNTIME_MANAGEABLE_FLAG_MEMBER, RUNTIME_PRODUCT_RW_FLAG_MEMBER, RUNTIME_LP64_PRODUCT_FLAG_MEMBER) RUNTIME_OS_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER, RUNTIME_PD_DEVELOP_FLAG_MEMBER, RUNTIME_PRODUCT_FLAG_MEMBER, RUNTIME_PD_PRODUCT_FLAG_MEMBER, RUNTIME_DIAGNOSTIC_FLAG_MEMBER, RUNTIME_NOTPRODUCT_FLAG_MEMBER) -#if INCLUDE_ALTERNATE_GCS +#if INCLUDE_ALL_GCS G1_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER, RUNTIME_PD_DEVELOP_FLAG_MEMBER, RUNTIME_PRODUCT_FLAG_MEMBER, RUNTIME_PD_PRODUCT_FLAG_MEMBER, RUNTIME_DIAGNOSTIC_FLAG_MEMBER, RUNTIME_EXPERIMENTAL_FLAG_MEMBER, RUNTIME_NOTPRODUCT_FLAG_MEMBER, RUNTIME_MANAGEABLE_FLAG_MEMBER, RUNTIME_PRODUCT_RW_FLAG_MEMBER) -#endif // INCLUDE_ALTERNATE_GCS +#endif // INCLUDE_ALL_GCS #ifdef COMPILER1 C1_FLAGS(C1_DEVELOP_FLAG_MEMBER, C1_PD_DEVELOP_FLAG_MEMBER, C1_PRODUCT_FLAG_MEMBER, C1_PD_PRODUCT_FLAG_MEMBER, C1_NOTPRODUCT_FLAG_MEMBER) #endif @@ -187,7 +188,7 @@ typedef enum { RUNTIME_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE, RUNTIME_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE, RUNTIME_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE) -#if INCLUDE_ALTERNATE_GCS +#if INCLUDE_ALL_GCS G1_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER_WITH_TYPE, RUNTIME_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE, RUNTIME_PRODUCT_FLAG_MEMBER_WITH_TYPE, @@ -197,7 +198,7 @@ typedef enum { RUNTIME_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE, RUNTIME_MANAGEABLE_FLAG_MEMBER_WITH_TYPE, RUNTIME_PRODUCT_RW_FLAG_MEMBER_WITH_TYPE) -#endif // INCLUDE_ALTERNATE_GCS +#endif // INCLUDE_ALL_GCS #ifdef COMPILER1 C1_FLAGS(C1_DEVELOP_FLAG_MEMBER_WITH_TYPE, C1_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE, diff --git a/hotspot/src/share/vm/runtime/init.cpp b/hotspot/src/share/vm/runtime/init.cpp index 541cb08676f..7ef17204bb2 100644 --- a/hotspot/src/share/vm/runtime/init.cpp +++ b/hotspot/src/share/vm/runtime/init.cpp @@ -34,6 +34,7 @@ #include "runtime/init.hpp" #include "runtime/safepoint.hpp" #include "runtime/sharedRuntime.hpp" +#include "utilities/macros.hpp" // Initialization done by VM thread in vm_init_globals() void check_ThreadShadow(); diff --git a/hotspot/src/share/vm/runtime/java.cpp b/hotspot/src/share/vm/runtime/java.cpp index fd9050d9cb1..f9be22344b1 100644 --- a/hotspot/src/share/vm/runtime/java.cpp +++ b/hotspot/src/share/vm/runtime/java.cpp @@ -64,6 +64,7 @@ #include "utilities/dtrace.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/histogram.hpp" +#include "utilities/macros.hpp" #include "utilities/vmError.hpp" #ifdef TARGET_ARCH_x86 # include "vm_version_x86.hpp" @@ -80,11 +81,11 @@ #ifdef TARGET_ARCH_ppc # include "vm_version_ppc.hpp" #endif -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp" #include "gc_implementation/parallelScavenge/psScavenge.hpp" #include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" -#endif +#endif // INCLUDE_ALL_GCS #ifdef COMPILER1 #include "c1/c1_Compiler.hpp" #include "c1/c1_Runtime1.hpp" diff --git a/hotspot/src/share/vm/runtime/os.cpp b/hotspot/src/share/vm/runtime/os.cpp index 649ce4fcc5c..b4090680395 100644 --- a/hotspot/src/share/vm/runtime/os.cpp +++ b/hotspot/src/share/vm/runtime/os.cpp @@ -985,15 +985,28 @@ void os::print_location(outputStream* st, intptr_t x, bool verbose) { // if C stack is walkable beyond current frame. The check for fp() is not // necessary on Sparc, but it's harmless. bool os::is_first_C_frame(frame* fr) { -#ifdef IA64 - // In order to walk native frames on Itanium, we need to access the unwind - // table, which is inside ELF. We don't want to parse ELF after fatal error, - // so return true for IA64. If we need to support C stack walking on IA64, - // this function needs to be moved to CPU specific files, as fp() on IA64 - // is register stack, which grows towards higher memory address. +#if defined(IA64) && !defined(_WIN32) + // On IA64 we have to check if the callers bsp is still valid + // (i.e. within the register stack bounds). + // Notice: this only works for threads created by the VM and only if + // we walk the current stack!!! If we want to be able to walk + // arbitrary other threads, we'll have to somehow store the thread + // object in the frame. + Thread *thread = Thread::current(); + if ((address)fr->fp() <= + thread->register_stack_base() HPUX_ONLY(+ 0x0) LINUX_ONLY(+ 0x50)) { + // This check is a little hacky, because on Linux the first C + // frame's ('start_thread') register stack frame starts at + // "register_stack_base + 0x48" while on HPUX, the first C frame's + // ('__pthread_bound_body') register stack frame seems to really + // start at "register_stack_base". + return true; + } else { + return false; + } +#elif defined(IA64) && defined(_WIN32) return true; -#endif - +#else // Load up sp, fp, sender sp and sender fp, check for reasonable values. // Check usp first, because if that's bad the other accessors may fault // on some architectures. Ditto ufp second, etc. @@ -1023,6 +1036,7 @@ bool os::is_first_C_frame(frame* fr) { if (old_fp - ufp > 64 * K) return true; return false; +#endif } #ifdef ASSERT diff --git a/hotspot/src/share/vm/runtime/safepoint.cpp b/hotspot/src/share/vm/runtime/safepoint.cpp index bf2d38c20e8..37ee19a8fbe 100644 --- a/hotspot/src/share/vm/runtime/safepoint.cpp +++ b/hotspot/src/share/vm/runtime/safepoint.cpp @@ -52,6 +52,7 @@ #include "services/memTracker.hpp" #include "services/runtimeService.hpp" #include "utilities/events.hpp" +#include "utilities/macros.hpp" #ifdef TARGET_ARCH_x86 # include "nativeInst_x86.hpp" # include "vmreg_x86.inline.hpp" @@ -72,10 +73,10 @@ # include "nativeInst_ppc.hpp" # include "vmreg_ppc.inline.hpp" #endif -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp" #include "gc_implementation/shared/concurrentGCThread.hpp" -#endif +#endif // INCLUDE_ALL_GCS #ifdef COMPILER1 #include "c1/c1_globals.hpp" #endif @@ -103,7 +104,7 @@ void SafepointSynchronize::begin() { _ts_of_current_safepoint = tty->time_stamp().seconds(); } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS if (UseConcMarkSweepGC) { // In the future we should investigate whether CMS can use the // more-general mechanism below. DLD (01/05). @@ -111,7 +112,7 @@ void SafepointSynchronize::begin() { } else if (UseG1GC) { ConcurrentGCThread::safepoint_synchronize(); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // By getting the Threads_lock, we assure that no threads are about to start or // exit. It is released again in SafepointSynchronize::end(). @@ -480,14 +481,14 @@ void SafepointSynchronize::end() { Threads_lock->unlock(); } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // If there are any concurrent GC threads resume them. if (UseConcMarkSweepGC) { ConcurrentMarkSweepThread::desynchronize(false); } else if (UseG1GC) { ConcurrentGCThread::safepoint_desynchronize(); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // record this time so VMThread can keep track how much time has elasped // since last safepoint. _end_of_last_safepoint = os::javaTimeMillis(); diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.cpp b/hotspot/src/share/vm/runtime/sharedRuntime.cpp index 7d2b816fe63..09a0b65b958 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp +++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp @@ -56,6 +56,7 @@ #include "utilities/dtrace.hpp" #include "utilities/events.hpp" #include "utilities/hashtable.inline.hpp" +#include "utilities/macros.hpp" #include "utilities/xmlstream.hpp" #ifdef TARGET_ARCH_x86 # include "nativeInst_x86.hpp" @@ -212,7 +213,7 @@ void SharedRuntime::print_ic_miss_histogram() { } #endif // PRODUCT -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // G1 write-barrier pre: executed before a pointer store. JRT_LEAF(void, SharedRuntime::g1_wb_pre(oopDesc* orig, JavaThread *thread)) @@ -230,7 +231,7 @@ JRT_LEAF(void, SharedRuntime::g1_wb_post(void* card_addr, JavaThread* thread)) thread->dirty_card_queue().enqueue(card_addr); JRT_END -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS JRT_LEAF(jlong, SharedRuntime::lmul(jlong y, jlong x)) @@ -2816,10 +2817,6 @@ VMRegPair *SharedRuntime::find_callee_arguments(Symbol* sig, bool has_receiver, JRT_LEAF(intptr_t*, SharedRuntime::OSR_migration_begin( JavaThread *thread) ) -#ifdef IA64 - ShouldNotReachHere(); // NYI -#endif /* IA64 */ - // // This code is dependent on the memory layout of the interpreter local // array and the monitors. On all of our platforms the layout is identical diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.hpp b/hotspot/src/share/vm/runtime/sharedRuntime.hpp index 54448890e0b..e6867645ae6 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntime.hpp +++ b/hotspot/src/share/vm/runtime/sharedRuntime.hpp @@ -32,6 +32,7 @@ #include "memory/resourceArea.hpp" #include "runtime/threadLocalStorage.hpp" #include "utilities/hashtable.hpp" +#include "utilities/macros.hpp" class AdapterHandlerEntry; class AdapterHandlerTable; @@ -168,11 +169,11 @@ class SharedRuntime: AllStatic { static address raw_exception_handler_for_return_address(JavaThread* thread, address return_address); static address exception_handler_for_return_address(JavaThread* thread, address return_address); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // G1 write barriers static void g1_wb_pre(oopDesc* orig, JavaThread *thread); static void g1_wb_post(void* card_addr, JavaThread* thread); -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS // exception handling and implicit exceptions static address compute_compiled_exc_handler(nmethod* nm, address ret_pc, Handle& exception, diff --git a/hotspot/src/share/vm/runtime/synchronizer.cpp b/hotspot/src/share/vm/runtime/synchronizer.cpp index 667066e7f17..bdf416275dc 100644 --- a/hotspot/src/share/vm/runtime/synchronizer.cpp +++ b/hotspot/src/share/vm/runtime/synchronizer.cpp @@ -53,7 +53,7 @@ # include "os_bsd.inline.hpp" #endif -#if defined(__GNUC__) && !defined(IA64) +#if defined(__GNUC__) // Need to inhibit inlining for older versions of GCC to avoid build-time failures #define ATTR __attribute__((noinline)) #else diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index ff6adde6eee..e0cf75b03f2 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.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 @@ -82,6 +82,7 @@ #include "utilities/dtrace.hpp" #include "utilities/events.hpp" #include "utilities/preserveException.hpp" +#include "utilities/macros.hpp" #ifdef TARGET_OS_FAMILY_linux # include "os_linux.inline.hpp" #endif @@ -94,11 +95,11 @@ #ifdef TARGET_OS_FAMILY_bsd # include "os_bsd.inline.hpp" #endif -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp" #include "gc_implementation/g1/concurrentMarkThread.inline.hpp" #include "gc_implementation/parallelScavenge/pcTasks.hpp" -#endif +#endif // INCLUDE_ALL_GCS #ifdef COMPILER1 #include "c1/c1_Compiler.hpp" #endif @@ -1482,17 +1483,17 @@ void JavaThread::initialize() { pd_initialize(); } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS SATBMarkQueueSet JavaThread::_satb_mark_queue_set; DirtyCardQueueSet JavaThread::_dirty_card_queue_set; -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS JavaThread::JavaThread(bool is_attaching_via_jni) : Thread() -#ifndef SERIALGC +#if INCLUDE_ALL_GCS , _satb_mark_queue(&_satb_mark_queue_set), _dirty_card_queue(&_dirty_card_queue_set) -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS { initialize(); if (is_attaching_via_jni) { @@ -1500,7 +1501,7 @@ JavaThread::JavaThread(bool is_attaching_via_jni) : } else { _jni_attach_state = _not_attaching_via_jni; } - assert(_deferred_card_mark.is_empty(), "Default MemRegion ctor"); + assert(deferred_card_mark().is_empty(), "Default MemRegion ctor"); _safepoint_visible = false; } @@ -1547,10 +1548,10 @@ static void compiler_thread_entry(JavaThread* thread, TRAPS); JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) : Thread() -#ifndef SERIALGC +#if INCLUDE_ALL_GCS , _satb_mark_queue(&_satb_mark_queue_set), _dirty_card_queue(&_dirty_card_queue_set) -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS { if (TraceThreadEvents) { tty->print_cr("creating thread %p", this); @@ -1896,19 +1897,26 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) { JvmtiExport::cleanup_thread(this); } -#ifndef SERIALGC - // We must flush G1-related buffers before removing a thread from + // We must flush any deferred card marks before removing a thread from // the list of active threads. + Universe::heap()->flush_deferred_store_barrier(this); + assert(deferred_card_mark().is_empty(), "Should have been flushed"); + +#if INCLUDE_ALL_GCS + // We must flush the G1-related buffers before removing a thread + // from the list of active threads. We must do this after any deferred + // card marks have been flushed (above) so that any entries that are + // added to the thread's dirty card queue as a result are not lost. if (UseG1GC) { flush_barrier_queues(); } -#endif +#endif // INCLUDE_ALL_GCS // Remove from list of active threads list, and notify VM thread if we are the last non-daemon thread Threads::remove(this); } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Flush G1-related queues. void JavaThread::flush_barrier_queues() { satb_mark_queue().flush(); @@ -1936,7 +1944,7 @@ void JavaThread::initialize_queues() { // active field set to true. assert(dirty_queue.is_active(), "dirty card queue should be active"); } -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS void JavaThread::cleanup_failed_attach_current_thread() { if (get_thread_profiler() != NULL) { @@ -1964,11 +1972,11 @@ void JavaThread::cleanup_failed_attach_current_thread() { tlab().make_parsable(true); // retire TLAB, if any } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS if (UseG1GC) { flush_barrier_queues(); } -#endif +#endif // INCLUDE_ALL_GCS Threads::remove(this); delete this; @@ -3600,7 +3608,7 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { vm_exit_during_initialization(Handle(THREAD, PENDING_EXCEPTION)); } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Support for ConcurrentMarkSweep. This should be cleaned up // and better encapsulated. The ugly nested if test would go away // once things are properly refactored. XXX YSR @@ -3614,7 +3622,7 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { vm_exit_during_initialization(Handle(THREAD, PENDING_EXCEPTION)); } } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // Always call even when there are not JVMTI environments yet, since environments // may be attached late and JVMTI must track phases of VM execution @@ -3739,28 +3747,6 @@ static OnLoadEntry_t lookup_on_load(AgentLibrary* agent, const char *on_load_sym name)) { library = os::dll_load(buffer, ebuf, sizeof ebuf); } -#ifdef KERNEL - // Download instrument dll - if (library == NULL && strcmp(name, "instrument") == 0) { - char *props = Arguments::get_kernel_properties(); - char *home = Arguments::get_java_home(); - const char *fmt = "%s/bin/java %s -Dkernel.background.download=false" - " sun.jkernel.DownloadManager -download client_jvm"; - size_t length = strlen(props) + strlen(home) + strlen(fmt) + 1; - char *cmd = NEW_C_HEAP_ARRAY(char, length, mtThread); - jio_snprintf(cmd, length, fmt, home, props); - int status = os::fork_and_exec(cmd); - FreeHeap(props); - if (status == -1) { - warning(cmd); - vm_exit_during_initialization("fork_and_exec failed: %s", - strerror(errno)); - } - FREE_C_HEAP_ARRAY(char, cmd, mtThread); - // when this comes back the instrument.dll should be where it belongs. - library = os::dll_load(buffer, ebuf, sizeof ebuf); - } -#endif // KERNEL if (library == NULL) { // Try the local directory char ns[1] = {0}; if (os::dll_build_name(buffer, sizeof(buffer), ns, name)) { @@ -4209,7 +4195,7 @@ void Threads::possibly_parallel_oops_do(OopClosure* f, CLDToOopClosure* cld_f, C } } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Used by ParallelScavenge void Threads::create_thread_roots_tasks(GCTaskQueue* q) { ALL_JAVA_THREADS(p) { @@ -4225,7 +4211,7 @@ void Threads::create_thread_roots_marking_tasks(GCTaskQueue* q) { } q->enqueue(new ThreadRootsMarkingTask(VMThread::vm_thread())); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS void Threads::nmethods_do(CodeBlobClosure* cf) { ALL_JAVA_THREADS(p) { @@ -4333,13 +4319,13 @@ void Threads::print_on(outputStream* st, bool print_stacks, bool internal_format ); st->cr(); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Dump concurrent locks ConcurrentLocksDump concurrent_locks; if (print_concurrent_locks) { concurrent_locks.dump_at_safepoint(); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS ALL_JAVA_THREADS(p) { ResourceMark rm; @@ -4352,11 +4338,11 @@ void Threads::print_on(outputStream* st, bool print_stacks, bool internal_format } } st->cr(); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS if (print_concurrent_locks) { concurrent_locks.print_locks_on(p, st); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS } VMThread::vm_thread()->print_on(st); diff --git a/hotspot/src/share/vm/runtime/thread.hpp b/hotspot/src/share/vm/runtime/thread.hpp index 627000c7233..98f8d254545 100644 --- a/hotspot/src/share/vm/runtime/thread.hpp +++ b/hotspot/src/share/vm/runtime/thread.hpp @@ -41,6 +41,7 @@ #include "runtime/stubRoutines.hpp" #include "runtime/threadLocalStorage.hpp" #include "runtime/unhandledOops.hpp" +#include "utilities/macros.hpp" #if INCLUDE_NMT #include "services/memRecorder.hpp" @@ -49,10 +50,10 @@ #include "trace/tracing.hpp" #include "utilities/exceptions.hpp" #include "utilities/top.hpp" -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/dirtyCardQueue.hpp" #include "gc_implementation/g1/satbQueue.hpp" -#endif +#endif // INCLUDE_ALL_GCS #ifdef ZERO #ifdef TARGET_ARCH_zero # include "stack_zero.hpp" @@ -929,7 +930,7 @@ class JavaThread: public Thread { } _jmp_ring[ jump_ring_buffer_size ]; #endif /* PRODUCT */ -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Support for G1 barriers ObjPtrQueue _satb_mark_queue; // Thread-local log for SATB barrier. @@ -941,7 +942,7 @@ class JavaThread: public Thread { static DirtyCardQueueSet _dirty_card_queue_set; void flush_barrier_queues(); -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS friend class VMThread; friend class ThreadWaitTransition; @@ -1345,10 +1346,10 @@ class JavaThread: public Thread { return byte_offset_of(JavaThread, _should_post_on_exceptions_flag); } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS static ByteSize satb_mark_queue_offset() { return byte_offset_of(JavaThread, _satb_mark_queue); } static ByteSize dirty_card_queue_offset() { return byte_offset_of(JavaThread, _dirty_card_queue); } -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS // Returns the jni environment for this thread JNIEnv* jni_environment() { return &_jni_environment; } @@ -1637,7 +1638,7 @@ public: _stack_size_at_create = value; } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // SATB marking queue support ObjPtrQueue& satb_mark_queue() { return _satb_mark_queue; } static SATBMarkQueueSet& satb_mark_queue_set() { @@ -1649,7 +1650,7 @@ public: static DirtyCardQueueSet& dirty_card_queue_set() { return _dirty_card_queue_set; } -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS // This method initializes the SATB and dirty card queues before a // JavaThread is added to the Java thread list. Right now, we don't @@ -1668,11 +1669,11 @@ public: // might happen between the JavaThread constructor being called and the // thread being added to the Java thread list (an example of this is // when the structure for the DestroyJavaVM thread is created). -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void initialize_queues(); -#else // !SERIALGC +#else // INCLUDE_ALL_GCS void initialize_queues() { } -#endif // !SERIALGC +#endif // INCLUDE_ALL_GCS // Machine dependent stuff #ifdef TARGET_OS_ARCH_linux_x86 diff --git a/hotspot/src/share/vm/runtime/vframeArray.cpp b/hotspot/src/share/vm/runtime/vframeArray.cpp index 2c9aa0f3adb..d00e9f00954 100644 --- a/hotspot/src/share/vm/runtime/vframeArray.cpp +++ b/hotspot/src/share/vm/runtime/vframeArray.cpp @@ -233,8 +233,6 @@ void vframeArrayElement::unpack_on_stack(int caller_actual_parameters, // Force early return from top frame after deoptimization #ifndef CC_INTERP pc = Interpreter::remove_activation_early_entry(state->earlyret_tos()); -#else - // TBD: Need to implement ForceEarlyReturn for CC_INTERP (ia64) #endif } else { // Possibly override the previous pc computation of the top (youngest) frame diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index a1fe3f2aa63..86169fcfc34 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -101,6 +101,7 @@ #include "utilities/array.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/hashtable.hpp" +#include "utilities/macros.hpp" #ifdef TARGET_ARCH_x86 # include "vmStructs_x86.hpp" #endif @@ -146,7 +147,7 @@ #ifdef TARGET_OS_ARCH_bsd_zero # include "vmStructs_bsd_zero.hpp" #endif -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp" #include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp" #include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp" @@ -161,7 +162,7 @@ #include "gc_implementation/parallelScavenge/psYoungGen.hpp" #include "gc_implementation/parallelScavenge/vmStructs_parallelgc.hpp" #include "gc_implementation/g1/vmStructs_g1.hpp" -#endif +#endif // INCLUDE_ALL_GCS #ifdef COMPILER2 #include "opto/addnode.hpp" #include "opto/block.hpp" @@ -1161,6 +1162,7 @@ typedef BinaryTreeDictionary MetablockTreeDictionary; static_field(Abstract_VM_Version, _vm_major_version, int) \ static_field(Abstract_VM_Version, _vm_minor_version, int) \ static_field(Abstract_VM_Version, _vm_build_number, int) \ + static_field(Abstract_VM_Version, _reserve_for_allocation_prefetch, int) \ \ static_field(JDK_Version, _current, JDK_Version) \ nonstatic_field(JDK_Version, _partially_initialized, bool) \ @@ -2087,8 +2089,7 @@ typedef BinaryTreeDictionary MetablockTreeDictionary; declare_toplevel_type(FreeBlockDictionary*) \ declare_toplevel_type(FreeList*) \ declare_toplevel_type(FreeList) \ - declare_toplevel_type(MetablockTreeDictionary*) \ - declare_type(MetablockTreeDictionary, FreeBlockDictionary) + declare_type(MetablockTreeDictionary, FreeBlockDictionary) //-------------------------------------------------------------------------------- @@ -2786,7 +2787,7 @@ VMStructEntry VMStructs::localHotSpotVMStructs[] = { GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY, GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS VM_STRUCTS_PARALLELGC(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_STATIC_VM_STRUCT_ENTRY) @@ -2796,7 +2797,7 @@ VMStructEntry VMStructs::localHotSpotVMStructs[] = { VM_STRUCTS_G1(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_STATIC_VM_STRUCT_ENTRY) -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS VM_STRUCTS_CPU(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_STATIC_VM_STRUCT_ENTRY, @@ -2830,7 +2831,7 @@ VMTypeEntry VMStructs::localHotSpotVMTypes[] = { GENERATE_C2_VM_TYPE_ENTRY, GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS VM_TYPES_PARALLELGC(GENERATE_VM_TYPE_ENTRY, GENERATE_TOPLEVEL_VM_TYPE_ENTRY) @@ -2841,7 +2842,7 @@ VMTypeEntry VMStructs::localHotSpotVMTypes[] = { VM_TYPES_G1(GENERATE_VM_TYPE_ENTRY, GENERATE_TOPLEVEL_VM_TYPE_ENTRY) -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS VM_TYPES_CPU(GENERATE_VM_TYPE_ENTRY, GENERATE_TOPLEVEL_VM_TYPE_ENTRY, @@ -2872,11 +2873,11 @@ VMIntConstantEntry VMStructs::localHotSpotVMIntConstants[] = { GENERATE_C2_VM_INT_CONSTANT_ENTRY, GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) -#ifndef SERIALGC +#if INCLUDE_ALL_GCS VM_INT_CONSTANTS_CMS(GENERATE_VM_INT_CONSTANT_ENTRY) VM_INT_CONSTANTS_PARNEW(GENERATE_VM_INT_CONSTANT_ENTRY) -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS VM_INT_CONSTANTS_CPU(GENERATE_VM_INT_CONSTANT_ENTRY, GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY, @@ -2930,7 +2931,7 @@ VMStructs::init() { CHECK_NO_OP, CHECK_NO_OP); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS VM_STRUCTS_PARALLELGC(CHECK_NONSTATIC_VM_STRUCT_ENTRY, CHECK_STATIC_VM_STRUCT_ENTRY); @@ -2940,7 +2941,7 @@ VMStructs::init() { VM_STRUCTS_G1(CHECK_NONSTATIC_VM_STRUCT_ENTRY, CHECK_STATIC_VM_STRUCT_ENTRY); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS VM_STRUCTS_CPU(CHECK_NONSTATIC_VM_STRUCT_ENTRY, CHECK_STATIC_VM_STRUCT_ENTRY, @@ -2969,7 +2970,7 @@ VMStructs::init() { CHECK_C2_VM_TYPE_ENTRY, CHECK_C2_TOPLEVEL_VM_TYPE_ENTRY); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS VM_TYPES_PARALLELGC(CHECK_VM_TYPE_ENTRY, CHECK_SINGLE_ARG_VM_TYPE_NO_OP); @@ -2980,7 +2981,7 @@ VMStructs::init() { VM_TYPES_G1(CHECK_VM_TYPE_ENTRY, CHECK_SINGLE_ARG_VM_TYPE_NO_OP); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS VM_TYPES_CPU(CHECK_VM_TYPE_ENTRY, CHECK_SINGLE_ARG_VM_TYPE_NO_OP, @@ -3035,7 +3036,7 @@ VMStructs::init() { ENSURE_C2_FIELD_TYPE_PRESENT, CHECK_NO_OP, CHECK_NO_OP)); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS debug_only(VM_STRUCTS_PARALLELGC(ENSURE_FIELD_TYPE_PRESENT, ENSURE_FIELD_TYPE_PRESENT)); debug_only(VM_STRUCTS_CMS(ENSURE_FIELD_TYPE_PRESENT, @@ -3043,7 +3044,7 @@ VMStructs::init() { ENSURE_FIELD_TYPE_PRESENT)); debug_only(VM_STRUCTS_G1(ENSURE_FIELD_TYPE_PRESENT, ENSURE_FIELD_TYPE_PRESENT)); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS debug_only(VM_STRUCTS_CPU(ENSURE_FIELD_TYPE_PRESENT, ENSURE_FIELD_TYPE_PRESENT, CHECK_NO_OP, diff --git a/hotspot/src/share/vm/runtime/vmStructs.hpp b/hotspot/src/share/vm/runtime/vmStructs.hpp index b1070a406e2..5c4c93a1f77 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.hpp +++ b/hotspot/src/share/vm/runtime/vmStructs.hpp @@ -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 @@ -25,9 +25,7 @@ #ifndef SHARE_VM_RUNTIME_VMSTRUCTS_HPP #define SHARE_VM_RUNTIME_VMSTRUCTS_HPP -#ifndef VM_STRUCTS_KERNEL #include "utilities/debug.hpp" -#endif #ifdef COMPILER1 #include "c1/c1_Runtime1.hpp" #endif diff --git a/hotspot/src/share/vm/runtime/vm_version.cpp b/hotspot/src/share/vm/runtime/vm_version.cpp index 2d105a97baf..ef03c76f62b 100644 --- a/hotspot/src/share/vm/runtime/vm_version.cpp +++ b/hotspot/src/share/vm/runtime/vm_version.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 @@ -111,9 +111,6 @@ void Abstract_VM_Version::initialize() { #endif #ifndef VMTYPE - #ifdef KERNEL - #define VMTYPE "Kernel" - #else // KERNEL #ifdef TIERED #define VMTYPE "Server" #else // TIERED @@ -128,7 +125,6 @@ void Abstract_VM_Version::initialize() { COMPILER2_PRESENT("Server") #endif // ZERO #endif // TIERED - #endif // KERNEL #endif #ifndef HOTSPOT_VM_DISTRO diff --git a/hotspot/src/share/vm/services/attachListener.cpp b/hotspot/src/share/vm/services/attachListener.cpp index 80dfd7effd4..da93859bb94 100644 --- a/hotspot/src/share/vm/services/attachListener.cpp +++ b/hotspot/src/share/vm/services/attachListener.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 @@ -170,7 +170,6 @@ static jint jcmd(AttachOperation* op, outputStream* out) { return JNI_OK; } -#ifndef SERVICES_KERNEL // Heap dumping not supported // Implementation of "dumpheap" command. // See also: HeapDumpDCmd class // @@ -212,7 +211,6 @@ jint dump_heap(AttachOperation* op, outputStream* out) { } return JNI_OK; } -#endif // SERVICES_KERNEL // Implementation of "inspectheap" command // See also: ClassHistogramDCmd class @@ -382,9 +380,7 @@ static jint print_flag(AttachOperation* op, outputStream* out) { static AttachOperationFunctionInfo funcs[] = { { "agentProperties", get_agent_properties }, { "datadump", data_dump }, -#ifndef SERVICES_KERNEL { "dumpheap", dump_heap }, -#endif // SERVICES_KERNEL { "load", JvmtiExport::load_agent_library }, { "properties", get_system_properties }, { "threaddump", thread_dump }, diff --git a/hotspot/src/share/vm/services/attachListener.hpp b/hotspot/src/share/vm/services/attachListener.hpp index 1916e8cacb8..2e7cff39537 100644 --- a/hotspot/src/share/vm/services/attachListener.hpp +++ b/hotspot/src/share/vm/services/attachListener.hpp @@ -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 @@ -28,6 +28,7 @@ #include "memory/allocation.hpp" #include "utilities/debug.hpp" #include "utilities/ostream.hpp" +#include "utilities/macros.hpp" // The AttachListener thread services a queue of operations that are enqueued // by client tools. Each operation is identified by a name and has up to 3 @@ -38,8 +39,6 @@ // complets the result value and any result data is returned to the client // tool. -#ifndef SERVICES_KERNEL - class AttachOperation; typedef jint (*AttachOperationFunction)(AttachOperation* op, outputStream* out); @@ -48,7 +47,6 @@ struct AttachOperationFunctionInfo { const char* name; AttachOperationFunction func; }; -#endif // SERVICES_KERNEL class AttachListener: AllStatic { public: diff --git a/hotspot/src/share/vm/services/classLoadingService.cpp b/hotspot/src/share/vm/services/classLoadingService.cpp index 04dfca89211..b06890808ab 100644 --- a/hotspot/src/share/vm/services/classLoadingService.cpp +++ b/hotspot/src/share/vm/services/classLoadingService.cpp @@ -31,6 +31,7 @@ #include "services/classLoadingService.hpp" #include "services/memoryService.hpp" #include "utilities/dtrace.hpp" +#include "utilities/macros.hpp" #ifdef DTRACE_ENABLED diff --git a/hotspot/src/share/vm/services/classLoadingService.hpp b/hotspot/src/share/vm/services/classLoadingService.hpp index 1ea177f8352..a7f2c4c254a 100644 --- a/hotspot/src/share/vm/services/classLoadingService.hpp +++ b/hotspot/src/share/vm/services/classLoadingService.hpp @@ -28,6 +28,7 @@ #include "runtime/handles.hpp" #include "runtime/perfData.hpp" #include "utilities/growableArray.hpp" +#include "utilities/macros.hpp" class InstanceKlass; diff --git a/hotspot/src/share/vm/services/diagnosticCommand.cpp b/hotspot/src/share/vm/services/diagnosticCommand.cpp index 52a098a2613..5499d9ad2fe 100644 --- a/hotspot/src/share/vm/services/diagnosticCommand.cpp +++ b/hotspot/src/share/vm/services/diagnosticCommand.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 @@ -30,6 +30,7 @@ #include "services/diagnosticFramework.hpp" #include "services/heapDumper.hpp" #include "services/management.hpp" +#include "utilities/macros.hpp" void DCmdRegistrant::register_dcmds(){ // Registration of the diagnostic commands @@ -43,12 +44,12 @@ void DCmdRegistrant::register_dcmds(){ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(true, false)); -#if INCLUDE_SERVICES // Heap dumping supported +#if INCLUDE_SERVICES // Heap dumping/inspection supported DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(true, false)); -#endif // INCLUDE_SERVICES DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(true, false)); +#endif // INCLUDE_SERVICES DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(true, false)); - //Enhanced JMX Agent Support DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(true,false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(true,false)); @@ -252,7 +253,7 @@ void RunFinalizationDCmd::execute(TRAPS) { vmSymbols::void_method_signature(), CHECK); } -#if INCLUDE_SERVICES // Heap dumping supported +#if INCLUDE_SERVICES // Heap dumping/inspection supported HeapDumpDCmd::HeapDumpDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap), _filename("filename","Name of the dump file", "STRING",true), @@ -292,7 +293,6 @@ int HeapDumpDCmd::num_arguments() { return 0; } } -#endif // INCLUDE_SERVICES ClassHistogramDCmd::ClassHistogramDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap), @@ -319,6 +319,65 @@ int ClassHistogramDCmd::num_arguments() { } } +#define DEFAULT_COLUMNS "InstBytes,KlassBytes,CpAll,annotations,MethodCount,Bytecodes,MethodAll,ROAll,RWAll,Total" +ClassStatsDCmd::ClassStatsDCmd(outputStream* output, bool heap) : + DCmdWithParser(output, heap), + _csv("-csv", "Print in CSV (comma-separated values) format for spreadsheets", + "BOOLEAN", false, "false"), + _all("-all", "Show all columns", + "BOOLEAN", false, "false"), + _help("-help", "Show meaning of all the columns", + "BOOLEAN", false, "false"), + _columns("columns", "Comma-separated list of all the columns to show. " + "If not specified, the following columns are shown: " DEFAULT_COLUMNS, + "STRING", false) { + _dcmdparser.add_dcmd_option(&_all); + _dcmdparser.add_dcmd_option(&_csv); + _dcmdparser.add_dcmd_option(&_help); + _dcmdparser.add_dcmd_argument(&_columns); +} + +void ClassStatsDCmd::execute(TRAPS) { + if (!UnlockDiagnosticVMOptions) { + output()->print_cr("GC.class_stats command requires -XX:+UnlockDiagnosticVMOptions"); + return; + } + + VM_GC_HeapInspection heapop(output(), + true, /* request_full_gc */ + true /* need_prologue */); + heapop.set_csv_format(_csv.value()); + heapop.set_print_help(_help.value()); + heapop.set_print_class_stats(true); + if (_all.value()) { + if (_columns.has_value()) { + output()->print_cr("Cannot specify -all and individual columns at the same time"); + return; + } else { + heapop.set_columns(NULL); + } + } else { + if (_columns.has_value()) { + heapop.set_columns(_columns.value()); + } else { + heapop.set_columns(DEFAULT_COLUMNS); + } + } + VMThread::execute(&heapop); +} + +int ClassStatsDCmd::num_arguments() { + ResourceMark rm; + ClassStatsDCmd* dcmd = new ClassStatsDCmd(NULL, false); + if (dcmd != NULL) { + DCmdMark mark(dcmd); + return dcmd->_dcmdparser.num_arguments(); + } else { + return 0; + } +} +#endif // INCLUDE_SERVICES + ThreadDumpDCmd::ThreadDumpDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap), _locks("-l", "print java.util.concurrent locks", "BOOLEAN", false, "false") { @@ -406,7 +465,32 @@ JMXStartRemoteDCmd::JMXStartRemoteDCmd(outputStream *output, bool heap_allocated _jmxremote_ssl_config_file ("jmxremote.ssl.config.file", - "set com.sun.management.jmxremote.ssl_config_file", "STRING", false) + "set com.sun.management.jmxremote.ssl_config_file", "STRING", false), + +// JDP Protocol support + _jmxremote_autodiscovery + ("jmxremote.autodiscovery", + "set com.sun.management.jmxremote.autodiscovery", "STRING", false), + + _jdp_port + ("jdp.port", + "set com.sun.management.jdp.port", "INT", false), + + _jdp_address + ("jdp.address", + "set com.sun.management.jdp.address", "STRING", false), + + _jdp_source_addr + ("jdp.source_addr", + "set com.sun.management.jdp.source_addr", "STRING", false), + + _jdp_ttl + ("jdp.ttl", + "set com.sun.management.jdp.ttl", "INT", false), + + _jdp_pause + ("jdp.pause", + "set com.sun.management.jdp.pause", "INT", false) { _dcmdparser.add_dcmd_option(&_config_file); @@ -422,6 +506,12 @@ JMXStartRemoteDCmd::JMXStartRemoteDCmd(outputStream *output, bool heap_allocated _dcmdparser.add_dcmd_option(&_jmxremote_ssl_enabled_protocols); _dcmdparser.add_dcmd_option(&_jmxremote_ssl_need_client_auth); _dcmdparser.add_dcmd_option(&_jmxremote_ssl_config_file); + _dcmdparser.add_dcmd_option(&_jmxremote_autodiscovery); + _dcmdparser.add_dcmd_option(&_jdp_port); + _dcmdparser.add_dcmd_option(&_jdp_address); + _dcmdparser.add_dcmd_option(&_jdp_source_addr); + _dcmdparser.add_dcmd_option(&_jdp_ttl); + _dcmdparser.add_dcmd_option(&_jdp_pause); } @@ -436,7 +526,6 @@ int JMXStartRemoteDCmd::num_arguments() { } } - void JMXStartRemoteDCmd::execute(TRAPS) { ResourceMark rm(THREAD); HandleMark hm(THREAD); @@ -466,7 +555,9 @@ void JMXStartRemoteDCmd::execute(TRAPS) { // file. #define PUT_OPTION(a) \ if ( (a).is_set() ){ \ - options.print("%scom.sun.management.%s=%s", comma, (a).name(), (a).value()); \ + options.print(\ + ( *((a).type()) == 'I' ) ? "%scom.sun.management.%s=%d" : "%scom.sun.management.%s=%s",\ + comma, (a).name(), (a).value()); \ comma[0] = ','; \ } @@ -483,6 +574,12 @@ void JMXStartRemoteDCmd::execute(TRAPS) { PUT_OPTION(_jmxremote_ssl_enabled_protocols); PUT_OPTION(_jmxremote_ssl_need_client_auth); PUT_OPTION(_jmxremote_ssl_config_file); + PUT_OPTION(_jmxremote_autodiscovery); + PUT_OPTION(_jdp_port); + PUT_OPTION(_jdp_address); + PUT_OPTION(_jdp_source_addr); + PUT_OPTION(_jdp_ttl); + PUT_OPTION(_jdp_pause); #undef PUT_OPTION diff --git a/hotspot/src/share/vm/services/diagnosticCommand.hpp b/hotspot/src/share/vm/services/diagnosticCommand.hpp index 99d75a92f33..ac5d5809d1e 100644 --- a/hotspot/src/share/vm/services/diagnosticCommand.hpp +++ b/hotspot/src/share/vm/services/diagnosticCommand.hpp @@ -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 @@ -35,6 +35,7 @@ #include "services/diagnosticCommand.hpp" #include "services/diagnosticFramework.hpp" #include "services/diagnosticCommand_ext.hpp" +#include "utilities/macros.hpp" class HelpDCmd : public DCmdWithParser { protected: @@ -178,7 +179,7 @@ public: }; #endif // INCLUDE_SERVICES -// See also: inspeactheap in attachListener.cpp +// See also: inspectheap in attachListener.cpp class ClassHistogramDCmd : public DCmdWithParser { protected: DCmdArgument _all; @@ -197,6 +198,27 @@ public: virtual void execute(TRAPS); }; +class ClassStatsDCmd : public DCmdWithParser { +protected: + DCmdArgument _all; + DCmdArgument _csv; + DCmdArgument _help; + DCmdArgument _columns; +public: + ClassStatsDCmd(outputStream* output, bool heap); + static const char* name() { + return "GC.class_stats"; + } + static const char* description() { + return "Provide statistics about Java class meta data. Requires -XX:+UnlockDiagnosticVMOptions."; + } + static const char* impact() { + return "High: Depends on Java heap size and content."; + } + static int num_arguments(); + virtual void execute(TRAPS); +}; + // See also: thread_dump in attachListener.cpp class ThreadDumpDCmd : public DCmdWithParser { protected: @@ -236,6 +258,16 @@ class JMXStartRemoteDCmd : public DCmdWithParser { DCmdArgument _jmxremote_ssl_need_client_auth; DCmdArgument _jmxremote_ssl_config_file; + // JDP support + // Keep autodiscovery char* not bool to pass true/false + // as property value to java level. + DCmdArgument _jmxremote_autodiscovery; + DCmdArgument _jdp_port; + DCmdArgument _jdp_address; + DCmdArgument _jdp_source_addr; + DCmdArgument _jdp_ttl; + DCmdArgument _jdp_pause; + public: JMXStartRemoteDCmd(outputStream *output, bool heap_allocated); diff --git a/hotspot/src/share/vm/services/g1MemoryPool.hpp b/hotspot/src/share/vm/services/g1MemoryPool.hpp index c84ecb2d555..abe67e2f91c 100644 --- a/hotspot/src/share/vm/services/g1MemoryPool.hpp +++ b/hotspot/src/share/vm/services/g1MemoryPool.hpp @@ -25,11 +25,12 @@ #ifndef SHARE_VM_SERVICES_G1MEMORYPOOL_HPP #define SHARE_VM_SERVICES_G1MEMORYPOOL_HPP -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1MonitoringSupport.hpp" #include "services/memoryPool.hpp" #include "services/memoryUsage.hpp" -#endif +#endif // INCLUDE_ALL_GCS // This file contains the three classes that represent the memory // pools of the G1 spaces: G1EdenPool, G1SurvivorPool, and diff --git a/hotspot/src/share/vm/services/heapDumper.cpp b/hotspot/src/share/vm/services/heapDumper.cpp index 65ee27f457a..fa1bf273e07 100644 --- a/hotspot/src/share/vm/services/heapDumper.cpp +++ b/hotspot/src/share/vm/services/heapDumper.cpp @@ -40,9 +40,10 @@ #include "services/heapDumper.hpp" #include "services/threadService.hpp" #include "utilities/ostream.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" -#endif +#endif // INCLUDE_ALL_GCS /* * HPROF binary format - description copied from: diff --git a/hotspot/src/share/vm/services/management.cpp b/hotspot/src/share/vm/services/management.cpp index a5b68d9b655..549622e9210 100644 --- a/hotspot/src/share/vm/services/management.cpp +++ b/hotspot/src/share/vm/services/management.cpp @@ -53,6 +53,7 @@ #include "services/memoryService.hpp" #include "services/runtimeService.hpp" #include "services/threadService.hpp" +#include "utilities/macros.hpp" PerfVariable* Management::_begin_vm_creation_time = NULL; PerfVariable* Management::_end_vm_creation_time = NULL; diff --git a/hotspot/src/share/vm/services/memBaseline.cpp b/hotspot/src/share/vm/services/memBaseline.cpp index 9d9832e8601..681b4d7d9d1 100644 --- a/hotspot/src/share/vm/services/memBaseline.cpp +++ b/hotspot/src/share/vm/services/memBaseline.cpp @@ -40,6 +40,7 @@ MemType2Name MemBaseline::MemType2NameMap[NUMBER_OF_MEMORY_TYPE] = { {mtNMT, "Memory Tracking"}, {mtChunk, "Pooled Free Chunks"}, {mtClassShared,"Shared spaces for classes"}, + {mtTest, "Test"}, {mtNone, "Unknown"} // It can happen when type tagging records are lagging // behind }; diff --git a/hotspot/src/share/vm/services/memPtr.cpp b/hotspot/src/share/vm/services/memPtr.cpp index 5d0fbf5bf57..3e124e2bde2 100644 --- a/hotspot/src/share/vm/services/memPtr.cpp +++ b/hotspot/src/share/vm/services/memPtr.cpp @@ -27,8 +27,8 @@ #include "services/memTracker.hpp" volatile jint SequenceGenerator::_seq_number = 1; +volatile unsigned long SequenceGenerator::_generation = 1; NOT_PRODUCT(jint SequenceGenerator::_max_seq_number = 1;) -DEBUG_ONLY(volatile unsigned long SequenceGenerator::_generation = 0;) jint SequenceGenerator::next() { jint seq = Atomic::add(1, &_seq_number); diff --git a/hotspot/src/share/vm/services/memPtr.hpp b/hotspot/src/share/vm/services/memPtr.hpp index a27c3eb4a10..e1c852ac7ba 100644 --- a/hotspot/src/share/vm/services/memPtr.hpp +++ b/hotspot/src/share/vm/services/memPtr.hpp @@ -47,16 +47,16 @@ class SequenceGenerator : AllStatic { static void reset() { assert(SafepointSynchronize::is_at_safepoint(), "Safepoint required"); _seq_number = 1; - DEBUG_ONLY(_generation ++;) + _generation ++; }; - DEBUG_ONLY(static unsigned long current_generation() { return (unsigned long)_generation; }) + static unsigned long current_generation() { return _generation; } NOT_PRODUCT(static jint max_seq_num() { return _max_seq_number; }) private: - static volatile jint _seq_number; - NOT_PRODUCT(static jint _max_seq_number; ) - DEBUG_ONLY(static volatile unsigned long _generation; ) + static volatile jint _seq_number; + static volatile unsigned long _generation; + NOT_PRODUCT(static jint _max_seq_number; ) }; /* diff --git a/hotspot/src/share/vm/services/memRecorder.cpp b/hotspot/src/share/vm/services/memRecorder.cpp index 93703269ede..776ad223c00 100644 --- a/hotspot/src/share/vm/services/memRecorder.cpp +++ b/hotspot/src/share/vm/services/memRecorder.cpp @@ -55,7 +55,7 @@ volatile jint MemRecorder::_instance_count = 0; MemRecorder::MemRecorder() { assert(MemTracker::is_on(), "Native memory tracking is off"); Atomic::inc(&_instance_count); - debug_only(set_generation();) + set_generation(); if (MemTracker::track_callsite()) { _pointer_records = new (std::nothrow)FixedSizeMemPointerArray { // used for linked list MemRecorder* _next; // active recorder can only record a certain generation data - debug_only(unsigned long _generation;) + unsigned long _generation; protected: _NOINLINE_ MemRecorder(); @@ -251,6 +251,8 @@ class MemRecorder : public CHeapObj { SequencedRecordIterator pointer_itr(); + // return the generation of this recorder which it belongs to + unsigned long get_generation() const { return _generation; } protected: // number of MemRecorder instance static volatile jint _instance_count; @@ -263,7 +265,7 @@ class MemRecorder : public CHeapObj { static int sort_record_fn(const void* e1, const void* e2); debug_only(void check_dup_seq(jint seq) const;) - debug_only(void set_generation();) + void set_generation(); }; #endif // SHARE_VM_SERVICES_MEM_RECORDER_HPP diff --git a/hotspot/src/share/vm/services/memReporter.hpp b/hotspot/src/share/vm/services/memReporter.hpp index 38f1e60bd89..86d4b52efdf 100644 --- a/hotspot/src/share/vm/services/memReporter.hpp +++ b/hotspot/src/share/vm/services/memReporter.hpp @@ -29,6 +29,7 @@ #include "services/memBaseline.hpp" #include "services/memTracker.hpp" #include "utilities/ostream.hpp" +#include "utilities/macros.hpp" #if INCLUDE_NMT diff --git a/hotspot/src/share/vm/services/memTrackWorker.cpp b/hotspot/src/share/vm/services/memTrackWorker.cpp index 19b375d4085..8c38d1a3731 100644 --- a/hotspot/src/share/vm/services/memTrackWorker.cpp +++ b/hotspot/src/share/vm/services/memTrackWorker.cpp @@ -91,6 +91,8 @@ void MemTrackWorker::run() { MemSnapshot* snapshot = MemTracker::get_snapshot(); assert(snapshot != NULL, "Worker should not be started"); MemRecorder* rec; + unsigned long processing_generation = 0; + bool worker_idle = false; while (!MemTracker::shutdown_in_progress()) { NOT_PRODUCT(_last_gen_in_use = generations_in_use();) @@ -100,6 +102,12 @@ void MemTrackWorker::run() { rec = _gen[_head].next_recorder(); } if (rec != NULL) { + if (rec->get_generation() != processing_generation || worker_idle) { + processing_generation = rec->get_generation(); + worker_idle = false; + MemTracker::set_current_processing_generation(processing_generation); + } + // merge the recorder into staging area if (!snapshot->merge(rec)) { MemTracker::shutdown(MemTracker::NMT_out_of_memory); @@ -129,6 +137,9 @@ void MemTrackWorker::run() { MemTracker::shutdown(MemTracker::NMT_out_of_memory); } } else { + // worker thread is idle + worker_idle = true; + MemTracker::report_worker_idle(); snapshot->wait(1000); ThreadCritical tc; // check if more data arrived diff --git a/hotspot/src/share/vm/services/memTrackWorker.hpp b/hotspot/src/share/vm/services/memTrackWorker.hpp index 9a2d52802e2..be80e294d58 100644 --- a/hotspot/src/share/vm/services/memTrackWorker.hpp +++ b/hotspot/src/share/vm/services/memTrackWorker.hpp @@ -107,6 +107,7 @@ class MemTrackWorker : public NamedThread { NOT_PRODUCT(int _merge_count;) NOT_PRODUCT(int _last_gen_in_use;) + // how many generations are queued inline int generations_in_use() const { return (_tail >= _head ? (_tail - _head + 1) : (MAX_GENERATIONS - (_head - _tail) + 1)); } diff --git a/hotspot/src/share/vm/services/memTracker.cpp b/hotspot/src/share/vm/services/memTracker.cpp index c8032d8fd1a..4c110d584ac 100644 --- a/hotspot/src/share/vm/services/memTracker.cpp +++ b/hotspot/src/share/vm/services/memTracker.cpp @@ -29,6 +29,7 @@ #include "runtime/mutexLocker.hpp" #include "runtime/safepoint.hpp" #include "runtime/threadCritical.hpp" +#include "runtime/vm_operations.hpp" #include "services/memPtr.hpp" #include "services/memReporter.hpp" #include "services/memTracker.hpp" @@ -65,6 +66,8 @@ volatile MemTracker::NMTStates MemTracker::_state = NMT_uninited; MemTracker::ShutdownReason MemTracker::_reason = NMT_shutdown_none; int MemTracker::_thread_count = 255; volatile jint MemTracker::_pooled_recorder_count = 0; +volatile unsigned long MemTracker::_processing_generation = 0; +volatile bool MemTracker::_worker_thread_idle = false; debug_only(intx MemTracker::_main_thread_tid = 0;) NOT_PRODUCT(volatile jint MemTracker::_pending_recorder_count = 0;) @@ -279,7 +282,7 @@ MemRecorder* MemTracker::get_new_or_pooled_instance() { } cur_head->set_next(NULL); Atomic::dec(&_pooled_recorder_count); - debug_only(cur_head->set_generation();) + cur_head->set_generation(); return cur_head; } } @@ -570,6 +573,51 @@ bool MemTracker::print_memory_usage(BaselineOutputer& out, size_t unit, bool sum return false; } +// Whitebox API for blocking until the current generation of NMT data has been merged +bool MemTracker::wbtest_wait_for_data_merge() { + // NMT can't be shutdown while we're holding _query_lock + MutexLockerEx lock(_query_lock, true); + assert(_worker_thread != NULL, "Invalid query"); + // the generation at query time, so NMT will spin till this generation is processed + unsigned long generation_at_query_time = SequenceGenerator::current_generation(); + unsigned long current_processing_generation = _processing_generation; + // if generation counter overflown + bool generation_overflown = (generation_at_query_time < current_processing_generation); + long generations_to_wrap = MAX_UNSIGNED_LONG - current_processing_generation; + // spin + while (!shutdown_in_progress()) { + if (!generation_overflown) { + if (current_processing_generation > generation_at_query_time) { + return true; + } + } else { + assert(generations_to_wrap >= 0, "Sanity check"); + long current_generations_to_wrap = MAX_UNSIGNED_LONG - current_processing_generation; + assert(current_generations_to_wrap >= 0, "Sanity check"); + // to overflow an unsigned long should take long time, so to_wrap check should be sufficient + if (current_generations_to_wrap > generations_to_wrap && + current_processing_generation > generation_at_query_time) { + return true; + } + } + + // if worker thread is idle, but generation is not advancing, that means + // there is not safepoint to let NMT advance generation, force one. + if (_worker_thread_idle) { + VM_ForceSafepoint vfs; + VMThread::execute(&vfs); + } + MemSnapshot* snapshot = get_snapshot(); + if (snapshot == NULL) { + return false; + } + snapshot->wait(1000); + current_processing_generation = _processing_generation; + } + // We end up here if NMT is shutting down before our data has been merged + return false; +} + // compare memory usage between current snapshot and baseline bool MemTracker::compare_memory_usage(BaselineOutputer& out, size_t unit, bool summary_only) { MutexLockerEx lock(_query_lock, true); diff --git a/hotspot/src/share/vm/services/memTracker.hpp b/hotspot/src/share/vm/services/memTracker.hpp index 538195c0c75..764b2950543 100644 --- a/hotspot/src/share/vm/services/memTracker.hpp +++ b/hotspot/src/share/vm/services/memTracker.hpp @@ -91,9 +91,10 @@ class MemTracker : AllStatic { static bool compare_memory_usage(BaselineOutputer& out, size_t unit, bool summary_only = true) { } + static bool wbtest_wait_for_data_merge() { } + static inline void sync() { } static inline void thread_exiting(JavaThread* thread) { } - }; @@ -111,6 +112,10 @@ class MemTracker : AllStatic { extern bool NMT_track_callsite; +#ifndef MAX_UNSIGNED_LONG +#define MAX_UNSIGNED_LONG (unsigned long)(-1) +#endif + #ifdef ASSERT #define DEBUG_CALLER_PC (NMT_track_callsite ? os::get_caller_pc(2) : 0) #else @@ -380,6 +385,11 @@ class MemTracker : AllStatic { static bool compare_memory_usage(BaselineOutputer& out, size_t unit, bool summary_only = true); + // the version for whitebox testing support, it ensures that all memory + // activities before this method call, are reflected in the snapshot + // database. + static bool wbtest_wait_for_data_merge(); + // sync is called within global safepoint to synchronize nmt data static void sync(); @@ -432,6 +442,15 @@ class MemTracker : AllStatic { static void create_record_in_recorder(address addr, MEMFLAGS type, size_t size, address pc, JavaThread* thread); + static void set_current_processing_generation(unsigned long generation) { + _worker_thread_idle = false; + _processing_generation = generation; + } + + static void report_worker_idle() { + _worker_thread_idle = true; + } + private: // global memory snapshot static MemSnapshot* _snapshot; @@ -483,6 +502,11 @@ class MemTracker : AllStatic { static volatile enum NMTStates _state; // the reason for shutting down nmt static enum ShutdownReason _reason; + // the generation that NMT is processing + static volatile unsigned long _processing_generation; + // although NMT is still procesing current generation, but + // there is not more recorder to process, set idle state + static volatile bool _worker_thread_idle; }; #endif // !INCLUDE_NMT diff --git a/hotspot/src/share/vm/services/memoryPool.cpp b/hotspot/src/share/vm/services/memoryPool.cpp index dc608c49214..e2895b1f816 100644 --- a/hotspot/src/share/vm/services/memoryPool.cpp +++ b/hotspot/src/share/vm/services/memoryPool.cpp @@ -32,6 +32,7 @@ #include "services/management.hpp" #include "services/memoryManager.hpp" #include "services/memoryPool.hpp" +#include "utilities/macros.hpp" MemoryPool::MemoryPool(const char* name, PoolType type, @@ -208,7 +209,7 @@ MemoryUsage SurvivorContiguousSpacePool::get_memory_usage() { return MemoryUsage(initial_size(), used, committed, maxSize); } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS CompactibleFreeListSpacePool::CompactibleFreeListSpacePool(CompactibleFreeListSpace* space, const char* name, PoolType type, @@ -225,7 +226,7 @@ MemoryUsage CompactibleFreeListSpacePool::get_memory_usage() { return MemoryUsage(initial_size(), used, committed, maxSize); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS GenerationPool::GenerationPool(Generation* gen, const char* name, diff --git a/hotspot/src/share/vm/services/memoryPool.hpp b/hotspot/src/share/vm/services/memoryPool.hpp index c97fdbfa7b3..82606185340 100644 --- a/hotspot/src/share/vm/services/memoryPool.hpp +++ b/hotspot/src/share/vm/services/memoryPool.hpp @@ -30,9 +30,10 @@ #include "memory/heap.hpp" #include "memory/space.hpp" #include "services/memoryUsage.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp" -#endif +#endif // INCLUDE_ALL_GCS // A memory pool represents the memory area that the VM manages. // The Java virtual machine has at least one memory pool @@ -185,7 +186,7 @@ public: } }; -#ifndef SERIALGC +#if INCLUDE_ALL_GCS class CompactibleFreeListSpacePool : public CollectedMemoryPool { private: CompactibleFreeListSpace* _space; @@ -199,7 +200,7 @@ public: MemoryUsage get_memory_usage(); size_t used_in_bytes() { return _space->used(); } }; -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS class GenerationPool : public CollectedMemoryPool { diff --git a/hotspot/src/share/vm/services/memoryService.cpp b/hotspot/src/share/vm/services/memoryService.cpp index 03af9b99885..0040f9d96fc 100644 --- a/hotspot/src/share/vm/services/memoryService.cpp +++ b/hotspot/src/share/vm/services/memoryService.cpp @@ -43,7 +43,8 @@ #include "services/memoryPool.hpp" #include "services/memoryService.hpp" #include "utilities/growableArray.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/parNew/parNewGeneration.hpp" @@ -52,7 +53,7 @@ #include "gc_implementation/parallelScavenge/psYoungGen.hpp" #include "services/g1MemoryPool.hpp" #include "services/psMemoryPool.hpp" -#endif +#endif // INCLUDE_ALL_GCS GrowableArray* MemoryService::_pools_list = new (ResourceObj::C_HEAP, mtInternal) GrowableArray(init_pools_list_size, true); @@ -83,7 +84,7 @@ void MemoryService::set_universe_heap(CollectedHeap* heap) { add_gen_collected_heap_info(GenCollectedHeap::heap()); break; } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS case CollectedHeap::ParallelScavengeHeap : { add_parallel_scavenge_heap_info(ParallelScavengeHeap::heap()); break; @@ -92,7 +93,7 @@ void MemoryService::set_universe_heap(CollectedHeap* heap) { add_g1_heap_info(G1CollectedHeap::heap()); break; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS default: { guarantee(false, "Unrecognized kind of heap"); } @@ -130,22 +131,22 @@ void MemoryService::add_gen_collected_heap_info(GenCollectedHeap* heap) { case Generation::DefNew: _minor_gc_manager = MemoryManager::get_copy_memory_manager(); break; -#ifndef SERIALGC +#if INCLUDE_ALL_GCS case Generation::ParNew: case Generation::ASParNew: _minor_gc_manager = MemoryManager::get_parnew_memory_manager(); break; -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS default: guarantee(false, "Unrecognized generation spec"); break; } if (policy->is_mark_sweep_policy()) { _major_gc_manager = MemoryManager::get_msc_memory_manager(); -#ifndef SERIALGC +#if INCLUDE_ALL_GCS } else if (policy->is_concurrent_mark_sweep_policy()) { _major_gc_manager = MemoryManager::get_cms_memory_manager(); -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS } else { guarantee(false, "Unknown two-gen policy"); } @@ -159,7 +160,7 @@ void MemoryService::add_gen_collected_heap_info(GenCollectedHeap* heap) { add_generation_memory_pool(heap->get_gen(major), _major_gc_manager); } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS // Add memory pools for ParallelScavengeHeap // This function currently only supports two generations collected heap. // The collector for ParallelScavengeHeap will have two memory managers. @@ -185,7 +186,7 @@ void MemoryService::add_g1_heap_info(G1CollectedHeap* g1h) { add_g1YoungGen_memory_pool(g1h, _major_gc_manager, _minor_gc_manager); add_g1OldGen_memory_pool(g1h, _major_gc_manager); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS MemoryPool* MemoryService::add_gen(Generation* gen, const char* name, @@ -222,7 +223,7 @@ MemoryPool* MemoryService::add_survivor_spaces(DefNewGeneration* gen, return (MemoryPool*) pool; } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS MemoryPool* MemoryService::add_cms_space(CompactibleFreeListSpace* space, const char* name, bool is_heap, @@ -233,7 +234,7 @@ MemoryPool* MemoryService::add_cms_space(CompactibleFreeListSpace* space, _pools_list->append(pool); return (MemoryPool*) pool; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS // Add memory pool(s) for one generation void MemoryService::add_generation_memory_pool(Generation* gen, @@ -261,7 +262,7 @@ void MemoryService::add_generation_memory_pool(Generation* gen, break; } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS case Generation::ParNew: case Generation::ASParNew: { @@ -282,7 +283,7 @@ void MemoryService::add_generation_memory_pool(Generation* gen, break; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS case Generation::MarkSweepCompact: { assert(major_mgr != NULL && minor_mgr == NULL, "Should have only one manager"); @@ -293,7 +294,7 @@ void MemoryService::add_generation_memory_pool(Generation* gen, break; } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS case Generation::ConcurrentMarkSweep: case Generation::ASConcurrentMarkSweep: { @@ -306,7 +307,7 @@ void MemoryService::add_generation_memory_pool(Generation* gen, true /* support_usage_threshold */); break; } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS default: assert(false, "should not reach here"); @@ -326,7 +327,7 @@ void MemoryService::add_generation_memory_pool(Generation* gen, } -#ifndef SERIALGC +#if INCLUDE_ALL_GCS void MemoryService::add_psYoung_memory_pool(PSYoungGen* gen, MemoryManager* major_mgr, MemoryManager* minor_mgr) { assert(major_mgr != NULL && minor_mgr != NULL, "Should have two managers"); @@ -384,7 +385,7 @@ void MemoryService::add_g1OldGen_memory_pool(G1CollectedHeap* g1h, mgr->add_pool(old_gen); _pools_list->append(old_gen); } -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS void MemoryService::add_code_heap_memory_pool(CodeHeap* heap) { _code_heap_pool = new CodeHeapPool(heap, @@ -534,17 +535,17 @@ Handle MemoryService::create_MemoryUsage_obj(MemoryUsage usage, TRAPS) { TraceMemoryManagerStats::TraceMemoryManagerStats(Generation::Name kind, GCCause::Cause cause) { switch (kind) { case Generation::DefNew: -#ifndef SERIALGC +#if INCLUDE_ALL_GCS case Generation::ParNew: case Generation::ASParNew: -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS _fullGC=false; break; case Generation::MarkSweepCompact: -#ifndef SERIALGC +#if INCLUDE_ALL_GCS case Generation::ConcurrentMarkSweep: case Generation::ASConcurrentMarkSweep: -#endif // SERIALGC +#endif // INCLUDE_ALL_GCS _fullGC=true; break; default: diff --git a/hotspot/src/share/vm/services/psMemoryPool.hpp b/hotspot/src/share/vm/services/psMemoryPool.hpp index 2fd193f70d0..080b49161f2 100644 --- a/hotspot/src/share/vm/services/psMemoryPool.hpp +++ b/hotspot/src/share/vm/services/psMemoryPool.hpp @@ -25,7 +25,8 @@ #ifndef SHARE_VM_SERVICES_PSMEMORYPOOL_HPP #define SHARE_VM_SERVICES_PSMEMORYPOOL_HPP -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "gc_implementation/parallelScavenge/psOldGen.hpp" #include "gc_implementation/parallelScavenge/psYoungGen.hpp" #include "gc_implementation/shared/mutableSpace.hpp" @@ -34,7 +35,7 @@ #include "memory/space.hpp" #include "services/memoryPool.hpp" #include "services/memoryUsage.hpp" -#endif +#endif // INCLUDE_ALL_GCS class PSGenerationPool : public CollectedMemoryPool { private: diff --git a/hotspot/src/share/vm/services/runtimeService.cpp b/hotspot/src/share/vm/services/runtimeService.cpp index bba6a95af73..49997dfc5b3 100644 --- a/hotspot/src/share/vm/services/runtimeService.cpp +++ b/hotspot/src/share/vm/services/runtimeService.cpp @@ -29,6 +29,7 @@ #include "services/runtimeService.hpp" #include "utilities/dtrace.hpp" #include "utilities/exceptions.hpp" +#include "utilities/macros.hpp" #ifndef USDT2 HS_DTRACE_PROBE_DECL(hs_private, safepoint__begin); diff --git a/hotspot/src/share/vm/utilities/macros.hpp b/hotspot/src/share/vm/utilities/macros.hpp index 64e331d90b0..a97e9e7d039 100644 --- a/hotspot/src/share/vm/utilities/macros.hpp +++ b/hotspot/src/share/vm/utilities/macros.hpp @@ -130,23 +130,23 @@ #endif // INCLUDE_MANAGEMENT /* - * When INCLUDE_ALTERNATE_GCS is false the only garbage collectors + * When INCLUDE_ALL_GCS is false the only garbage collectors * included in the JVM are defaultNewGeneration and markCompact. * - * When INCLUDE_ALTERNATE_GCS is true all garbage collectors are + * When INCLUDE_ALL_GCS is true all garbage collectors are * included in the JVM. */ -#ifndef INCLUDE_ALTERNATE_GCS -#define INCLUDE_ALTERNATE_GCS 1 -#endif // INCLUDE_ALTERNATE_GCS +#ifndef INCLUDE_ALL_GCS +#define INCLUDE_ALL_GCS 1 +#endif // INCLUDE_ALL_GCS -#if INCLUDE_ALTERNATE_GCS -#define NOT_ALTERNATE_GCS_RETURN /* next token must be ; */ -#define NOT_ALTERNATE_GCS_RETURN_(code) /* next token must be ; */ +#if INCLUDE_ALL_GCS +#define NOT_ALL_GCS_RETURN /* next token must be ; */ +#define NOT_ALL_GCS_RETURN_(code) /* next token must be ; */ #else -#define NOT_ALTERNATE_GCS_RETURN {} -#define NOT_ALTERNATE_GCS_RETURN_(code) { return code; } -#endif // INCLUDE_ALTERNATE_GCS +#define NOT_ALL_GCS_RETURN {} +#define NOT_ALL_GCS_RETURN_(code) { return code; } +#endif // INCLUDE_ALL_GCS #ifndef INCLUDE_NMT #define INCLUDE_NMT 1 diff --git a/hotspot/src/share/vm/utilities/top.hpp b/hotspot/src/share/vm/utilities/top.hpp index 034148a50db..b1abbc2f6a5 100644 --- a/hotspot/src/share/vm/utilities/top.hpp +++ b/hotspot/src/share/vm/utilities/top.hpp @@ -33,9 +33,9 @@ #include "utilities/macros.hpp" #include "utilities/ostream.hpp" #include "utilities/sizes.hpp" -#ifndef SERIALGC +#if INCLUDE_ALL_GCS #include "gc_implementation/g1/g1_globals.hpp" -#endif +#endif // INCLUDE_ALL_GCS #ifdef COMPILER1 #include "c1/c1_globals.hpp" #endif diff --git a/hotspot/src/share/vm/utilities/yieldingWorkgroup.cpp b/hotspot/src/share/vm/utilities/yieldingWorkgroup.cpp index 7e594232af4..e344aea4bbf 100644 --- a/hotspot/src/share/vm/utilities/yieldingWorkgroup.cpp +++ b/hotspot/src/share/vm/utilities/yieldingWorkgroup.cpp @@ -23,9 +23,10 @@ */ #include "precompiled.hpp" -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "utilities/yieldingWorkgroup.hpp" -#endif +#endif // INCLUDE_ALL_GCS // Forward declaration of classes declared here. diff --git a/hotspot/src/share/vm/utilities/yieldingWorkgroup.hpp b/hotspot/src/share/vm/utilities/yieldingWorkgroup.hpp index f9646f91f7f..5a626ce7fa3 100644 --- a/hotspot/src/share/vm/utilities/yieldingWorkgroup.hpp +++ b/hotspot/src/share/vm/utilities/yieldingWorkgroup.hpp @@ -25,9 +25,10 @@ #ifndef SHARE_VM_UTILITIES_YIELDINGWORKGROUP_HPP #define SHARE_VM_UTILITIES_YIELDINGWORKGROUP_HPP -#ifndef SERIALGC +#include "utilities/macros.hpp" +#if INCLUDE_ALL_GCS #include "utilities/workgroup.hpp" -#endif +#endif // INCLUDE_ALL_GCS // Forward declarations diff --git a/hotspot/test/TEST.ROOT b/hotspot/test/TEST.ROOT index 24014f68209..629bb54ddb4 100644 --- a/hotspot/test/TEST.ROOT +++ b/hotspot/test/TEST.ROOT @@ -28,4 +28,4 @@ # DO NOT EDIT without first contacting hotspot-regtest@sun.com # The list of keywords supported in this test suite -keys=cte_test +keys=cte_test jcmd nmt regression diff --git a/hotspot/test/compiler/8004741/Test8004741.java b/hotspot/test/compiler/8004741/Test8004741.java index 95e63b9c0c1..baacc34763d 100644 --- a/hotspot/test/compiler/8004741/Test8004741.java +++ b/hotspot/test/compiler/8004741/Test8004741.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 @@ -25,70 +25,160 @@ * @test Test8004741.java * @bug 8004741 * @summary Missing compiled exception handle table entry for multidimensional array allocation + * @run main/othervm -Xmx64m -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -XX:+StressCompiledExceptionHandlers -XX:+SafepointALot -XX:GuaranteedSafepointInterval=100 Test8004741 * @run main/othervm -Xmx64m -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -XX:+StressCompiledExceptionHandlers Test8004741 - * */ import java.util.*; public class Test8004741 extends Thread { + static int passed = 0; + + /** + * Loop forever allocating 2-d arrays. + * Catches and rethrows all exceptions; in the case of ThreadDeath, increments passed. + * Note that passed is incremented here because this is the exception handler with + * the smallest scope; we only want to declare success in the case where it is highly + * likely that the test condition + * (exception in 2-d array alloc interrupted by ThreadDeath) + * actually occurs. + */ static int[][] test(int a, int b) throws Exception { - int[][] ar = null; + int[][] ar; try { ar = new int[a][b]; - } catch (Error e) { - System.out.println("test got Error"); - passed = true; - throw(e); - } catch (Exception e) { - System.out.println("test got Exception"); + } catch (ThreadDeath e) { + System.out.println("test got ThreadDeath"); + passed++; throw(e); } return ar; } - static boolean passed = false; + /* Cookbook wait-notify to track progress of test thread. */ + Object progressLock = new Object(); + private static final int NOT_STARTED = 0; + private static final int RUNNING = 1; + private static final int STOPPING = 2; - public void run() { - System.out.println("test started"); - try { - while(true) { - test(2,20000); + int progressState = NOT_STARTED; + + void toState(int state) { + synchronized (progressLock) { + progressState = state; + progressLock.notify(); + } + } + + void waitFor(int state) { + synchronized (progressLock) { + while (progressState < state) { + try { + progressLock.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + System.out.println("unexpected InterruptedException"); + fail(); } - } catch (ThreadDeath e) { - System.out.println("test got ThreadDeath"); - passed = true; - } catch (Error e) { - e.printStackTrace(); - System.out.println("test got Error"); - } catch (Exception e) { - e.printStackTrace(); - System.out.println("test got Exception"); } + if (progressState > state) { + System.out.println("unexpected test state change, expected " + + state + " but saw " + progressState); + fail(); + } + } + } + + /** + * Loops running test until some sort of an exception or error, + * expects to see ThreadDeath. + */ + public void run() { + try { + // Print before state change, so that other thread is most likely + // to see this thread executing calls to test() in a loop. + System.out.println("thread running"); + toState(RUNNING); + while (true) { + // (2,2) (2,10) (2,100) were observed to tickle the bug; + test(2, 100); + } + } catch (ThreadDeath e) { + // nothing to say, passing was incremented by the test. + } catch (Throwable e) { + e.printStackTrace(); + System.out.println("unexpected Throwable " + e); + fail(); + } + toState(STOPPING); + } + + /** + * Runs a single trial of the test in a thread. + * No single trial is definitive, since the ThreadDeath + * exception might not land in the tested region of code. + */ + public static void threadTest() throws InterruptedException { + Test8004741 t = new Test8004741(); + t.start(); + t.waitFor(RUNNING); + Thread.sleep(100); + System.out.println("stopping thread"); + t.stop(); + t.waitFor(STOPPING); + t.join(); } public static void main(String[] args) throws Exception { + // Warm up "test" + // t will never be started. for (int n = 0; n < 11000; n++) { - test(2, 20); + test(2, 100); } - // First test exception catch - Test8004741 t = new Test8004741(); + // Will this sleep help ensure that the compiler is run? + Thread.sleep(500); + passed = 0; - passed = false; - t.start(); - Thread.sleep(1000); - t.stop(); + try { + test(-1, 100); + System.out.println("Missing NegativeArraySizeException #1"); + fail(); + } catch ( java.lang.NegativeArraySizeException e ) { + System.out.println("Saw expected NegativeArraySizeException #1"); + } - Thread.sleep(5000); - t.join(); - if (passed) { + try { + test(100, -1); + fail(); + System.out.println("Missing NegativeArraySizeException #2"); + fail(); + } catch ( java.lang.NegativeArraySizeException e ) { + System.out.println("Saw expected NegativeArraySizeException #2"); + } + + /* Test repetitions. If the test succeeds-mostly, it succeeds, + * as long as it does not crash (the outcome if the exception range + * table entry for the array allocation is missing). + */ + int N = 12; + for (int n = 0; n < N; n++) { + threadTest(); + } + + if (passed > N/2) { + System.out.println("Saw " + passed + " out of " + N + " possible ThreadDeath hits"); System.out.println("PASSED"); } else { - System.out.println("FAILED"); - System.exit(97); + System.out.println("Too few ThreadDeath hits; expected at least " + N/2 + + " but saw only " + passed); + fail(); } } + static void fail() { + System.out.println("FAILED"); + System.exit(97); + } }; diff --git a/hotspot/test/runtime/7158988/FieldMonitor.java b/hotspot/test/runtime/7158988/FieldMonitor.java index 584d39d20ca..5421f626278 100644 --- a/hotspot/test/runtime/7158988/FieldMonitor.java +++ b/hotspot/test/runtime/7158988/FieldMonitor.java @@ -24,8 +24,10 @@ /* * @test FieldMonitor.java * @bug 7158988 + * @key regression * @summary verify jvm does not crash while debugging - * @run shell TestFieldMonitor.sh + * @run compile TestPostFieldModification.java + * @run main/othervm FieldMonitor * @author axel.siebenborn@sap.com */ import java.io.BufferedReader; diff --git a/hotspot/test/runtime/7158988/TestFieldMonitor.sh b/hotspot/test/runtime/7158988/TestFieldMonitor.sh deleted file mode 100644 index aa18c1609ba..00000000000 --- a/hotspot/test/runtime/7158988/TestFieldMonitor.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/bin/sh - -if [ "${TESTSRC}" = "" ] -then TESTSRC=. -fi - -if [ "${TESTJAVA}" = "" ] -then - PARENT=`dirname \`which java\`` - TESTJAVA=`dirname ${PARENT}` - echo "TESTJAVA not set, selecting " ${TESTJAVA} - echo "If this is incorrect, try setting the variable manually." -fi - -if [ "${TESTCLASSES}" = "" ] -then - echo "TESTCLASSES not set. Test cannot execute. Failed." - exit 1 -fi - -# set platform-dependent variables -OS=`uname -s` -case "$OS" in - SunOS | Linux | Darwin) - NULL=/dev/null - PS=":" - FS="/" - ;; - Windows_95 | Windows_98 | Windows_ME ) - NULL=NUL - PS=";" - FS="\\" - echo "Test skipped, only for WinNT" - exit 0 - ;; - Windows_NT ) - NULL=NUL - PS=";" - FS="\\" - ;; - CYGWIN_NT* ) - NULL=/dev/null - PS=";" - FS="/" - ;; - CYGWIN_* ) - NULL=/dev/null - PS=";" - FS="/" - echo "Test skipped, only for WinNT" - exit 0 - ;; - * ) - echo "Unrecognized system!" - exit 1; - ;; -esac - -#CLASSPATH=.${PS}${TESTCLASSES} ; export CLASSPATH - -cp ${TESTSRC}${FS}*.java . - -${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -fullversion - -${TESTJAVA}${FS}bin${FS}javac -classpath .${PS}$TESTJAVA${FS}lib${FS}tools.jar *.java - -${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -classpath .${PS}$TESTJAVA${FS}lib${FS}tools.jar FieldMonitor > test.out - -grep "A fatal error has been detected" test.out > ${NULL} -if [ $? = 0 ]; then - cat test.out - STATUS=1 -fi - -exit $STATUS diff --git a/hotspot/test/runtime/8000968/Test8000968.sh b/hotspot/test/runtime/8000968/Test8000968.sh new file mode 100644 index 00000000000..cd7183476cf --- /dev/null +++ b/hotspot/test/runtime/8000968/Test8000968.sh @@ -0,0 +1,99 @@ +# +# 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 Test8000968.sh +# @bug 8000968 +# @summary NPG: UseCompressedKlassPointers asserts with ObjectAlignmentInBytes=32 +# @run shell Test8000968.sh +# + +if [ "${TESTJAVA}" = "" ] +then + PARENT=`dirname \`which java\`` + TESTJAVA=`dirname ${PARENT}` + printf "TESTJAVA not set, selecting " ${TESTJAVA} + printf " If this is incorrect, try setting the variable manually.\n" +fi + + +# set platform-dependent variables +OS=`uname -s` +case "$OS" in + Windows_* ) + FS="\\" + NULL=NUL + ;; + * ) + FS="/" + NULL=/dev/null + ;; +esac + +JAVA=${TESTJAVA}${FS}bin${FS}java + +# +# See if platform has 64 bit java. +# +${JAVA} ${TESTVMOPTS} -d64 -version 2>&1 | grep -i "does not support" > ${NULL} +if [ "$?" != "1" ] +then + printf "Platform is 32 bit, does not support -XX:ObjectAlignmentInBytes= option.\n" + printf "Passed.\n" + exit 0 +fi + +# +# Test -XX:ObjectAlignmentInBytes with -XX:+UseCompressedKlassPointers -XX:+UseCompressedOops. +# +${JAVA} ${TESTVMOPTS} -d64 -XX:+UseCompressedKlassPointers -XX:+UseCompressedOops -XX:ObjectAlignmentInBytes=16 -version 2>&1 > ${NULL} +if [ "$?" != "0" ] +then + printf "FAILED: -XX:ObjectAlignmentInBytes=16 option did not work.\n" + exit 1 +fi + +${JAVA} ${TESTVMOPTS} -d64 -XX:+UseCompressedKlassPointers -XX:+UseCompressedOops -XX:ObjectAlignmentInBytes=32 -version 2>&1 > ${NULL} +if [ "$?" != "0" ] +then + printf "FAILED: -XX:ObjectAlignmentInBytes=32 option did not work.\n" + exit 1 +fi + +${JAVA} ${TESTVMOPTS} -d64 -XX:+UseCompressedKlassPointers -XX:+UseCompressedOops -XX:ObjectAlignmentInBytes=64 -version 2>&1 > ${NULL} +if [ "$?" != "0" ] +then + printf "FAILED: -XX:ObjectAlignmentInBytes=64 option did not work.\n" + exit 1 +fi + +${JAVA} ${TESTVMOPTS} -d64 -XX:+UseCompressedKlassPointers -XX:+UseCompressedOops -XX:ObjectAlignmentInBytes=128 -version 2>&1 > ${NULL} +if [ "$?" != "0" ] +then + printf "FAILED: -XX:ObjectAlignmentInBytes=128 option did not work.\n" + exit 1 +fi + + +printf "Passed.\n" +exit 0 diff --git a/hotspot/test/runtime/8007475/StackMapFrameTest.java b/hotspot/test/runtime/8007475/StackMapFrameTest.java new file mode 100644 index 00000000000..b927ae76db6 --- /dev/null +++ b/hotspot/test/runtime/8007475/StackMapFrameTest.java @@ -0,0 +1,41 @@ +/* + * 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 8007475 + * @summary Test memory stomp in stack map test + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UseMallocOnly StackMapFrameTest + */ +public class StackMapFrameTest { + + public static void foo() { + Object o = new Object(); + } + + public static void main(String args[]) { + for (int i = 0; i < 25000; i++) { + foo(); + } + } +} diff --git a/hotspot/test/runtime/NMT/AllocTestType.java b/hotspot/test/runtime/NMT/AllocTestType.java new file mode 100644 index 00000000000..7644884445d --- /dev/null +++ b/hotspot/test/runtime/NMT/AllocTestType.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test consistency of NMT by leaking a few select allocations of the Test type and then verify visibility with jcmd + * @key nmt jcmd + * @library /testlibrary + * @run compile -J-XX:+UnlockDiagnosticVMOptions -J-XX:+WhiteBoxAPI AllocTestType.java + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail AllocTestType + */ + +import com.oracle.java.testlibrary.*; +import sun.hotspot.WhiteBox; + +public class AllocTestType { + + public static void main(String args[]) throws Exception { + OutputAnalyzer output; + + // Grab my own PID + String pid = Integer.toString(ProcessTools.getProcessId()); + ProcessBuilder pb = new ProcessBuilder(); + + // Use WB API to alloc with the mtTest type + if (!WhiteBox.getWhiteBox().NMTAllocTest()) { + throw new Exception("Call to WB API NMTAllocTest() failed"); + } + + // Use WB API to ensure that all data has been merged before we continue + if (!WhiteBox.getWhiteBox().NMTWaitForDataMerge()) { + throw new Exception("Call to WB API NMTWaitForDataMerge() failed"); + } + + // Run 'jcmd VM.native_memory summary' + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Test (reserved=512KB, committed=512KB)"); + + // Free the memory allocated by NMTAllocTest + if (!WhiteBox.getWhiteBox().NMTFreeTestMemory()) { + throw new Exception("Call to WB API NMTFreeTestMemory() failed"); + } + + // Use WB API to ensure that all data has been merged before we continue + if (!WhiteBox.getWhiteBox().NMTWaitForDataMerge()) { + throw new Exception("Call to WB API NMTWaitForDataMerge() failed"); + } + output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("Test (reserved="); + } +} diff --git a/hotspot/test/runtime/NMT/BaselineWithParameter.java b/hotspot/test/runtime/NMT/BaselineWithParameter.java new file mode 100644 index 00000000000..594bd7165ed --- /dev/null +++ b/hotspot/test/runtime/NMT/BaselineWithParameter.java @@ -0,0 +1,54 @@ +/* + * 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 8004802 + * @key nmt jcmd regression + * @summary Regression test for invoking a jcmd with baseline=false, result was that the target VM crashed + * @library /testlibrary + * @run main/othervm -XX:NativeMemoryTracking=detail BaselineWithParameter + */ + +import com.oracle.java.testlibrary.*; + +public class BaselineWithParameter { + + public static void main(String args[]) throws Exception { + // Grab my own PID + String pid = Integer.toString(ProcessTools.getProcessId()); + OutputAnalyzer output; + + ProcessBuilder pb = new ProcessBuilder(); + + // Run 'jcmd VM.native_memory baseline=false' + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "baseline=false"}); + pb.start(); + + // Run 'jcmd VM.native_memory summary=false' + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary=false"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("No command to execute"); + + } +} diff --git a/hotspot/test/runtime/NMT/CommandLineDetail.java b/hotspot/test/runtime/NMT/CommandLineDetail.java new file mode 100644 index 00000000000..d993316ba9c --- /dev/null +++ b/hotspot/test/runtime/NMT/CommandLineDetail.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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 + * @key nmt + * @summary Running with NMT detail should not result in an error or warning + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.*; + +public class CommandLineDetail { + + public static void main(String args[]) throws Exception { + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:NativeMemoryTracking=detail", + "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("error"); + output.shouldNotContain("warning"); + output.shouldHaveExitValue(0); + } +} diff --git a/hotspot/test/runtime/NMT/CommandLineEmptyArgument.java b/hotspot/test/runtime/NMT/CommandLineEmptyArgument.java new file mode 100644 index 00000000000..956cdd26006 --- /dev/null +++ b/hotspot/test/runtime/NMT/CommandLineEmptyArgument.java @@ -0,0 +1,41 @@ +/* + * 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 + * @key nmt + * @summary Empty argument to NMT should result in an informative error message + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.*; + +public class CommandLineEmptyArgument { + + public static void main(String args[]) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:NativeMemoryTracking="); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("Syntax error, expecting -XX:NativeMemoryTracking=[off|summary|detail]"); + output.shouldHaveExitValue(1); + } +} diff --git a/hotspot/test/runtime/NMT/CommandLineInvalidArgument.java b/hotspot/test/runtime/NMT/CommandLineInvalidArgument.java new file mode 100644 index 00000000000..79cc2de9442 --- /dev/null +++ b/hotspot/test/runtime/NMT/CommandLineInvalidArgument.java @@ -0,0 +1,41 @@ +/* + * 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 + * @key nmt + * @summary Invalid argument to NMT should result in an informative error message + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.*; + +public class CommandLineInvalidArgument { + + public static void main(String args[]) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:NativeMemoryTracking=apa"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("Syntax error, expecting -XX:NativeMemoryTracking=[off|summary|detail]"); + output.shouldHaveExitValue(1); + } +} diff --git a/hotspot/test/runtime/NMT/CommandLineSummary.java b/hotspot/test/runtime/NMT/CommandLineSummary.java new file mode 100644 index 00000000000..b8415d1bde9 --- /dev/null +++ b/hotspot/test/runtime/NMT/CommandLineSummary.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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 + * @key nmt + * @summary Running with NMT summary should not result in an error or warning + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.*; + +public class CommandLineSummary { + + public static void main(String args[]) throws Exception { + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:NativeMemoryTracking=summary", + "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("error"); + output.shouldNotContain("warning"); + output.shouldHaveExitValue(0); + } +} diff --git a/hotspot/test/runtime/NMT/CommandLineTurnOffNMT.java b/hotspot/test/runtime/NMT/CommandLineTurnOffNMT.java new file mode 100644 index 00000000000..e8d950cba0a --- /dev/null +++ b/hotspot/test/runtime/NMT/CommandLineTurnOffNMT.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + /* + * @test + * @key nmt + * @summary Turning off NMT should not result in an error or warning + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.*; + +public class CommandLineTurnOffNMT { + + public static void main(String args[]) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:NativeMemoryTracking=off", + "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("error"); + output.shouldNotContain("warning"); + output.shouldHaveExitValue(0); + } +} diff --git a/hotspot/test/runtime/NMT/JcmdScale.java b/hotspot/test/runtime/NMT/JcmdScale.java new file mode 100644 index 00000000000..e57d27b59a3 --- /dev/null +++ b/hotspot/test/runtime/NMT/JcmdScale.java @@ -0,0 +1,67 @@ +/* + * 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 + * @key nmt jcmd + * @summary Test the NMT scale parameter + * @library /testlibrary + * @run main/othervm -XX:NativeMemoryTracking=summary JcmdScale + */ + +import com.oracle.java.testlibrary.*; + +public class JcmdScale { + + public static void main(String args[]) throws Exception { + ProcessBuilder pb = new ProcessBuilder(); + OutputAnalyzer output; + // Grab my own PID + String pid = Integer.toString(ProcessTools.getProcessId()); + + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "scale=KB"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("KB, committed="); + + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "scale=MB"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("MB, committed="); + + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "scale=GB"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("GB, committed="); + + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "scale=apa"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Incorrect scale value: apa"); + + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary", "scale=GB"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("GB, committed="); + + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary", "scale=apa"}); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Incorrect scale value: apa"); + + } +} diff --git a/hotspot/test/runtime/NMT/JcmdWithNMTDisabled.java b/hotspot/test/runtime/NMT/JcmdWithNMTDisabled.java new file mode 100644 index 00000000000..7b58a841315 --- /dev/null +++ b/hotspot/test/runtime/NMT/JcmdWithNMTDisabled.java @@ -0,0 +1,63 @@ +/* + * 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 + * @key nmt jcmd + * @summary Verify that jcmd correctly reports that NMT is not enabled + * @library /testlibrary + * First run without enabling NMT + * @run main/othervm JcmdWithNMTDisabled + * Then run with explicitly disabling NMT, should not be any difference + * @run main/othervm -XX:NativeMemoryTracking=off JcmdWithNMTDisabled + */ + +import com.oracle.java.testlibrary.*; + +public class JcmdWithNMTDisabled { + static ProcessBuilder pb = new ProcessBuilder(); + static String pid; + + public static void main(String args[]) throws Exception { + // Grab my own PID + pid = Integer.toString(ProcessTools.getProcessId()); + + jcmdCommand("summary"); + jcmdCommand("detail"); + jcmdCommand("baseline"); + jcmdCommand("summary.diff"); + jcmdCommand("detail.diff"); + jcmdCommand("scale=GB"); + jcmdCommand("shutdown"); + } + + // Helper method for invoking different jcmd calls, all should fail with the same message saying NMT is not enabled + public static void jcmdCommand(String command) throws Exception { + + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", command}); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + // Verify that jcmd reports that NMT is not enabled + output.shouldContain("Native memory tracking is not enabled"); + } +} diff --git a/hotspot/test/runtime/NMT/PrintNMTStatistics.java b/hotspot/test/runtime/NMT/PrintNMTStatistics.java new file mode 100644 index 00000000000..307ab948abd --- /dev/null +++ b/hotspot/test/runtime/NMT/PrintNMTStatistics.java @@ -0,0 +1,66 @@ +/* + * 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 + * @key nmt regression + * @bug 8005936 + * @summary Make sure PrintNMTStatistics works on normal JVM exit + * @library /testlibrary + * @run compile -J-XX:+UnlockDiagnosticVMOptions -J-XX:+WhiteBoxAPI PrintNMTStatistics.java + */ + +import com.oracle.java.testlibrary.*; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import sun.hotspot.WhiteBox; + +public class PrintNMTStatistics { + + public static void main(String args[]) throws Exception { + + // We start a new java process running with an argument and use WB API to ensure + // we have data for NMT on VM exit + if (args.length > 0) { + // Use WB API to ensure that all data has been merged before we continue + if (!WhiteBox.getWhiteBox().NMTWaitForDataMerge()) { + throw new Exception("Call to WB API NMTWaitForDataMerge() failed"); + } + return; + } + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:NativeMemoryTracking=summary", + "+XX:+PrintNMTStatistics", + "PrintNMTStatistics", + "test"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("Java Heap (reserved="); + output.shouldNotContain("error"); + output.shouldNotContain("warning"); + output.shouldHaveExitValue(0); + } +} diff --git a/hotspot/test/runtime/NMT/PrintNMTStatisticsWithNMTDisabled.java b/hotspot/test/runtime/NMT/PrintNMTStatisticsWithNMTDisabled.java new file mode 100644 index 00000000000..1c25f284d4b --- /dev/null +++ b/hotspot/test/runtime/NMT/PrintNMTStatisticsWithNMTDisabled.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + /* + * @test + * @key nmt + * @summary Trying to enable PrintNMTStatistics should result in a warning + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.*; + +public class PrintNMTStatisticsWithNMTDisabled { + + public static void main(String args[]) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+PrintNMTStatistics", + "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("warning: PrintNMTStatistics is disabled, because native memory tracking is not enabled"); + output.shouldHaveExitValue(0); + } +} diff --git a/hotspot/test/runtime/NMT/ShutdownTwice.java b/hotspot/test/runtime/NMT/ShutdownTwice.java new file mode 100644 index 00000000000..1bb327aedb1 --- /dev/null +++ b/hotspot/test/runtime/NMT/ShutdownTwice.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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 + * @key nmt jcmd + * @summary Run shutdown twice + * @library /testlibrary + * @run main/othervm -XX:NativeMemoryTracking=detail ShutdownTwice + */ + +import com.oracle.java.testlibrary.*; + +public class ShutdownTwice { + + public static void main(String args[]) throws Exception { + // Grab my own PID + String pid = Integer.toString(ProcessTools.getProcessId()); + OutputAnalyzer output; + + ProcessBuilder pb = new ProcessBuilder(); + + // Run 'jcmd VM.native_memory shutdown' + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "shutdown"}); + output = new OutputAnalyzer(pb.start()); + + // Verify that jcmd reports that NMT is shutting down + output.shouldContain("Shutdown is in progress, it will take a few moments to completely shutdown"); + + // Run shutdown again + output = new OutputAnalyzer(pb.start()); + + // Verify that jcmd reports that NMT has been shutdown already + output.shouldContain("Native memory tracking has been shutdown by user"); + } +} diff --git a/hotspot/test/runtime/NMT/SummaryAfterShutdown.java b/hotspot/test/runtime/NMT/SummaryAfterShutdown.java new file mode 100644 index 00000000000..96061f3f004 --- /dev/null +++ b/hotspot/test/runtime/NMT/SummaryAfterShutdown.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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 + * @key nmt jcmd + * @summary Verify that jcmd correctly reports that NMT is not enabled after a shutdown + * @library /testlibrary + * @run main/othervm -XX:NativeMemoryTracking=detail SummaryAfterShutdown + */ + +import com.oracle.java.testlibrary.*; + +public class SummaryAfterShutdown { + + public static void main(String args[]) throws Exception { + OutputAnalyzer output; + // Grab my own PID + String pid = Integer.toString(ProcessTools.getProcessId()); + ProcessBuilder pb = new ProcessBuilder(); + + // Run 'jcmd VM.native_memory shutdown' + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "shutdown"}); + output = new OutputAnalyzer(pb.start()); + + // Verify that jcmd reports that NMT is shutting down + output.shouldContain("Shutdown is in progress, it will take a few moments to completely shutdown"); + + // Run 'jcmd VM.native_memory summary' + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary"}); + output = new OutputAnalyzer(pb.start()); + + // Verify that jcmd reports that NMT has been shutdown + output.shouldContain("Native memory tracking has been shutdown by user"); + } +} diff --git a/hotspot/test/runtime/NMT/SummarySanityCheck.java b/hotspot/test/runtime/NMT/SummarySanityCheck.java new file mode 100644 index 00000000000..cf81d5b35af --- /dev/null +++ b/hotspot/test/runtime/NMT/SummarySanityCheck.java @@ -0,0 +1,119 @@ +/* + * 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 + * @key nmt jcmd + * @summary Sanity check the output of NMT + * @library /testlibrary + * @run compile -J-XX:+UnlockDiagnosticVMOptions -J-XX:+WhiteBoxAPI SummarySanityCheck.java + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:NativeMemoryTracking=summary -XX:+WhiteBoxAPI SummarySanityCheck + */ + +import com.oracle.java.testlibrary.*; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import sun.hotspot.WhiteBox; + +public class SummarySanityCheck { + + private static String jcmdout; + public static void main(String args[]) throws Exception { + // Grab my own PID + String pid = Integer.toString(ProcessTools.getProcessId()); + + // Use WB API to ensure that all data has been merged before we continue + if (!WhiteBox.getWhiteBox().NMTWaitForDataMerge()) { + throw new Exception("Call to WB API NMTWaitForDataMerge() failed"); + } + + ProcessBuilder pb = new ProcessBuilder(); + + // Run 'jcmd VM.native_memory summary scale=KB' + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary", "scale=KB"}); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + jcmdout = output.getOutput(); + // Split by '-' to get the 'groups' + String[] lines = jcmdout.split("\n"); + + if (lines.length == 0) { + throwTestException("Failed to parse jcmd output"); + } + + int totalCommitted = 0, totalReserved = 0; + int totalCommittedSum = 0, totalReservedSum = 0; + + // Match '- (reserved=KB, committed=KB) + Pattern mtTypePattern = Pattern.compile("-\\s+(?[\\w\\s]+)\\(reserved=(?\\d+)KB,\\scommitted=(?\\d+)KB\\)"); + // Match 'Total: reserved=KB, committed=KB' + Pattern totalMemoryPattern = Pattern.compile("Total\\:\\s\\sreserved=(?\\d+)KB,\\s\\scommitted=(?\\d+)KB"); + + for (int i = 0; i < lines.length; i++) { + if (lines[i].startsWith("Total")) { + Matcher totalMemoryMatcher = totalMemoryPattern.matcher(lines[i]); + + if (totalMemoryMatcher.matches() && totalMemoryMatcher.groupCount() == 2) { + totalCommitted = Integer.parseInt(totalMemoryMatcher.group("committed")); + totalReserved = Integer.parseInt(totalMemoryMatcher.group("reserved")); + } else { + throwTestException("Failed to match the expected groups in 'Total' memory part"); + } + } else if (lines[i].startsWith("-")) { + Matcher typeMatcher = mtTypePattern.matcher(lines[i]); + if (typeMatcher.matches()) { + int typeCommitted = Integer.parseInt(typeMatcher.group("committed")); + int typeReserved = Integer.parseInt(typeMatcher.group("reserved")); + + // Make sure reserved is always less or equals + if (typeCommitted > typeReserved) { + throwTestException("Committed (" + typeCommitted + ") was more than Reserved (" + + typeReserved + ") for mtType: " + typeMatcher.group("typename")); + } + + // Add to total and compare them in the end + totalCommittedSum += typeCommitted; + totalReservedSum += typeReserved; + } else { + throwTestException("Failed to match the group on line " + i); + } + } + } + + // See if they add up correctly, rounding is a problem so make sure we're within +/- 8KB + int committedDiff = totalCommitted - totalCommittedSum; + if (committedDiff > 8 || committedDiff < -8) { + throwTestException("Total committed (" + totalCommitted + ") did not match the summarized committed (" + totalCommittedSum + ")" ); + } + + int reservedDiff = totalReserved - totalReservedSum; + if (reservedDiff > 8 || reservedDiff < -8) { + throwTestException("Total reserved (" + totalReserved + ") did not match the summarized reserved (" + totalReservedSum + ")" ); + } + } + + private static void throwTestException(String reason) throws Exception { + throw new Exception(reason + " . Stdout is :\n" + jcmdout); + } +} diff --git a/hotspot/test/testlibrary/OutputAnalyzerTest.java b/hotspot/test/testlibrary/OutputAnalyzerTest.java new file mode 100644 index 00000000000..cc48fd3ff43 --- /dev/null +++ b/hotspot/test/testlibrary/OutputAnalyzerTest.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test the OutputAnalyzer utility class + * @library /testlibrary + */ + +import com.oracle.java.testlibrary.OutputAnalyzer; + +public class OutputAnalyzerTest { + + public static void main(String args[]) throws Exception { + + String stdout = "aaaaaa"; + String stderr = "bbbbbb"; + + OutputAnalyzer output = new OutputAnalyzer(stdout, stderr); + + if (!stdout.equals(output.getStdout())) { + throw new Exception("getStdout() returned '" + output.getStdout() + "', expected '" + stdout + "'"); + } + + if (!stderr.equals(output.getStderr())) { + throw new Exception("getStderr() returned '" + output.getStderr() + "', expected '" + stderr + "'"); + } + + try { + output.shouldContain(stdout); + output.stdoutShouldContain(stdout); + output.shouldContain(stderr); + output.stderrShouldContain(stderr); + } catch (RuntimeException e) { + throw new Exception("shouldContain() failed", e); + } + + try { + output.shouldContain("cccc"); + throw new Exception("shouldContain() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.stdoutShouldContain(stderr); + throw new Exception("stdoutShouldContain() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.stderrShouldContain(stdout); + throw new Exception("stdoutShouldContain() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.shouldNotContain("cccc"); + output.stdoutShouldNotContain("cccc"); + output.stderrShouldNotContain("cccc"); + } catch (RuntimeException e) { + throw new Exception("shouldNotContain() failed", e); + } + + try { + output.shouldNotContain(stdout); + throw new Exception("shouldContain() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.stdoutShouldNotContain(stdout); + throw new Exception("shouldContain() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.stderrShouldNotContain(stderr); + throw new Exception("shouldContain() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + } +} diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/JDKToolFinder.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/JDKToolFinder.java new file mode 100644 index 00000000000..91ad6a8c8a9 --- /dev/null +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/JDKToolFinder.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.java.testlibrary; + +import java.io.File; + +public final class JDKToolFinder { + + private JDKToolFinder() { + } + + /** + * Returns the full path to an executable in jdk/bin based on System property + * test.jdk (set by jtreg test suite) + * + * @return Full path to an executable in jdk/bin + */ + public static String getJDKTool(String tool) { + String binPath = System.getProperty("test.jdk"); + if (binPath == null) { + throw new RuntimeException("System property 'test.jdk' not set. This property is normally set by jtreg. " + + "When running test separately, set this property using '-Dtest.jdk=/path/to/jdk'."); + } + + binPath += File.separatorChar + "bin" + File.separatorChar + tool; + + return binPath; + } +} diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/OutputAnalyzer.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/OutputAnalyzer.java new file mode 100644 index 00000000000..469d0c24a70 --- /dev/null +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/OutputAnalyzer.java @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.java.testlibrary; + +import java.io.IOException; + +public final class OutputAnalyzer { + + private final String stdout; + private final String stderr; + private final int exitValue; + + /** + * Create an OutputAnalyzer, a utility class for verifying output and exit + * value from a Process + * + * @param process Process to analyze + * @throws IOException If an I/O error occurs. + */ + public OutputAnalyzer(Process process) throws IOException { + OutputBuffer output = ProcessTools.getOutput(process); + exitValue = process.exitValue(); + this.stdout = output.getStdout(); + this.stderr = output.getStderr(); + } + + /** + * Create an OutputAnalyzer, a utility class for verifying output + * + * @param buf String buffer to analyze + */ + public OutputAnalyzer(String buf) { + this(buf, buf); + } + + /** + * Create an OutputAnalyzer, a utility class for verifying output + * + * @param stdout stdout buffer to analyze + * @param stderr stderr buffer to analyze + */ + public OutputAnalyzer(String stdout, String stderr) { + this.stdout = stdout; + this.stderr = stderr; + exitValue = -1; + } + + /** + * Verify that the stdout and stderr contents of output buffer contains the string + * + * @param expectedString String that buffer should contain + * @throws RuntimeException If the string was not found + */ + public void shouldContain(String expectedString) { + if (!stdout.contains(expectedString) && !stderr.contains(expectedString)) { + throw new RuntimeException("'" + expectedString + "' missing from stdout/stderr: [" + stdout + stderr + "]\n"); + } + } + + /** + * Verify that the stdout contents of output buffer contains the string + * + * @param expectedString String that buffer should contain + * @throws RuntimeException If the string was not found + */ + public void stdoutShouldContain(String expectedString) { + if (!stdout.contains(expectedString)) { + throw new RuntimeException("'" + expectedString + "' missing from stdout: [" + stdout + "]\n"); + } + } + + /** + * Verify that the stderr contents of output buffer contains the string + * + * @param expectedString String that buffer should contain + * @throws RuntimeException If the string was not found + */ + public void stderrShouldContain(String expectedString) { + if (!stderr.contains(expectedString)) { + throw new RuntimeException("'" + expectedString + "' missing from stderr: [" + stderr + "]\n"); + } + } + + /** + * Verify that the stdout and stderr contents of output buffer does not contain the string + * + * @param expectedString String that the buffer should not contain + * @throws RuntimeException If the string was found + */ + public void shouldNotContain(String notExpectedString) { + if (stdout.contains(notExpectedString)) { + throw new RuntimeException("'" + notExpectedString + "' found in stdout: [" + stdout + "]\n"); + } + if (stderr.contains(notExpectedString)) { + throw new RuntimeException("'" + notExpectedString + "' found in stderr: [" + stderr + "]\n"); + } + } + + /** + * Verify that the stdout contents of output buffer does not contain the string + * + * @param expectedString String that the buffer should not contain + * @throws RuntimeException If the string was found + */ + public void stdoutShouldNotContain(String notExpectedString) { + if (stdout.contains(notExpectedString)) { + throw new RuntimeException("'" + notExpectedString + "' found in stdout: [" + stdout + "]\n"); + } + } + + /** + * Verify that the stderr contents of output buffer does not contain the string + * + * @param expectedString String that the buffer should not contain + * @throws RuntimeException If the string was found + */ + public void stderrShouldNotContain(String notExpectedString) { + if (stderr.contains(notExpectedString)) { + throw new RuntimeException("'" + notExpectedString + "' found in stderr: [" + stderr + "]\n"); + } + } + + /** + * Verifiy the exit value of the process + * + * @param expectedExitValue Expected exit value from process + * @throws RuntimeException If the exit value from the process did not match the expected value + */ + public void shouldHaveExitValue(int expectedExitValue) { + if (getExitValue() != expectedExitValue) { + throw new RuntimeException("Exit value " + getExitValue() + " , expected to get " + expectedExitValue); + } + } + + /** + * Get the contents of the output buffer (stdout and stderr) + * + * @return Content of the output buffer + */ + public String getOutput() { + return stdout + stderr; + } + + /** + * Get the contents of the stdout buffer + * + * @return Content of the stdout buffer + */ + public String getStdout() { + return stdout; + } + + /** + * Get the contents of the stderr buffer + * + * @return Content of the stderr buffer + */ + public String getStderr() { + return stderr; + } + + /** + * Get the process exit value + * + * @return Process exit value + */ + public int getExitValue() { + return exitValue; + } +} diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/OutputBuffer.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/OutputBuffer.java new file mode 100644 index 00000000000..b98d05650f5 --- /dev/null +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/OutputBuffer.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.java.testlibrary; + +public class OutputBuffer { + private final String stdout; + private final String stderr; + + /** + * Create an OutputBuffer, a class for storing and managing stdout and stderr + * results separately + * + * @param stdout stdout result + * @param stderr stderr result + */ + public OutputBuffer(String stdout, String stderr) { + this.stdout = stdout; + this.stderr = stderr; + } + + /** + * Returns the stdout result + * + * @return stdout result + */ + public String getStdout() { + return stdout; + } + + /** + * Returns the stderr result + * + * @return stderr result + */ + public String getStderr() { + return stderr; + } +} diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/ProcessTools.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/ProcessTools.java new file mode 100644 index 00000000000..42203d17ff0 --- /dev/null +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/ProcessTools.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.java.testlibrary; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; + +import sun.management.VMManagement; + +public final class ProcessTools { + + private ProcessTools() { + } + + /** + * Pumps stdout and stderr from running the process into a String. + * + * @param processHandler ProcessHandler to run. + * @return Output from process. + * @throws IOException If an I/O error occurs. + */ + public static OutputBuffer getOutput(ProcessBuilder processBuilder) throws IOException { + return getOutput(processBuilder.start()); + } + + /** + * Pumps stdout and stderr the running process into a String. + * + * @param process Process to pump. + * @return Output from process. + * @throws IOException If an I/O error occurs. + */ + public static OutputBuffer getOutput(Process process) throws IOException { + ByteArrayOutputStream stderrBuffer = new ByteArrayOutputStream(); + ByteArrayOutputStream stdoutBuffer = new ByteArrayOutputStream(); + StreamPumper outPumper = new StreamPumper(process.getInputStream(), stdoutBuffer); + StreamPumper errPumper = new StreamPumper(process.getErrorStream(), stderrBuffer); + Thread outPumperThread = new Thread(outPumper); + Thread errPumperThread = new Thread(errPumper); + + outPumperThread.setDaemon(true); + errPumperThread.setDaemon(true); + + outPumperThread.start(); + errPumperThread.start(); + + try { + process.waitFor(); + outPumperThread.join(); + errPumperThread.join(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return null; + } + + return new OutputBuffer(stdoutBuffer.toString(), stderrBuffer.toString()); + } + + /** + * Get the process id of the current running Java process + * + * @return Process id + */ + public static int getProcessId() throws Exception { + + // Get the current process id using a reflection hack + RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean(); + Field jvm = runtime.getClass().getDeclaredField("jvm"); + + jvm.setAccessible(true); + VMManagement mgmt = (sun.management.VMManagement) jvm.get(runtime); + + Method pid_method = mgmt.getClass().getDeclaredMethod("getProcessId"); + + pid_method.setAccessible(true); + + int pid = (Integer) pid_method.invoke(mgmt); + + return pid; + } + + /** + * Get platform specific VM arguments (e.g. -d64 on 64bit Solaris) + * + * @return String[] with platform specific arguments, empty if there are none + */ + public static String[] getPlatformSpecificVMArgs() { + String osName = System.getProperty("os.name"); + String dataModel = System.getProperty("sun.arch.data.model"); + + if (osName.equals("SunOS") && dataModel.equals("64")) { + return new String[] { "-d64" }; + } + + return new String[] {}; + } + + /** + * Create ProcessBuilder using the java launcher from the jdk to be tested and + * with any platform specific arguments prepended + */ + public static ProcessBuilder createJavaProcessBuilder(String... command) throws Exception { + String javapath = JDKToolFinder.getJDKTool("java"); + + ArrayList args = new ArrayList<>(); + args.add(javapath); + Collections.addAll(args, getPlatformSpecificVMArgs()); + Collections.addAll(args, command); + + return new ProcessBuilder(args.toArray(new String[args.size()])); + + } + +} diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/StreamPumper.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/StreamPumper.java new file mode 100644 index 00000000000..4631bce6175 --- /dev/null +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/StreamPumper.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.java.testlibrary; + +import java.io.OutputStream; +import java.io.InputStream; +import java.io.IOException; + +public final class StreamPumper implements Runnable { + + private static final int BUF_SIZE = 256; + + private final OutputStream out; + private final InputStream in; + + /** + * Create a StreamPumper that reads from in and writes to out. + * + * @param in The stream to read from. + * @param out The stream to write to. + */ + public StreamPumper(InputStream in, OutputStream out) { + this.in = in; + this.out = out; + } + + /** + * Implements Thread.run(). Continuously read from in and write + * to out until in has reached end of stream. Abort + * on interruption. Abort on IOExceptions. + */ + @Override + public void run() { + int length; + InputStream localIn = in; + OutputStream localOut = out; + byte[] buffer = new byte[BUF_SIZE]; + + try { + while (!Thread.interrupted() && (length = localIn.read(buffer)) > 0) { + localOut.write(buffer, 0, length); + } + } catch (IOException e) { + // Just abort if something like this happens. + e.printStackTrace(); + } finally { + try { + localOut.flush(); + in.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } +} diff --git a/jaxp/.hgtags b/jaxp/.hgtags index 25b3727d9e6..ce25c2db0cb 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -196,3 +196,5 @@ b854e70084214e9dcf1b37373f6e4b1a68760e03 jdk8-b68 bdf2af722a6b54fca47d8c51d17a1b8f41dd7a3e jdk8-b72 84946404d1e1de003ed2bf218ef8d48906a90e37 jdk8-b73 2087e24a4357eceb6432e94918e75fdc706a27d6 jdk8-b74 +ff0b73a6b3f6cea644d37d56d746a37743419fa7 jdk8-b75 +0c08593944d0cd30645f6e1e4946c51ff2b10c8c jdk8-b76 diff --git a/jaxp/makefiles/BuildJaxp.gmk b/jaxp/makefiles/BuildJaxp.gmk index e28cdf890c3..749046481a3 100644 --- a/jaxp/makefiles/BuildJaxp.gmk +++ b/jaxp/makefiles/BuildJaxp.gmk @@ -30,8 +30,6 @@ default: all include MakeBase.gmk include JavaCompilation.gmk -JAVAC_JARS ?= "-Xbootclasspath/p:$(LANGTOOLS_OUTPUTDIR)/dist/bootstrap/lib/javac.jar" \ - -jar $(LANGTOOLS_OUTPUTDIR)/dist/bootstrap/lib/javac.jar DISABLE_JAXP_WARNINGS:=-Xlint:all,-deprecation,-unchecked,-rawtypes,-cast,-serial,-dep-ann,-static,-fallthrough # The generate new bytecode uses the new compiler for to generate bytecode @@ -39,7 +37,7 @@ DISABLE_JAXP_WARNINGS:=-Xlint:all,-deprecation,-unchecked,-rawtypes,-cast,-seria # cannot necessarily be run with the boot jdk. $(eval $(call SetupJavaCompiler,GENERATE_NEWBYTECODE_DEBUG,\ JVM:=$(JAVA),\ - JAVAC:=$(JAVAC_JARS),\ + JAVAC:=$(NEW_JAVAC),\ FLAGS:=-XDignore.symbol.file=true $(DISABLE_JAXP_WARNINGS) -g,\ SERVER_DIR:=$(SJAVAC_SERVER_DIR),\ SERVER_JVM:=$(SJAVAC_SERVER_JAVA))) diff --git a/jaxp/src/javax/xml/validation/SchemaFactoryFinder.java b/jaxp/src/javax/xml/validation/SchemaFactoryFinder.java index 39c76ed428f..abd0a7ca0af 100644 --- a/jaxp/src/javax/xml/validation/SchemaFactoryFinder.java +++ b/jaxp/src/javax/xml/validation/SchemaFactoryFinder.java @@ -68,7 +68,7 @@ class SchemaFactoryFinder { // Use try/catch block to support applets try { debug = ss.getSystemProperty("jaxp.debug") != null; - } catch (Exception _) { + } catch (Exception unused) { debug = false; } } @@ -113,7 +113,7 @@ class SchemaFactoryFinder { debugPrintln("using thread context class loader ("+classLoader+") for search"); return; } - } catch( Throwable _ ) { + } catch( Throwable unused ) { ; // getContextClassLoader() undefined in JDK1.1 } diff --git a/jaxp/src/javax/xml/xpath/XPathFactoryFinder.java b/jaxp/src/javax/xml/xpath/XPathFactoryFinder.java index 6db1dae1794..b22120da26a 100644 --- a/jaxp/src/javax/xml/xpath/XPathFactoryFinder.java +++ b/jaxp/src/javax/xml/xpath/XPathFactoryFinder.java @@ -56,7 +56,7 @@ class XPathFactoryFinder { // Use try/catch block to support applets try { debug = ss.getSystemProperty("jaxp.debug") != null; - } catch (Exception _) { + } catch (Exception unused) { debug = false; } } @@ -111,7 +111,7 @@ class XPathFactoryFinder { debugPrintln("using thread context class loader ("+classLoader+") for search"); return; } - } catch( Throwable _ ) { + } catch( Throwable unused ) { ; // getContextClassLoader() undefined in JDK1.1 } diff --git a/jaxws/.hgtags b/jaxws/.hgtags index 1ae97b3df38..54f020a17c1 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -196,3 +196,5 @@ f577a39c9fb3d5820248c13c2cc74a192a9313e0 jdk8-b71 d9707230294d54e695e745a90de6112909100f12 jdk8-b72 c606f644a5d9118c14b5822738bf23c300f14f24 jdk8-b73 12db3c5a3393b03eeb09ff26f418c4420c21aaab jdk8-b74 +966bf9f3c41a59ff5d86ff4275291c52f329f984 jdk8-b75 +c4853f3f0e89ac60aa5b517f5f224f0f60e08577 jdk8-b76 diff --git a/jaxws/makefiles/BuildJaxws.gmk b/jaxws/makefiles/BuildJaxws.gmk index c1b092d64bc..348cba90780 100644 --- a/jaxws/makefiles/BuildJaxws.gmk +++ b/jaxws/makefiles/BuildJaxws.gmk @@ -30,8 +30,6 @@ include $(SPEC) include MakeBase.gmk include JavaCompilation.gmk -JAVAC_JARS ?= -Xbootclasspath/p:$(LANGTOOLS_OUTPUTDIR)/dist/bootstrap/lib/javac.jar \ - -jar $(LANGTOOLS_OUTPUTDIR)/dist/bootstrap/lib/javac.jar DISABLE_JAXWS_WARNINGS:=-Xlint:all,-varargs,-rawtypes,-deprecation,-unchecked,-serial,-dep-ann,-cast,-fallthrough,-static # The generate new bytecode uses the new compiler for to generate bytecode @@ -39,7 +37,7 @@ DISABLE_JAXWS_WARNINGS:=-Xlint:all,-varargs,-rawtypes,-deprecation,-unchecked,-s # cannot necessarily be run with the boot jdk. $(eval $(call SetupJavaCompiler,GENERATE_NEWBYTECODE_DEBUG,\ JVM:=$(JAVA),\ - JAVAC:=$(JAVAC_JARS),\ + JAVAC:=$(NEW_JAVAC),\ FLAGS:=-XDignore.symbol.file=true $(DISABLE_JAXWS_WARNINGS) -g,\ SERVER_DIR:=$(SJAVAC_SERVER_DIR),\ SERVER_JVM:=$(SJAVAC_SERVER_JAVA))) diff --git a/jdk/.hgtags b/jdk/.hgtags index dbc8d128f1f..6622885bcd8 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -196,3 +196,6 @@ a996b57e554198f4592a5f3c30f2f9f4075e545d jdk8-b70 32a57e645e012a1f0665c075969ca598e0dbb948 jdk8-b72 733885f57e14cc27f5a5ff0dffe641d2fa3c704a jdk8-b73 57d5d954462831ac353a1f40d3bb05ddb4620952 jdk8-b74 +4a67fdb752b7d6329d9be9c28d3f9d6cf7eb9a3c jdk8-b75 +3a263052866137b645ab86498a43693ff5c19e69 jdk8-b76 +b2fc8e31cecc35b76188e821d4c5dc0e0b74ac24 jdk8-b77 diff --git a/jdk/make/common/shared/Sanity.gmk b/jdk/make/common/shared/Sanity.gmk index c73a3b755d6..c4a96d73c5f 100644 --- a/jdk/make/common/shared/Sanity.gmk +++ b/jdk/make/common/shared/Sanity.gmk @@ -1486,26 +1486,6 @@ endif ###################################################### sane-gcc-compiler: ifndef OPENJDK - ifeq ($(PLATFORM), solaris) - @if [ -r $(GCC_COMPILER_PATH) ]; then \ - if [ ! "$(GCC_VER)" = $(REQUIRED_GCC_VER) ]; then \ - $(ECHO) "ERROR: The Solaris GCC compiler version must be $(REQUIRED_GCC_VER). \n" \ - " You are using the following compiler version: $(GCC_VER) \n" \ - " The compiler was obtained from the following location: \n" \ - " $(GCC_COMPILER_PATH) \n" \ - " Please change your compiler. \n" \ - "" >> $(ERROR_FILE) ; \ - fi \ - else \ - $(ECHO) "ERROR: You do not have a valid GCC_COMPILER_PATH setting. \n" \ - " Please check your access to \n" \ - " $(GCC_COMPILER_PATH) \n" \ - " and/or check your value of ALT_GCC_COMPILER_PATH. \n" \ - " This will affect you if you build the plugin target. \n" \ - "" >> $(ERROR_FILE) ; \ - fi - endif - ifeq ($(PLATFORM), linux) ifeq ($(ARCH_DATA_MODEL), 32) ifdef ALT_GCC29_COMPILER_PATH diff --git a/jdk/make/docs/CORE_PKGS.gmk b/jdk/make/docs/CORE_PKGS.gmk index 86aeae9501d..d55bb8b664e 100644 --- a/jdk/make/docs/CORE_PKGS.gmk +++ b/jdk/make/docs/CORE_PKGS.gmk @@ -128,9 +128,9 @@ CORE_PKGS = \ java.text \ java.text.spi \ java.time \ - java.time.temporal \ - java.time.calendar \ + java.time.chrono \ java.time.format \ + java.time.temporal \ java.time.zone \ java.util \ java.util.concurrent \ diff --git a/jdk/make/java/java/FILES_java.gmk b/jdk/make/java/java/FILES_java.gmk index bf0f9833670..8c2f80c5248 100644 --- a/jdk/make/java/java/FILES_java.gmk +++ b/jdk/make/java/java/FILES_java.gmk @@ -255,7 +255,6 @@ JAVA_JAVA_java = \ java/util/SimpleTimeZone.java \ sun/util/calendar/ZoneInfo.java \ sun/util/calendar/ZoneInfoFile.java \ - sun/util/calendar/TzIDOldMapping.java \ java/util/TooManyListenersException.java \ java/util/Comparator.java \ java/util/Collections.java \ @@ -389,6 +388,7 @@ JAVA_JAVA_java = \ java/util/concurrent/locks/ReadWriteLock.java \ java/util/concurrent/locks/ReentrantLock.java \ java/util/concurrent/locks/ReentrantReadWriteLock.java \ + java/util/concurrent/locks/StampedLock.java \ java/util/regex/Pattern.java \ java/util/regex/Matcher.java \ java/util/regex/MatchResult.java \ diff --git a/jdk/make/jprt.properties b/jdk/make/jprt.properties index a6d2ea1d0d4..8f7038e1f3b 100644 --- a/jdk/make/jprt.properties +++ b/jdk/make/jprt.properties @@ -63,6 +63,7 @@ jprt.vm.default.test.targets= \ ${jprt.my.test.target.set:TESTNAME=jvm98} # Default jdk test targets (testset=default) +# NOTE: This does not match test/Makefile :: jdk_default jprt.make.rule.default.test.targets= \ ${jprt.my.test.target.set:TESTNAME=jdk_lang}, \ ${jprt.my.test.target.set:TESTNAME=jdk_math} @@ -72,6 +73,7 @@ jprt.vm.core.test.targets= \ ${jprt.vm.default.test.targets} # Core jdk test targets (testset=core) +# NOTE: please keep this in sync with test/Makefile :: jdk_core jprt.make.rule.core.test.targets= \ ${jprt.make.rule.default.test.targets}, \ ${jprt.my.test.target.set:TESTNAME=jdk_util}, \ @@ -97,6 +99,7 @@ jprt.vm.all.test.targets= \ ${jprt.my.test.target.set:TESTNAME=jbb_default} # All jdk test targets (testset=all) +# NOTE: This does not match test/Makefile :: jdk_all jprt.make.rule.all.test.targets= \ ${jprt.make.rule.core.test.targets}, \ ${jprt.my.test.target.set:TESTNAME=jdk_awt}, \ diff --git a/jdk/make/netbeans/common/architectures/arch-x86_64.properties b/jdk/make/netbeans/common/architectures/arch-x86_64.properties new file mode 100644 index 00000000000..eac11240e57 --- /dev/null +++ b/jdk/make/netbeans/common/architectures/arch-x86_64.properties @@ -0,0 +1,32 @@ +# +# Copyright (c) 2007, Oracle and/or its affiliates. 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 Oracle 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. +# + +arch=x86_64 diff --git a/jdk/make/netbeans/common/architectures/name-Macosx.properties b/jdk/make/netbeans/common/architectures/name-Macosx.properties new file mode 100644 index 00000000000..05744c7f05c --- /dev/null +++ b/jdk/make/netbeans/common/architectures/name-Macosx.properties @@ -0,0 +1,32 @@ +# +# Copyright (c) 2007, 2012, Oracle and/or its affiliates. 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 Oracle 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. +# + +platform=macosx diff --git a/jdk/make/netbeans/common/java-data-native.ent b/jdk/make/netbeans/common/java-data-native.ent index a801e821db6..8db2a86d618 100644 --- a/jdk/make/netbeans/common/java-data-native.ent +++ b/jdk/make/netbeans/common/java-data-native.ent @@ -39,11 +39,11 @@ ${bootstrap.jdk}/jre/lib/rt.jar ${root}/build/${platform}-${arch}/classes ${root}/build/${platform}-${arch}/docs/api - 1.7 + 1.8 ${root}/test - 1.7 + 1.8 diff --git a/jdk/make/netbeans/common/java-data-no-native.ent b/jdk/make/netbeans/common/java-data-no-native.ent index a204f3a6f17..240ec4aadc9 100644 --- a/jdk/make/netbeans/common/java-data-no-native.ent +++ b/jdk/make/netbeans/common/java-data-no-native.ent @@ -37,11 +37,11 @@ ${bootstrap.jdk}/jre/lib/rt.jar ${root}/build/${platform}-${arch}/classes ${root}/build/${platform}-${arch}/docs/api - 1.7 + 1.8 ${root}/test - 1.7 + 1.8 diff --git a/jdk/make/netbeans/common/make.xml b/jdk/make/netbeans/common/make.xml index a61f04f07db..ee1a47a4fe1 100644 --- a/jdk/make/netbeans/common/make.xml +++ b/jdk/make/netbeans/common/make.xml @@ -33,7 +33,7 @@ - + @@ -42,6 +42,11 @@ + + + + + diff --git a/jdk/make/netbeans/common/shared.xml b/jdk/make/netbeans/common/shared.xml index 7c2b8095f79..ba104445273 100644 --- a/jdk/make/netbeans/common/shared.xml +++ b/jdk/make/netbeans/common/shared.xml @@ -85,6 +85,9 @@ + + + @@ -126,10 +129,6 @@ - - - - diff --git a/jdk/make/sun/Makefile b/jdk/make/sun/Makefile index 3d26ee5e0b4..35fb554a81a 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 tzdb +SUBDIRS = jar security misc net nio text util launcher cldr tzdb ifdef BUILD_HEADLESS_ONLY DISPLAY_LIBS = awt $(HEADLESS_SUBDIR) diff --git a/jdk/make/sun/javazic/Makefile b/jdk/make/sun/javazic/Makefile index 23280317162..9ae3c00b142 100644 --- a/jdk/make/sun/javazic/Makefile +++ b/jdk/make/sun/javazic/Makefile @@ -33,11 +33,11 @@ include $(BUILDDIR)/common/Defs.gmk # Time zone data file creation TZDATA = ./tzdata/ -TZDATA_VER = `$(GREP) '^tzdata' $(TZDATA)VERSION` +TZDATA_VER := $(shell $(GREP) '^tzdata' $(TZDATA)VERSION) TZFILE = \ africa antarctica asia australasia europe northamerica \ pacificnew southamerica backward \ - etcetera solar87 solar88 solar89 systemv + etcetera systemv JDKTZDATA = ./tzdata_jdk/ JDKTZFILES = gmt jdk11_backward TZFILES = \ diff --git a/jdk/make/sun/javazic/tzdata/gmt b/jdk/make/sun/javazic/tzdata/gmt new file mode 100644 index 00000000000..0be31797d7f --- /dev/null +++ b/jdk/make/sun/javazic/tzdata/gmt @@ -0,0 +1,27 @@ +# +# Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# Zone NAME GMTOFF RULES FORMAT [UNTIL] +Zone GMT 0:00 - GMT diff --git a/jdk/make/sun/javazic/tzdata/jdk11_backward b/jdk/make/sun/javazic/tzdata/jdk11_backward new file mode 100644 index 00000000000..5404ceaae4c --- /dev/null +++ b/jdk/make/sun/javazic/tzdata/jdk11_backward @@ -0,0 +1,51 @@ +# +# Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# JDK 1.1.x compatible time zone IDs +# + +# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S +Rule SystemV min 1973 - Apr lastSun 2:00 1:00 D +Rule SystemV min 1973 - Oct lastSun 2:00 0 S +Rule SystemV 1974 only - Jan 6 2:00 1:00 D +Rule SystemV 1974 only - Nov lastSun 2:00 0 S +Rule SystemV 1975 only - Feb 23 2:00 1:00 D +Rule SystemV 1975 only - Oct lastSun 2:00 0 S +Rule SystemV 1976 max - Apr lastSun 2:00 1:00 D +Rule SystemV 1976 max - Oct lastSun 2:00 0 S + +# Zone NAME GMTOFF RULES/SAVE FORMAT [UNTIL] +Zone SystemV/AST4ADT -4:00 SystemV A%sT +Zone SystemV/EST5EDT -5:00 SystemV E%sT +Zone SystemV/CST6CDT -6:00 SystemV C%sT +Zone SystemV/MST7MDT -7:00 SystemV M%sT +Zone SystemV/PST8PDT -8:00 SystemV P%sT +Zone SystemV/YST9YDT -9:00 SystemV Y%sT +Zone SystemV/AST4 -4:00 - AST +Zone SystemV/EST5 -5:00 - EST +Zone SystemV/CST6 -6:00 - CST +Zone SystemV/MST7 -7:00 - MST +Zone SystemV/PST8 -8:00 - PST +Zone SystemV/YST9 -9:00 - YST +Zone SystemV/HST10 -10:00 - HST diff --git a/jdk/make/sun/tzdb/Makefile b/jdk/make/sun/tzdb/Makefile index d09a1251b1d..14fd87a5e69 100644 --- a/jdk/make/sun/tzdb/Makefile +++ b/jdk/make/sun/tzdb/Makefile @@ -43,9 +43,15 @@ BUILD_MANIFEST=true # TZDATA_DIR := ../javazic/tzdata TZDATA_VER := $(subst tzdata,,$(shell $(GREP) '^tzdata' $(TZDATA_DIR)/VERSION)) -TZFILE := africa antarctica asia australasia europe northamerica southamerica backward etcetera +TZFILE := \ + africa antarctica asia australasia europe northamerica \ + pacificnew southamerica backward etcetera \ + gmt jdk11_backward + TZFILES := $(addprefix $(TZDATA_DIR)/,$(TZFILE)) + + TZDB_JAR = tzdb.jar # @@ -61,7 +67,7 @@ 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 \ + $(BOOT_JAVA_CMD) -jar $(BUILDTOOLJARDIR)/tzdb.jar \ -version $(TZDATA_VER) -srcdir $(TZDATA_DIR) -dstdir $(LIBDIR) $(TZFILE) clean clobber:: diff --git a/jdk/make/tools/Makefile b/jdk/make/tools/Makefile index 586a1699486..e01f77ea03d 100644 --- a/jdk/make/tools/Makefile +++ b/jdk/make/tools/Makefile @@ -48,7 +48,6 @@ SUBDIRS = \ hasher_classes \ jarreorder \ jarsplit \ - javazic \ jdwpgen \ makeclasslist \ strip_properties \ diff --git a/jdk/make/tools/src/build/tools/javazic/Zoneinfo.java b/jdk/make/tools/src/build/tools/javazic/Zoneinfo.java index 5614a3c25f3..129f87c57d2 100644 --- a/jdk/make/tools/src/build/tools/javazic/Zoneinfo.java +++ b/jdk/make/tools/src/build/tools/javazic/Zoneinfo.java @@ -490,11 +490,16 @@ class Zoneinfo { tz.addUsedRec(rrec); usedZone = true; } - } else { + } else { // fromTime == minTime int save = rrec.getSave(); - tz.addTransition(fromTime, + tz.addTransition(minTime, + tz.getOffsetIndex(gmtOffset), + tz.getDstOffsetIndex(0)); + + tz.addTransition(transition, tz.getOffsetIndex(gmtOffset+save), tz.getDstOffsetIndex(save)); + tz.addUsedRec(rrec); usedZone = true; } diff --git a/jdk/make/tools/src/build/tools/tzdb/TzdbZoneRulesCompiler.java b/jdk/make/tools/src/build/tools/tzdb/TzdbZoneRulesCompiler.java index 7b32ccf267a..6f42dd9f600 100644 --- a/jdk/make/tools/src/build/tools/tzdb/TzdbZoneRulesCompiler.java +++ b/jdk/make/tools/src/build/tools/tzdb/TzdbZoneRulesCompiler.java @@ -227,6 +227,7 @@ public final class TzdbZoneRulesCompiler { Map> allBuiltZones = new TreeMap<>(); Set allRegionIds = new TreeSet(); Set allRules = new HashSet(); + Map> allLinks = new TreeMap<>(); for (File srcDir : srcDirs) { // source files in this directory @@ -242,7 +243,8 @@ public final class TzdbZoneRulesCompiler { } // compile - String loopVersion = srcDir.getName(); + String loopVersion = (srcDirs.size() == 1 && version != null) + ? version : srcDir.getName(); TzdbZoneRulesCompiler compiler = new TzdbZoneRulesCompiler(loopVersion, srcFiles, verbose); try { // compile @@ -255,12 +257,13 @@ public final class TzdbZoneRulesCompiler { if (verbose) { System.out.println("Outputting file: " + dstFile); } - outputFile(dstFile, loopVersion, builtZones); + outputFile(dstFile, loopVersion, builtZones, compiler.links); // create totals allBuiltZones.put(loopVersion, builtZones); allRegionIds.addAll(builtZones.keySet()); allRules.addAll(builtZones.values()); + allLinks.put(loopVersion, compiler.links); } catch (Exception ex) { System.out.println("Failed: " + ex.toString()); ex.printStackTrace(); @@ -274,7 +277,7 @@ public final class TzdbZoneRulesCompiler { if (verbose) { System.out.println("Outputting combined file: " + dstFile); } - outputFile(dstFile, allBuiltZones, allRegionIds, allRules); + outputFile(dstFile, allBuiltZones, allRegionIds, allRules, allLinks); } } @@ -283,12 +286,15 @@ public final class TzdbZoneRulesCompiler { */ private static void outputFile(File dstFile, String version, - SortedMap builtZones) { + SortedMap builtZones, + Map links) { 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); + Map> loopAllLinks = new TreeMap<>(); + loopAllLinks.put(version, links); + outputFile(dstFile, loopAllBuiltZones, loopAllRegionIds, loopAllRules, loopAllLinks); } /** @@ -297,10 +303,10 @@ public final class TzdbZoneRulesCompiler { private static void outputFile(File dstFile, Map> allBuiltZones, Set allRegionIds, - Set allRules) - { + Set allRules, + Map> allLinks) { try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(dstFile))) { - outputTZEntry(jos, allBuiltZones, allRegionIds, allRules); + outputTZEntry(jos, allBuiltZones, allRegionIds, allRules, allLinks); } catch (Exception ex) { System.out.println("Failed: " + ex.toString()); ex.printStackTrace(); @@ -314,7 +320,8 @@ public final class TzdbZoneRulesCompiler { private static void outputTZEntry(JarOutputStream jos, Map> allBuiltZones, Set allRegionIds, - Set allRules) { + Set allRules, + Map> allLinks) { // this format is not publicly specified try { jos.putNextEntry(new ZipEntry("TZDB.dat")); @@ -359,6 +366,16 @@ public final class TzdbZoneRulesCompiler { out.writeShort(rulesIndex); } } + // alias-region + for (String version : allLinks.keySet()) { + out.writeShort(allLinks.get(version).size()); + for (Map.Entry entry : allLinks.get(version).entrySet()) { + int aliasIndex = Arrays.binarySearch(regionArray, entry.getKey()); + int regionIndex = Arrays.binarySearch(regionArray, entry.getValue()); + out.writeShort(aliasIndex); + out.writeShort(regionIndex); + } + } out.flush(); jos.closeEntry(); } catch (Exception ex) { @@ -621,7 +638,8 @@ public final class TzdbZoneRulesCompiler { private int parseYear(String str, int defaultYear) { if (YEAR.reset(str).matches()) { if (YEAR.group("min") != null) { - return YEAR_MIN_VALUE; + //return YEAR_MIN_VALUE; + return 1900; // systemv has min } else if (YEAR.group("max") != null) { return YEAR_MAX_VALUE; } else if (YEAR.group("only") != null) { @@ -742,16 +760,20 @@ public final class TzdbZoneRulesCompiler { if (realRules == null) { throw new IllegalArgumentException("Alias '" + aliasId + "' links to invalid zone '" + realId + "' for '" + version + "'"); } + links.put(aliasId, realId); + } builtZones.put(aliasId, realRules); } // remove UTC and GMT - builtZones.remove("UTC"); - builtZones.remove("GMT"); - builtZones.remove("GMT0"); + //builtZones.remove("UTC"); + //builtZones.remove("GMT"); + //builtZones.remove("GMT0"); builtZones.remove("GMT+0"); builtZones.remove("GMT-0"); + links.remove("GMT+0"); + links.remove("GMT-0"); } //----------------------------------------------------------------------- @@ -785,7 +807,6 @@ public final class TzdbZoneRulesCompiler { 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); diff --git a/jdk/makefiles/GendataTZDB.gmk b/jdk/makefiles/GendataTZDB.gmk index 3c608fb06ba..51289dd1b6c 100644 --- a/jdk/makefiles/GendataTZDB.gmk +++ b/jdk/makefiles/GendataTZDB.gmk @@ -30,7 +30,7 @@ GENDATA_TZDB := # 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_TZFILE := africa antarctica asia australasia europe northamerica pacificnew southamerica backward etcetera gmt jdk11_backward TZDATA_TZFILES := $(addprefix $(TZDATA_DIR)/,$(TZDATA_TZFILE)) GENDATA_TZDB_DST := $(JDK_OUTPUTDIR)/lib @@ -39,6 +39,6 @@ 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) + $(TOOL_TZDB) -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/GendataTimeZone.gmk b/jdk/makefiles/GendataTimeZone.gmk index dcca735b8f5..1a482dcc044 100644 --- a/jdk/makefiles/GendataTimeZone.gmk +++ b/jdk/makefiles/GendataTimeZone.gmk @@ -34,7 +34,7 @@ GENDATA_TIMEZONE_TMP := $(JDK_OUTPUTDIR)/gendata_timezone TZFILE0 := \ africa antarctica asia australasia europe northamerica \ pacificnew southamerica backward \ - etcetera solar87 solar88 solar89 systemv + etcetera systemv TZFILE1 := \ gmt jdk11_backward diff --git a/jdk/makefiles/GenerateData.gmk b/jdk/makefiles/GenerateData.gmk index 7d7e16b6903..f35cf3278df 100644 --- a/jdk/makefiles/GenerateData.gmk +++ b/jdk/makefiles/GenerateData.gmk @@ -44,9 +44,6 @@ GENDATA += $(BREAK_ITERATOR) include GendataFontConfig.gmk GENDATA += $(GENDATA_FONT_CONFIG) -include GendataTimeZone.gmk -GENDATA += $(GENDATA_TIMEZONE) - include GendataTZDB.gmk GENDATA += $(GENDATA_TZDB) diff --git a/jdk/makefiles/Tools.gmk b/jdk/makefiles/Tools.gmk index 0ed760e0778..5052b7ccb7d 100644 --- a/jdk/makefiles/Tools.gmk +++ b/jdk/makefiles/Tools.gmk @@ -103,9 +103,6 @@ TOOL_HASHER=$(JAVA) -cp $(JDK_OUTPUTDIR)/btclasses \ TOOL_JARSPLIT=$(JAVA) -cp $(JDK_OUTPUTDIR)/btclasses \ build.tools.jarsplit.JarSplit -TOOL_JAVAZIC=$(JAVA) -cp $(JDK_OUTPUTDIR)/btclasses \ - build.tools.javazic.Main - TOOL_TZDB=$(JAVA) -cp $(JDK_OUTPUTDIR)/btclasses \ build.tools.tzdb.TzdbZoneRulesCompiler diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/CDragSourceContextPeer.java b/jdk/src/macosx/classes/sun/lwawt/macosx/CDragSourceContextPeer.java index cec7c552b94..b4f9fd7abb5 100644 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CDragSourceContextPeer.java +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CDragSourceContextPeer.java @@ -88,40 +88,25 @@ public final class CDragSourceContextPeer extends SunDragSourceContextPeer { DragGestureEvent trigger = getTrigger(); InputEvent triggerEvent = trigger.getTriggerEvent(); - Point dragOrigin = trigger.getDragOrigin(); + Point dragOrigin = new Point(trigger.getDragOrigin()); int extModifiers = (triggerEvent.getModifiers() | triggerEvent.getModifiersEx()); long timestamp = triggerEvent.getWhen(); int clickCount = ((triggerEvent instanceof MouseEvent) ? (((MouseEvent) triggerEvent).getClickCount()) : 1); - // Get drag source component and its peer: Component component = trigger.getComponent(); - Point componentOffset = new Point(); - ComponentPeer peer = component.getPeer(); - - // For a lightweight component traverse up the hierarchy to the first heavyweight - // which will be used as the ComponentModel for the native drag source. - if (component.isLightweight()) { - Point loc = component.getLocation(); - componentOffset.translate(loc.x, loc.y); - - for (Component parent = component.getParent(); parent != null; parent = parent.getParent()) { - if (parent.isLightweight() == false) { - peer = parent.getPeer(); - break; - } - - loc = parent.getLocation(); - componentOffset.translate(loc.x, loc.y); - } + // For a lightweight component traverse up the hierarchy to the root + Point loc = component.getLocation(); + Component rootComponent = component; + while (!(rootComponent instanceof Window)) { + dragOrigin.translate(loc.x, loc.y); + rootComponent = rootComponent.getParent(); + loc = rootComponent.getLocation(); } - // Make sure the drop target is a ComponentModel: - if (!(peer instanceof LWComponentPeer)) - throw new IllegalArgumentException("DragSource's peer must be a ComponentModel."); - - // Get model pointer (CButton.m and such) and its native peer: - LWComponentPeer model = (LWComponentPeer) peer; - CPlatformWindow platformWindow = (CPlatformWindow) model.getPlatformWindow(); + //It sure will be LWComponentPeer instance as rootComponent is a Window + LWComponentPeer peer = (LWComponentPeer)rootComponent.getPeer(); + //Get a pointer to a native window + CPlatformWindow platformWindow = (CPlatformWindow) peer.getPlatformWindow(); long nativeWindowPtr = platformWindow.getNSWindowPtr(); // Get drag cursor: @@ -155,7 +140,7 @@ public final class CDragSourceContextPeer extends SunDragSourceContextPeer { try { // Create native dragging source: final long nativeDragSource = createNativeDragSource(component, peer, nativeWindowPtr, transferable, triggerEvent, - (int) (dragOrigin.getX() + componentOffset.x), (int) (dragOrigin.getY() + componentOffset.y), extModifiers, + (int) (dragOrigin.getX()), (int) (dragOrigin.getY()), extModifiers, clickCount, timestamp, cursor, fDragCImage, dragImageOffset.x, dragImageOffset.y, getDragSourceContext().getSourceActions(), formats, formatMap); @@ -165,8 +150,8 @@ public final class CDragSourceContextPeer extends SunDragSourceContextPeer { setNativeContext(nativeDragSource); CCursorManager.getInstance().startDrag( - (int) (dragOrigin.getX() + componentOffset.x), - (int) (dragOrigin.getY() + componentOffset.y)); + (int) (dragOrigin.getX()), + (int) (dragOrigin.getY())); } catch (Exception e) { diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/CPrinterJob.java b/jdk/src/macosx/classes/sun/lwawt/macosx/CPrinterJob.java index 56f5ac7ecc6..791182c1565 100644 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CPrinterJob.java +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CPrinterJob.java @@ -30,6 +30,8 @@ import java.awt.*; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.awt.print.*; +import java.security.AccessController; +import java.security.PrivilegedAction; import javax.print.*; import javax.print.attribute.PrintRequestAttributeSet; @@ -47,6 +49,8 @@ public class CPrinterJob extends RasterPrinterJob { private static String sShouldNotReachHere = "Should not reach here."; + private volatile SecondaryLoop printingLoop; + private boolean noDefaultPrinter = false; private static Font defaultFont; @@ -160,11 +164,22 @@ public class CPrinterJob extends RasterPrinterJob { volatile boolean onEventThread; + @Override + protected void cancelDoc() throws PrinterAbortException { + super.cancelDoc(); + if (printingLoop != null) { + printingLoop.exit(); + } + } + private void completePrintLoop() { Runnable r = new Runnable() { public void run() { synchronized(this) { performingPrinting = false; } + if (printingLoop != null) { + printingLoop.exit(); + } }}; if (onEventThread) { @@ -219,17 +234,21 @@ public class CPrinterJob extends RasterPrinterJob { onEventThread = true; + printingLoop = AccessController.doPrivileged(new PrivilegedAction() { + @Override + public SecondaryLoop run() { + return Toolkit.getDefaultToolkit() + .getSystemEventQueue() + .createSecondaryLoop(); + } + }); + try { // Fire off the print rendering loop on the AppKit thread, and don't have // it wait and block this thread. if (printLoop(false, firstPage, lastPage)) { - // Fire off the EventConditional that will what until the condition is met, - // but will still process AWTEvent's as they occur. - new EventDispatchAccess() { - public boolean evaluate() { - return performingPrinting; - } - }.pumpEventsAndWait(); + // Start a secondary loop on EDT until printing operation is finished or cancelled + printingLoop.enter(); } } catch (Exception e) { e.printStackTrace(); @@ -253,6 +272,9 @@ public class CPrinterJob extends RasterPrinterJob { performingPrinting = false; notify(); } + if (printingLoop != null) { + printingLoop.exit(); + } } // Normalize the collated, # copies, numPages, first/last pages. Need to diff --git a/jdk/src/macosx/lib/flavormap.properties b/jdk/src/macosx/lib/flavormap.properties index 5e17d6e3d83..4a9f5fe3ffe 100644 --- a/jdk/src/macosx/lib/flavormap.properties +++ b/jdk/src/macosx/lib/flavormap.properties @@ -1,7 +1,7 @@ # # This properties file is used to initialize the default -# java.awt.datatransfer.SystemFlavorMap. It contains the X11 platform-specific, -# default mappings between common X11 selection atoms and platform-independent +# java.awt.datatransfer.SystemFlavorMap. It contains the Mac OS X platform-specific, +# default mappings between common Mac OS X selection atoms and platform-independent # MIME type strings, which will be converted into # java.awt.datatransfer.DataFlavors. # @@ -76,3 +76,5 @@ FILE_NAME=application/x-java-file-list;class=java.util.List text/uri-list=application/x-java-file-list;class=java.util.List PNG=image/x-java-image;class=java.awt.Image JFIF=image/x-java-image;class=java.awt.Image +RICH_TEXT=text/rtf +HTML=text/html;charset=utf-8;eoln="\r\n";terminators=1 diff --git a/jdk/src/macosx/native/jobjc/src/core/native/SEL.m b/jdk/src/macosx/native/jobjc/src/core/native/SEL.m index 970a5d30bcf..ebbcf254082 100644 --- a/jdk/src/macosx/native/jobjc/src/core/native/SEL.m +++ b/jdk/src/macosx/native/jobjc/src/core/native/SEL.m @@ -34,7 +34,7 @@ JNIEXPORT jlong JNICALL Java_com_apple_jobjc_SEL_getSelectorPtr const char *selNameAsChars = (*env)->GetStringUTFChars(env, selName, JNI_FALSE); const SEL sel = sel_registerName(selNameAsChars); (*env)->ReleaseStringUTFChars(env, selName, selNameAsChars); - return ptr_to_jlong(sel); + return ptr_to_jlong((void*)sel); } JNIEXPORT jstring JNICALL Java_com_apple_jobjc_SEL_getSelectorName diff --git a/jdk/src/macosx/native/sun/awt/AWTWindow.m b/jdk/src/macosx/native/sun/awt/AWTWindow.m index 3af7c6c736f..bac24ff8d52 100644 --- a/jdk/src/macosx/native/sun/awt/AWTWindow.m +++ b/jdk/src/macosx/native/sun/awt/AWTWindow.m @@ -813,9 +813,9 @@ JNF_COCOA_ENTER(env); if ([nsWindow isKeyWindow]) [window.javaMenuBar deactivate]; window.javaMenuBar = menuBar; - // if ([self isKeyWindow]) { - [CMenuBar activate:window.javaMenuBar modallyDisabled:NO]; - // } + if ([nsWindow isKeyWindow]) { + [CMenuBar activate:window.javaMenuBar modallyDisabled:NO]; + } }]; JNF_COCOA_EXIT(env); diff --git a/jdk/src/macosx/native/sun/awt/CDragSource.m b/jdk/src/macosx/native/sun/awt/CDragSource.m index ef7b09a6edc..635026483d3 100644 --- a/jdk/src/macosx/native/sun/awt/CDragSource.m +++ b/jdk/src/macosx/native/sun/awt/CDragSource.m @@ -443,9 +443,9 @@ static BOOL sNeedsEnter; NSGraphicsContext* graphicsContext = [NSGraphicsContext graphicsContextWithWindow:window]; // Convert mouse coordinates to NS: - NSPoint location = NSMakePoint(fDragPos.x, fDragPos.y); - NSPoint eventLocation = [fView convertPoint:location toView:nil]; - + NSPoint eventLocation = [fView convertPoint:NSMakePoint(fDragPos.x, fDragPos.y) toView:nil]; + eventLocation.y = [[fView window] frame].size.height - eventLocation.y; + // Convert fTriggerEventTimeStamp to NS - AWTEvent.h defines UTC(nsEvent) as ((jlong)[event timestamp] * 1000): NSTimeInterval timeStamp = fTriggerEventTimeStamp / 1000; @@ -497,12 +497,9 @@ static BOOL sNeedsEnter; NSImage* dragImage = fDragImage; // Get drag origin and offset: - NSPoint dragOrigin; - dragOrigin.x = fDragPos.x; - dragOrigin.y = fDragPos.y; - dragOrigin = [view convertPoint:[dragEvent locationInWindow] fromView:nil]; + NSPoint dragOrigin = [dragEvent locationInWindow]; dragOrigin.x += fDragImageOffset.x; - dragOrigin.y += [dragImage size].height + fDragImageOffset.y; + dragOrigin.y -= fDragImageOffset.y + [dragImage size].height; // Drag offset values don't seem to matter: NSSize dragOffset = NSMakeSize(0, 0); @@ -516,7 +513,6 @@ static BOOL sNeedsEnter; DLog5(@" - drag image: %f, %f (%f x %f)", fDragImageOffset.x, fDragImageOffset.y, [dragImage size].width, [dragImage size].height); DLog3(@" - event point (window) %f, %f", [dragEvent locationInWindow].x, [dragEvent locationInWindow].y); DLog3(@" - drag point (view) %f, %f", dragOrigin.x, dragOrigin.y); - // Set up the fDragKeyModifier, so we know if the operation has changed // Set up the fDragMouseModifier, so we can |= it later (since CoreDrag doesn't tell us mouse states during a drag) fDragKeyModifiers = [DnDUtilities extractJavaExtKeyModifiersFromJavaExtModifiers:fModifiers]; diff --git a/jdk/src/macosx/native/sun/awt/CPrinterJob.m b/jdk/src/macosx/native/sun/awt/CPrinterJob.m index 52976f31d26..3935240ff78 100644 --- a/jdk/src/macosx/native/sun/awt/CPrinterJob.m +++ b/jdk/src/macosx/native/sun/awt/CPrinterJob.m @@ -383,31 +383,6 @@ static void javaPrinterJobToNSPrintInfo(JNIEnv* env, jobject srcPrinterJob, jobj } } -/* - * Class: sun_lwawt_macosx_EventDispatchAccess - * Method: pumpEventsAndWait - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_lwawt_macosx_EventDispatchAccess_pumpEventsAndWait -(JNIEnv *env, jobject eda) -{ - static JNF_CLASS_CACHE(jc_Thread, "java/lang/Thread"); - static JNF_STATIC_MEMBER_CACHE(jm_currentThread, jc_Thread, "currentThread", "()Ljava/lang/Thread;"); - static JNF_CLASS_CACHE(jc_EventDispatchThread, "java/awt/EventDispatchThread"); - static JNF_MEMBER_CACHE(jm_macosxGetConditional, jc_EventDispatchThread, "_macosxGetConditional", "(Ljava/lang/Object;)Ljava/awt/Conditional;"); - static JNF_MEMBER_CACHE(jm_pumpEvents, jc_EventDispatchThread, "pumpEvents", "(Ljava/awt/Conditional;)V"); - -JNF_COCOA_DURING(env); - - jobject thread = JNFCallStaticObjectMethod(env, jm_currentThread); - jobject conditional = JNFCallObjectMethod(env, thread, jm_macosxGetConditional, eda); - if (conditional != NULL) { - JNFCallVoidMethod(env, thread, jm_pumpEvents, conditional); - } - -JNF_COCOA_HANDLE(env); -} - /* * Class: sun_lwawt_macosx_CPrinterJob * Method: abortDoc diff --git a/jdk/src/share/bin/parse_manifest.c b/jdk/src/share/bin/parse_manifest.c index ec3014931f2..61b0bbf4884 100644 --- a/jdk/src/share/bin/parse_manifest.c +++ b/jdk/src/share/bin/parse_manifest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -106,8 +106,9 @@ inflate_file(int fd, zentry *entry, int *size_out) *size_out = (int)entry->isize; } return (out); - } else - return (NULL); + } + free(in); + return (NULL); } static jboolean zip64_present = JNI_FALSE; @@ -563,7 +564,7 @@ JLI_ParseManifest(char *jarfile, manifest_info *info) if ((fd = open(jarfile, O_RDONLY #ifdef O_LARGEFILE - | O_LARGEFILE /* large file mode on solaris */ + | O_LARGEFILE /* large file mode */ #endif #ifdef O_BINARY | O_BINARY /* use binary mode on windows */ @@ -618,6 +619,9 @@ JLI_JarUnpackFile(const char *jarfile, const char *filename, int *size) { void *data = NULL; fd = open(jarfile, O_RDONLY +#ifdef O_LARGEFILE + | O_LARGEFILE /* large file mode */ +#endif #ifdef O_BINARY | O_BINARY /* use binary mode on windows */ #endif @@ -661,6 +665,9 @@ JLI_ManifestIterate(const char *jarfile, attribute_closure ac, void *user_data) int rc; if ((fd = open(jarfile, O_RDONLY +#ifdef O_LARGEFILE + | O_LARGEFILE /* large file mode */ +#endif #ifdef O_BINARY | O_BINARY /* use binary mode on windows */ #endif 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 9e891fc7c87..f6ff030263e 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 @@ -1287,19 +1287,24 @@ class Attribute implements Comparable { if (localRef == 0) { globalRef = null; // N.B. global null reference is -1 } else { - globalRef = holder.getCPMap()[localRef]; - if (e.refKind == CONSTANT_Signature + Entry[] cpMap = holder.getCPMap(); + globalRef = (localRef >= 0 && localRef < cpMap.length + ? cpMap[localRef] + : null); + byte tag = e.refKind; + if (globalRef != null && tag == CONSTANT_Signature && globalRef.getTag() == CONSTANT_Utf8) { // Cf. ClassReader.readSignatureRef. String typeName = globalRef.stringValue(); globalRef = ConstantPool.getSignatureEntry(typeName); - } else if (e.refKind == CONSTANT_FieldSpecific) { - assert(globalRef.getTag() >= CONSTANT_Integer); - assert(globalRef.getTag() <= CONSTANT_String || - globalRef.getTag() >= CONSTANT_MethodHandle); - assert(globalRef.getTag() <= CONSTANT_MethodType); - } else if (e.refKind < CONSTANT_GroupFirst) { - assert(e.refKind == globalRef.getTag()); + } + String got = (globalRef == null + ? "invalid CP index" + : "type=" + ConstantPool.tagName(globalRef.tag)); + if (globalRef == null || !globalRef.tagMatches(tag)) { + throw new IllegalArgumentException( + "Bad constant, expected type=" + + ConstantPool.tagName(tag) + " got " + got); } } out.putRef(bandIndex, globalRef); diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java index 2ca2d0926c6..3df8706da37 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/ClassReader.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 @@ -54,6 +54,7 @@ class ClassReader { Package pkg; Class cls; long inPos; + long constantPoolLimit = -1; DataInputStream in; Map attrDefs; Map attrCommands; @@ -117,15 +118,33 @@ class ClassReader { private Entry readRef(byte tag) throws IOException { Entry e = readRef(); - assert(e != null); assert(!(e instanceof UnresolvedEntry)); - assert(e.tagMatches(tag)); + checkTag(e, tag); return e; } + /** Throw a ClassFormatException if the entry does not match the expected tag type. */ + private Entry checkTag(Entry e, byte tag) throws ClassFormatException { + if (e == null || !e.tagMatches(tag)) { + String where = (inPos == constantPoolLimit + ? " in constant pool" + : " at pos: " + inPos); + String got = (e == null + ? "null CP index" + : "type=" + ConstantPool.tagName(e.tag)); + throw new ClassFormatException("Bad constant, expected type=" + + ConstantPool.tagName(tag) + + " got "+ got + ", in File: " + cls.file.nameString + where); + } + return e; + } + private Entry checkTag(Entry e, byte tag, boolean nullOK) throws ClassFormatException { + return nullOK && e == null ? null : checkTag(e, tag); + } + private Entry readRefOrNull(byte tag) throws IOException { Entry e = readRef(); - assert(e == null || e.tagMatches(tag)); + checkTag(e, tag, true); return e; } @@ -143,8 +162,10 @@ class ClassReader { private SignatureEntry readSignatureRef() throws IOException { // The class file stores a Utf8, but we want a Signature. - Entry e = readRef(CONSTANT_Utf8); - return ConstantPool.getSignatureEntry(e.stringValue()); + Entry e = readRef(CONSTANT_Signature); + return (e != null && e.getTag() == CONSTANT_Utf8) + ? ConstantPool.getSignatureEntry(e.stringValue()) + : (SignatureEntry) e; } void read() throws IOException { @@ -279,6 +300,7 @@ class ClassReader { " at pos: " + inPos); } } + constantPoolLimit = inPos; // Fix up refs, which might be out of order. while (fptr > 0) { @@ -311,25 +333,25 @@ class ClassReader { case CONSTANT_Fieldref: case CONSTANT_Methodref: case CONSTANT_InterfaceMethodref: - ClassEntry mclass = (ClassEntry) cpMap[ref]; - DescriptorEntry mdescr = (DescriptorEntry) cpMap[ref2]; + ClassEntry mclass = (ClassEntry) checkTag(cpMap[ref], CONSTANT_Class); + DescriptorEntry mdescr = (DescriptorEntry) checkTag(cpMap[ref2], CONSTANT_NameandType); cpMap[cpi] = ConstantPool.getMemberEntry((byte)tag, mclass, mdescr); break; case CONSTANT_NameandType: - Utf8Entry mname = (Utf8Entry) cpMap[ref]; - Utf8Entry mtype = (Utf8Entry) cpMap[ref2]; + Utf8Entry mname = (Utf8Entry) checkTag(cpMap[ref], CONSTANT_Utf8); + Utf8Entry mtype = (Utf8Entry) checkTag(cpMap[ref2], CONSTANT_Signature); cpMap[cpi] = ConstantPool.getDescriptorEntry(mname, mtype); break; case CONSTANT_MethodType: - cpMap[cpi] = ConstantPool.getMethodTypeEntry((Utf8Entry) cpMap[ref]); + cpMap[cpi] = ConstantPool.getMethodTypeEntry((Utf8Entry) checkTag(cpMap[ref], CONSTANT_Signature)); break; case CONSTANT_MethodHandle: byte refKind = (byte)(-1 ^ ref); - MemberEntry memRef = (MemberEntry) cpMap[ref2]; + MemberEntry memRef = (MemberEntry) checkTag(cpMap[ref2], CONSTANT_AnyMember); cpMap[cpi] = ConstantPool.getMethodHandleEntry(refKind, memRef); break; case CONSTANT_InvokeDynamic: - DescriptorEntry idescr = (DescriptorEntry) cpMap[ref2]; + DescriptorEntry idescr = (DescriptorEntry) checkTag(cpMap[ref2], CONSTANT_NameandType); cpMap[cpi] = new UnresolvedEntry((byte)tag, (-1 ^ ref), idescr); // Note that ref must be resolved later, using the BootstrapMethods attribute. break; @@ -541,7 +563,8 @@ class ClassReader { code.max_locals = readUnsignedShort(); code.bytes = new byte[readInt()]; in.readFully(code.bytes); - Instruction.opcodeChecker(code.bytes); + Entry[] cpMap = cls.getCPMap(); + Instruction.opcodeChecker(code.bytes, cpMap); int nh = readUnsignedShort(); code.setHandlerCount(nh); for (int i = 0; i < nh; i++) { @@ -559,7 +582,7 @@ class ClassReader { MethodHandleEntry bsmRef = (MethodHandleEntry) readRef(CONSTANT_MethodHandle); Entry[] argRefs = new Entry[readUnsignedShort()]; for (int j = 0; j < argRefs.length; j++) { - argRefs[j] = readRef(); + argRefs[j] = readRef(CONSTANT_LoadableValue); } bsms[i] = ConstantPool.getBootstrapMethodEntry(bsmRef, argRefs); } diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java index be4da54d247..ad2175f9993 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.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 @@ -243,8 +243,32 @@ class ConstantPool { return tag == CONSTANT_Double || tag == CONSTANT_Long; } - public final boolean tagMatches(int tag) { - return (this.tag == tag); + public final boolean tagMatches(int matchTag) { + if (tag == matchTag) + return true; + byte[] allowedTags; + switch (matchTag) { + case CONSTANT_All: + return true; + case CONSTANT_Signature: + return tag == CONSTANT_Utf8; // format check also? + case CONSTANT_LoadableValue: + allowedTags = LOADABLE_VALUE_TAGS; + break; + case CONSTANT_AnyMember: + allowedTags = ANY_MEMBER_TAGS; + break; + case CONSTANT_FieldSpecific: + allowedTags = FIELD_SPECIFIC_TAGS; + break; + default: + return false; + } + for (byte b : allowedTags) { + if (b == tag) + return true; + } + return false; } public String toString() { diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/Instruction.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/Instruction.java index f488bede323..31ee22b059d 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Instruction.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Instruction.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 @@ -647,7 +647,7 @@ class Instruction { } } - public static void opcodeChecker(byte[] code) throws FormatException { + public static void opcodeChecker(byte[] code, ConstantPool.Entry[] cpMap) throws FormatException { Instruction i = at(code, 0); while (i != null) { int opcode = i.getBC(); @@ -655,6 +655,16 @@ class Instruction { String message = "illegal opcode: " + opcode + " " + i; throw new FormatException(message); } + ConstantPool.Entry e = i.getCPRef(cpMap); + if (e != null) { + byte tag = i.getCPTag(); + if (!e.tagMatches(tag)) { + String message = "illegal reference, expected type=" + + ConstantPool.tagName(tag) + ": " + + i.toString(cpMap); + throw new FormatException(message); + } + } i = i.next(); } } 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 e6990451135..47959294fd2 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 @@ -1618,6 +1618,16 @@ class PackageWriter extends BandStructure { bc_which = null; assert(false); } + if (ref != null && bc_which.index != null && !bc_which.index.contains(ref)) { + // Crash and burn with a complaint if there are funny + // references for this bytecode instruction. + // Example: invokestatic of a CONSTANT_InterfaceMethodref. + String complaint = code.getMethod() + + " contains a bytecode " + i + + " with an unsupported constant reference; please use the pass-file option on this class."; + Utils.log.warning(complaint); + throw new IOException(complaint); + } bc_codes.putByte(vbc); bc_which.putRef(ref); // handle trailing junk diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java index c7ef4ee2013..0dc88a108c7 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.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 @@ -180,6 +180,15 @@ public class PackerImpl extends TLGlobals implements Pack200.Packer { } unknownAttrCommand = uaMode.intern(); } + final String classFormatCommand; + { + String fmtMode = props.getProperty(Utils.CLASS_FORMAT_ERROR, Pack200.Packer.PASS); + if (!(Pack200.Packer.PASS.equals(fmtMode) || + Pack200.Packer.ERROR.equals(fmtMode))) { + throw new RuntimeException("Bad option: " + Utils.CLASS_FORMAT_ERROR + " = " + fmtMode); + } + classFormatCommand = fmtMode.intern(); + } final Map attrDefs; final Map attrCommands; @@ -505,8 +514,7 @@ public class PackerImpl extends TLGlobals implements Pack200.Packer { } } else if (ioe instanceof ClassReader.ClassFormatException) { ClassReader.ClassFormatException ce = (ClassReader.ClassFormatException) ioe; - // %% TODO: Do we invent a new property for this or reuse %% - if (unknownAttrCommand.equals(Pack200.Packer.PASS)) { + if (classFormatCommand.equals(Pack200.Packer.PASS)) { Utils.log.info(ce.toString()); Utils.log.warning(message + " unknown class format: " + fname); diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/PropMap.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/PropMap.java index 6199c77b51d..24485040378 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/PropMap.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/PropMap.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 @@ -112,6 +112,11 @@ final class PropMap implements SortedMap { // Pass through files with unrecognized attributes by default. props.put(Pack200.Packer.UNKNOWN_ATTRIBUTE, Pack200.Packer.PASS); + // Pass through files with unrecognized format by default, also + // allow system property to be set + props.put(Utils.CLASS_FORMAT_ERROR, + System.getProperty(Utils.CLASS_FORMAT_ERROR, Pack200.Packer.PASS)); + // Default effort is 5, midway between 1 and 9. props.put(Pack200.Packer.EFFORT, "5"); diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/Utils.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/Utils.java index 5edd73e21cb..ebe0960dba0 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Utils.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Utils.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 @@ -122,6 +122,12 @@ class Utils { */ static final String PACK_ZIP_ARCHIVE_MARKER_COMMENT = "PACK200"; + /* + * behaviour when we hit a class format error, but not necessarily + * an unknown attribute, by default it is allowed to PASS. + */ + static final String CLASS_FORMAT_ERROR = COM_PREFIX+"class.format.error"; + // Keep a TLS point to the global data and environment. // This makes it simpler to supply environmental options // to the engine code, especially the native code. diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java index 2e259a818c8..5680cc66631 100644 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java @@ -50,8 +50,6 @@ import javax.management.MBeanInfo; import javax.management.NotCompliantMBeanException; import com.sun.jmx.remote.util.EnvHelp; -import java.beans.BeanInfo; -import java.beans.PropertyDescriptor; import java.lang.reflect.Array; import java.lang.reflect.InvocationTargetException; import javax.management.AttributeNotFoundException; diff --git a/jdk/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java b/jdk/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java index 3d1744ba172..719aeee76d4 100644 --- a/jdk/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java +++ b/jdk/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java @@ -52,16 +52,19 @@ import sun.misc.HexDumpEncoder; * principal set and private credentials set are updated only when * commit is called. * When commit is called, the KerberosPrincipal - * is added to the Subject's - * principal set and KerberosTicket is + * is added to the Subject's principal set (unless the + * principal is specified as "*"). If isInitiator + * is true, the KerberosTicket is * added to the Subject's private credentials. * *

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

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

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

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

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

*

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

*

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

*

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

*

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

*

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

*

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

*

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

+ *

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

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

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

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

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

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

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

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

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

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

    + *

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

+ *

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

    *

    * useTicketCache=true @@ -409,6 +424,7 @@ public class Krb5LoginModule implements LoginModule { private KerberosTicket kerbTicket = null; private KerberosKey[] kerbKeys = null; private StringBuffer krb5PrincName = null; + private boolean unboundServer = false; private char[] password = null; private static final String NAME = "javax.security.auth.login.name"; @@ -520,8 +536,6 @@ public class Krb5LoginModule implements LoginModule { */ public boolean login() throws LoginException { - int len; - validateConfiguration(); if (refreshKrb5Config) { try { if (debug) { @@ -544,6 +558,12 @@ public class Krb5LoginModule implements LoginModule { } } + validateConfiguration(); + + if (krb5PrincName != null && krb5PrincName.toString().equals("*")) { + unboundServer = true; + } + if (tryFirstPass) { try { attemptAuthentication(true); @@ -698,9 +718,17 @@ public class Krb5LoginModule implements LoginModule { * (encKeys == null) to check. */ if (useKeyTab) { - ktab = (keyTabName == null) - ? KeyTab.getInstance() - : KeyTab.getInstance(new File(keyTabName)); + if (!unboundServer) { + KerberosPrincipal kp = + new KerberosPrincipal(principal.getName()); + ktab = (keyTabName == null) + ? KeyTab.getInstance(kp) + : KeyTab.getInstance(kp, new File(keyTabName)); + } else { + ktab = (keyTabName == null) + ? KeyTab.getUnboundInstance() + : KeyTab.getUnboundInstance(new File(keyTabName)); + } if (isInitiator) { if (Krb5Util.keysFromJavaxKeyTab(ktab, principal).length == 0) { @@ -939,6 +967,13 @@ public class Krb5LoginModule implements LoginModule { ("Configuration Error" + " - either useTicketCache should be " + " true or renewTGT should be false"); + if (krb5PrincName != null && krb5PrincName.toString().equals("*")) { + if (isInitiator) { + throw new LoginException + ("Configuration Error" + + " - principal cannot be * when isInitiator is true"); + } + } } private boolean isCurrent(Credentials creds) @@ -1052,7 +1087,10 @@ public class Krb5LoginModule implements LoginModule { } // Let us add the kerbClientPrinc,kerbTicket and KeyTab/KerbKey (if // storeKey is true) - if (!princSet.contains(kerbClientPrinc)) { + + // We won't add "*" as a KerberosPrincipal + if (!unboundServer && + !princSet.contains(kerbClientPrinc)) { princSet.add(kerbClientPrinc); } diff --git a/jdk/src/share/classes/com/sun/security/ntlm/Client.java b/jdk/src/share/classes/com/sun/security/ntlm/Client.java index fcad176b052..7117cdcdc93 100644 --- a/jdk/src/share/classes/com/sun/security/ntlm/Client.java +++ b/jdk/src/share/classes/com/sun/security/ntlm/Client.java @@ -138,8 +138,7 @@ public final class Client extends NTLM { domain = domainFromServer; } if (domain == null) { - throw new NTLMException(NTLMException.NO_DOMAIN_INFO, - "No domain info"); + domain = ""; } int flags = 0x88200 | (inputFlags & 3); diff --git a/jdk/src/share/classes/com/sun/security/ntlm/NTLM.java b/jdk/src/share/classes/com/sun/security/ntlm/NTLM.java index f0949b13a0a..b85fcee7812 100644 --- a/jdk/src/share/classes/com/sun/security/ntlm/NTLM.java +++ b/jdk/src/share/classes/com/sun/security/ntlm/NTLM.java @@ -136,10 +136,10 @@ class NTLM { int readInt(int offset) throws NTLMException { try { - return internal[offset] & 0xff + - (internal[offset+1] & 0xff << 8) + - (internal[offset+2] & 0xff << 16) + - (internal[offset+3] & 0xff << 24); + return (internal[offset] & 0xff) + + ((internal[offset+1] & 0xff) << 8) + + ((internal[offset+2] & 0xff) << 16) + + ((internal[offset+3] & 0xff) << 24); } catch (ArrayIndexOutOfBoundsException ex) { throw new NTLMException(NTLMException.PACKET_READ_ERROR, "Input message incorrect size"); @@ -148,8 +148,8 @@ class NTLM { int readShort(int offset) throws NTLMException { try { - return internal[offset] & 0xff + - (internal[offset+1] & 0xff << 8); + return (internal[offset] & 0xff) + + ((internal[offset+1] & 0xff << 8)); } catch (ArrayIndexOutOfBoundsException ex) { throw new NTLMException(NTLMException.PACKET_READ_ERROR, "Input message incorrect size"); diff --git a/jdk/src/share/classes/java/awt/Component.java b/jdk/src/share/classes/java/awt/Component.java index 42e422d3e93..3bfb115c15e 100644 --- a/jdk/src/share/classes/java/awt/Component.java +++ b/jdk/src/share/classes/java/awt/Component.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -8994,7 +8994,10 @@ public abstract class Component implements ImageObserver, MenuContainer, * to the individual objects which extend Component. */ - AccessibleContext accessibleContext = null; + /** + * The {@code AccessibleContext} associated with this {@code Component}. + */ + protected AccessibleContext accessibleContext = null; /** * Gets the AccessibleContext associated @@ -9034,6 +9037,13 @@ public abstract class Component implements ImageObserver, MenuContainer, protected AccessibleAWTComponent() { } + /** + * Number of PropertyChangeListener objects registered. It's used + * to add/remove ComponentListener and FocusListener to track + * target Component's state. + */ + private volatile transient int propertyListenersCount = 0; + protected ComponentListener accessibleAWTComponentHandler = null; protected FocusListener accessibleAWTFocusHandler = null; @@ -9098,10 +9108,12 @@ public abstract class Component implements ImageObserver, MenuContainer, public void addPropertyChangeListener(PropertyChangeListener listener) { if (accessibleAWTComponentHandler == null) { accessibleAWTComponentHandler = new AccessibleAWTComponentHandler(); - Component.this.addComponentListener(accessibleAWTComponentHandler); } if (accessibleAWTFocusHandler == null) { accessibleAWTFocusHandler = new AccessibleAWTFocusHandler(); + } + if (propertyListenersCount++ == 0) { + Component.this.addComponentListener(accessibleAWTComponentHandler); Component.this.addFocusListener(accessibleAWTFocusHandler); } super.addPropertyChangeListener(listener); @@ -9115,13 +9127,9 @@ public abstract class Component implements ImageObserver, MenuContainer, * @param listener The PropertyChangeListener to be removed */ public void removePropertyChangeListener(PropertyChangeListener listener) { - if (accessibleAWTComponentHandler != null) { + if (--propertyListenersCount == 0) { Component.this.removeComponentListener(accessibleAWTComponentHandler); - accessibleAWTComponentHandler = null; - } - if (accessibleAWTFocusHandler != null) { Component.this.removeFocusListener(accessibleAWTFocusHandler); - accessibleAWTFocusHandler = null; } super.removePropertyChangeListener(listener); } diff --git a/jdk/src/share/classes/java/awt/Container.java b/jdk/src/share/classes/java/awt/Container.java index 78af6b10c62..1118852f0e9 100644 --- a/jdk/src/share/classes/java/awt/Container.java +++ b/jdk/src/share/classes/java/awt/Container.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -3824,6 +3824,12 @@ public class Container extends Component { return Container.this.getAccessibleAt(p); } + /** + * Number of PropertyChangeListener objects registered. It's used + * to add/remove ContainerListener to track target Container's state. + */ + private volatile transient int propertyListenersCount = 0; + protected ContainerListener accessibleContainerHandler = null; /** @@ -3859,11 +3865,27 @@ public class Container extends Component { public void addPropertyChangeListener(PropertyChangeListener listener) { if (accessibleContainerHandler == null) { accessibleContainerHandler = new AccessibleContainerHandler(); + } + if (propertyListenersCount++ == 0) { Container.this.addContainerListener(accessibleContainerHandler); } super.addPropertyChangeListener(listener); } + /** + * Remove a PropertyChangeListener from the listener list. + * This removes a PropertyChangeListener that was registered + * for all properties. + * + * @param listener the PropertyChangeListener to be removed + */ + public void removePropertyChangeListener(PropertyChangeListener listener) { + if (--propertyListenersCount == 0) { + Container.this.removeContainerListener(accessibleContainerHandler); + } + super.removePropertyChangeListener(listener); + } + } // inner class AccessibleAWTContainer /** diff --git a/jdk/src/share/classes/java/awt/EventDispatchThread.java b/jdk/src/share/classes/java/awt/EventDispatchThread.java index 427ad7efeb7..c707f02abdb 100644 --- a/jdk/src/share/classes/java/awt/EventDispatchThread.java +++ b/jdk/src/share/classes/java/awt/EventDispatchThread.java @@ -107,34 +107,6 @@ class EventDispatchThread extends Thread { } } - // MacOSX change: - // This was added because this class (and java.awt.Conditional) are package private. - // There are certain instances where classes in other packages need to block the - // AWTEventQueue while still allowing it to process events. This uses reflection - // to call back into the caller in order to remove dependencies. - // - // NOTE: This uses reflection in its implementation, so it is not for performance critical code. - // - // cond is an instance of sun.lwawt.macosx.EventDispatchAccess - // - private Conditional _macosxGetConditional(final Object cond) { - try { - return new Conditional() { - final Method evaluateMethod = Class.forName("sun.lwawt.macosx.EventDispatchAccess").getMethod("evaluate", null); - public boolean evaluate() { - try { - return ((Boolean)evaluateMethod.invoke(cond, null)).booleanValue(); - } catch (Exception e) { - return false; - } - } - }; - } catch (Exception e) { - return new Conditional() { public boolean evaluate() { return false; } }; - } - } - - void pumpEvents(Conditional cond) { pumpEvents(ANY_EVENT, cond); } diff --git a/jdk/src/share/classes/java/io/Closeable.java b/jdk/src/share/classes/java/io/Closeable.java index 26c7ea00e36..530cde86171 100644 --- a/jdk/src/share/classes/java/io/Closeable.java +++ b/jdk/src/share/classes/java/io/Closeable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ import java.io.IOException; * * @since 1.5 */ - +@FunctionalInterface public interface Closeable extends AutoCloseable { /** diff --git a/jdk/src/share/classes/java/io/FileFilter.java b/jdk/src/share/classes/java/io/FileFilter.java index 15f00d630d3..f973d77cea7 100644 --- a/jdk/src/share/classes/java/io/FileFilter.java +++ b/jdk/src/share/classes/java/io/FileFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2002, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ package java.io; * * @since 1.2 */ +@FunctionalInterface public interface FileFilter { /** @@ -46,5 +47,4 @@ public interface FileFilter { * should be included */ boolean accept(File pathname); - } diff --git a/jdk/src/share/classes/java/io/FilenameFilter.java b/jdk/src/share/classes/java/io/FilenameFilter.java index 915adf54097..71b88af4646 100644 --- a/jdk/src/share/classes/java/io/FilenameFilter.java +++ b/jdk/src/share/classes/java/io/FilenameFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,8 +39,8 @@ package java.io; * @see java.io.File#list(java.io.FilenameFilter) * @since JDK1.0 */ -public -interface FilenameFilter { +@FunctionalInterface +public interface FilenameFilter { /** * Tests if a specified file should be included in a file list. * diff --git a/jdk/src/share/classes/java/io/Flushable.java b/jdk/src/share/classes/java/io/Flushable.java index e598ea88426..8912316d4d2 100644 --- a/jdk/src/share/classes/java/io/Flushable.java +++ b/jdk/src/share/classes/java/io/Flushable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ import java.io.IOException; * * @since 1.5 */ - +@FunctionalInterface public interface Flushable { /** diff --git a/jdk/src/share/classes/java/lang/AutoCloseable.java b/jdk/src/share/classes/java/lang/AutoCloseable.java index d928a9d0f1c..ce0fffe5939 100644 --- a/jdk/src/share/classes/java/lang/AutoCloseable.java +++ b/jdk/src/share/classes/java/lang/AutoCloseable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ package java.lang; * @author Josh Bloch * @since 1.7 */ +@FunctionalInterface public interface AutoCloseable { /** * Closes this resource, relinquishing any underlying resources. diff --git a/jdk/src/share/classes/java/lang/Class.java b/jdk/src/share/classes/java/lang/Class.java index 094f0cf26d6..671d04a65c7 100644 --- a/jdk/src/share/classes/java/lang/Class.java +++ b/jdk/src/share/classes/java/lang/Class.java @@ -29,12 +29,14 @@ import java.lang.reflect.Array; import java.lang.reflect.GenericArrayType; import java.lang.reflect.Member; import java.lang.reflect.Field; +import java.lang.reflect.Executable; import java.lang.reflect.Method; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.AnnotatedType; import java.lang.ref.SoftReference; import java.io.InputStream; import java.io.ObjectStreamField; @@ -2325,6 +2327,11 @@ public final // Annotations handling private native byte[] getRawAnnotations(); + // Since 1.8 + native byte[] getRawTypeAnnotations(); + static byte[] getExecutableTypeAnnotationBytes(Executable ex) { + return getReflectionFactory().getExecutableTypeAnnotationBytes(ex); + } native ConstantPool getConstantPool(); @@ -3068,28 +3075,20 @@ public final * @throws NullPointerException {@inheritDoc} * @since 1.5 */ + @SuppressWarnings("unchecked") public A getAnnotation(Class annotationClass) { Objects.requireNonNull(annotationClass); initAnnotationsIfNecessary(); - return AnnotationSupport.getOneAnnotation(annotations, annotationClass); - } - - /** - * @throws NullPointerException {@inheritDoc} - * @since 1.5 - */ - public boolean isAnnotationPresent(Class annotationClass) { - Objects.requireNonNull(annotationClass); - - return getAnnotation(annotationClass) != null; + return (A) annotations.get(annotationClass); } /** * @throws NullPointerException {@inheritDoc} * @since 1.8 */ - public A[] getAnnotations(Class annotationClass) { + @Override + public A[] getAnnotationsByType(Class annotationClass) { Objects.requireNonNull(annotationClass); initAnnotationsIfNecessary(); @@ -3101,25 +3100,28 @@ public final */ public Annotation[] getAnnotations() { initAnnotationsIfNecessary(); - return AnnotationSupport.unpackToArray(annotations); + return AnnotationParser.toArray(annotations); } /** * @throws NullPointerException {@inheritDoc} * @since 1.8 */ + @Override + @SuppressWarnings("unchecked") public A getDeclaredAnnotation(Class annotationClass) { Objects.requireNonNull(annotationClass); initAnnotationsIfNecessary(); - return AnnotationSupport.getOneAnnotation(declaredAnnotations, annotationClass); + return (A) declaredAnnotations.get(annotationClass); } /** * @throws NullPointerException {@inheritDoc} * @since 1.8 */ - public A[] getDeclaredAnnotations(Class annotationClass) { + @Override + public A[] getDeclaredAnnotationsByType(Class annotationClass) { Objects.requireNonNull(annotationClass); initAnnotationsIfNecessary(); @@ -3131,17 +3133,7 @@ public final */ public Annotation[] getDeclaredAnnotations() { initAnnotationsIfNecessary(); - return AnnotationSupport.unpackToArray(declaredAnnotations); - } - - /** Returns one "directly" present annotation or null */ - A getDirectDeclaredAnnotation(Class annotationClass) { - Objects.requireNonNull(annotationClass); - - initAnnotationsIfNecessary(); - @SuppressWarnings("unchecked") // TODO check safe - A ret = (A)declaredAnnotations.get(annotationClass); - return ret; + return AnnotationParser.toArray(declaredAnnotations); } // Annotations cache @@ -3196,4 +3188,53 @@ public final * Maintained by the ClassValue class. */ transient ClassValue.ClassValueMap classValueMap; + + /** + * Returns an AnnotatedType object that represents the use of a type to specify + * the superclass of the entity represented by this Class. (The use of type + * Foo to specify the superclass in '... extends Foo' is distinct from the + * declaration of type Foo.) + * + * If this Class represents a class type whose declaration does not explicitly + * indicate an annotated superclass, the return value is null. + * + * If this Class represents either the Object class, an interface type, an + * array type, a primitive type, or void, the return value is null. + * + * @since 1.8 + */ + public AnnotatedType getAnnotatedSuperclass() { + return TypeAnnotationParser.buildAnnotatedSuperclass(getRawTypeAnnotations(), getConstantPool(), this); +} + + /** + * Returns an array of AnnotatedType objects that represent the use of types to + * specify superinterfaces of the entity represented by this Class. (The use + * of type Foo to specify a superinterface in '... implements Foo' is + * distinct from the declaration of type Foo.) + * + * If this Class represents a class, the return value is an array + * containing objects representing the uses of interface types to specify + * interfaces implemented by the class. The order of the objects in the + * array corresponds to the order of the interface types used in the + * 'implements' clause of the declaration of this Class. + * + * If this Class represents an interface, the return value is an array + * containing objects representing the uses of interface types to specify + * interfaces directly extended by the interface. The order of the objects in + * the array corresponds to the order of the interface types used in the + * 'extends' clause of the declaration of this Class. + * + * If this Class represents a class or interface whose declaration does not + * explicitly indicate any annotated superinterfaces, the return value is an + * array of length 0. + * + * If this Class represents either the Object class, an array type, a + * primitive type, or void, the return value is an array of length 0. + * + * @since 1.8 + */ + public AnnotatedType[] getAnnotatedInterfaces() { + return TypeAnnotationParser.buildAnnotatedInterfaces(getRawTypeAnnotations(), getConstantPool(), this); + } } diff --git a/jdk/src/share/classes/java/lang/Comparable.java b/jdk/src/share/classes/java/lang/Comparable.java index d8531972bb3..123e10aa4da 100644 --- a/jdk/src/share/classes/java/lang/Comparable.java +++ b/jdk/src/share/classes/java/lang/Comparable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -93,7 +93,7 @@ import java.util.*; * @see java.util.Comparator * @since 1.2 */ - +@FunctionalInterface public interface Comparable { /** * Compares this object with the specified object for order. Returns a diff --git a/jdk/src/share/classes/java/lang/Double.java b/jdk/src/share/classes/java/lang/Double.java index f79980f4bb8..9bdb0ca4679 100644 --- a/jdk/src/share/classes/java/lang/Double.java +++ b/jdk/src/share/classes/java/lang/Double.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 @@ -289,7 +289,7 @@ public final class Double extends Number implements Comparable { return Double.toString(d); else { // Initialized to maximum size of output. - StringBuffer answer = new StringBuffer(24); + StringBuilder answer = new StringBuilder(24); if (Math.copySign(1.0, d) == -1.0) // value is negative, answer.append("-"); // so append sign info @@ -300,8 +300,7 @@ public final class Double extends Number implements Comparable { if(d == 0.0) { answer.append("0.0p0"); - } - else { + } else { boolean subnormal = (d < DoubleConsts.MIN_NORMAL); // Isolate significand bits and OR in a high-order bit @@ -324,13 +323,14 @@ public final class Double extends Number implements Comparable { "0": signif.replaceFirst("0{1,12}$", "")); + answer.append('p'); // If the value is subnormal, use the E_min exponent // value for double; otherwise, extract and report d's // exponent (the representation of a subnormal uses // E_min -1). - answer.append("p" + (subnormal ? - DoubleConsts.MIN_EXPONENT: - Math.getExponent(d) )); + answer.append(subnormal ? + DoubleConsts.MIN_EXPONENT: + Math.getExponent(d)); } return answer.toString(); } diff --git a/jdk/src/share/classes/java/lang/Iterable.java b/jdk/src/share/classes/java/lang/Iterable.java index 24efc8644af..a47319243f0 100644 --- a/jdk/src/share/classes/java/lang/Iterable.java +++ b/jdk/src/share/classes/java/lang/Iterable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ import java.util.Iterator; * * @since 1.5 */ +@FunctionalInterface public interface Iterable { /** diff --git a/jdk/src/share/classes/java/lang/Package.java b/jdk/src/share/classes/java/lang/Package.java index 744a292d6ee..b9776f478db 100644 --- a/jdk/src/share/classes/java/lang/Package.java +++ b/jdk/src/share/classes/java/lang/Package.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 @@ -385,21 +385,13 @@ public class Package implements java.lang.reflect.AnnotatedElement { return getPackageInfo().getAnnotation(annotationClass); } - /** - * @throws NullPointerException {@inheritDoc} - * @since 1.5 - */ - public boolean isAnnotationPresent( - Class annotationClass) { - return getPackageInfo().isAnnotationPresent(annotationClass); - } - /** * @throws NullPointerException {@inheritDoc} * @since 1.8 */ - public A[] getAnnotations(Class annotationClass) { - return getPackageInfo().getAnnotations(annotationClass); + @Override + public A[] getAnnotationsByType(Class annotationClass) { + return getPackageInfo().getAnnotationsByType(annotationClass); } /** @@ -413,6 +405,7 @@ public class Package implements java.lang.reflect.AnnotatedElement { * @throws NullPointerException {@inheritDoc} * @since 1.8 */ + @Override public A getDeclaredAnnotation(Class annotationClass) { return getPackageInfo().getDeclaredAnnotation(annotationClass); } @@ -421,8 +414,9 @@ public class Package implements java.lang.reflect.AnnotatedElement { * @throws NullPointerException {@inheritDoc} * @since 1.8 */ - public A[] getDeclaredAnnotations(Class annotationClass) { - return getPackageInfo().getDeclaredAnnotations(annotationClass); + @Override + public A[] getDeclaredAnnotationsByType(Class annotationClass) { + return getPackageInfo().getDeclaredAnnotationsByType(annotationClass); } /** diff --git a/jdk/src/share/classes/java/lang/Readable.java b/jdk/src/share/classes/java/lang/Readable.java index 7e4e924390e..e3d08d34b62 100644 --- a/jdk/src/share/classes/java/lang/Readable.java +++ b/jdk/src/share/classes/java/lang/Readable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ import java.io.IOException; * * @since 1.5 */ - +@FunctionalInterface public interface Readable { /** @@ -51,5 +51,4 @@ public interface Readable { * @throws java.nio.ReadOnlyBufferException if cb is a read only buffer */ public int read(java.nio.CharBuffer cb) throws IOException; - } diff --git a/jdk/src/share/classes/java/lang/Runnable.java b/jdk/src/share/classes/java/lang/Runnable.java index 6aeb8928c98..b9f1df7a0cc 100644 --- a/jdk/src/share/classes/java/lang/Runnable.java +++ b/jdk/src/share/classes/java/lang/Runnable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,8 +52,8 @@ package java.lang; * @see java.util.concurrent.Callable * @since JDK1.0 */ -public -interface Runnable { +@FunctionalInterface +public interface Runnable { /** * When an object implementing interface Runnable is used * to create a thread, starting the thread causes the object's diff --git a/jdk/src/share/classes/java/lang/System.java b/jdk/src/share/classes/java/lang/System.java index a6206e60391..45ea7190ae8 100644 --- a/jdk/src/share/classes/java/lang/System.java +++ b/jdk/src/share/classes/java/lang/System.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 @@ -25,7 +25,7 @@ package java.lang; import java.io.*; -import java.lang.annotation.Annotation; +import java.lang.reflect.Executable; import java.util.Properties; import java.util.PropertyPermission; import java.util.StringTokenizer; @@ -1196,8 +1196,11 @@ public final class System { public AnnotationType getAnnotationType(Class klass) { return klass.getAnnotationType(); } - public A getDirectDeclaredAnnotation(Class klass, Class anno) { - return klass.getDirectDeclaredAnnotation(anno); + public byte[] getRawClassTypeAnnotations(Class klass) { + return klass.getRawTypeAnnotations(); + } + public byte[] getRawExecutableTypeAnnotations(Executable executable) { + return Class.getExecutableTypeAnnotationBytes(executable); } public > E[] getEnumConstantsShared(Class klass) { diff --git a/jdk/src/share/classes/java/lang/Thread.java b/jdk/src/share/classes/java/lang/Thread.java index 64987bdc2fa..8aab573ded7 100644 --- a/jdk/src/share/classes/java/lang/Thread.java +++ b/jdk/src/share/classes/java/lang/Thread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1851,6 +1851,7 @@ class Thread implements Runnable { * @see ThreadGroup#uncaughtException * @since 1.5 */ + @FunctionalInterface public interface UncaughtExceptionHandler { /** * Method invoked when the given thread terminates due to the diff --git a/jdk/src/share/classes/java/lang/annotation/ContainedBy.java b/jdk/src/share/classes/java/lang/annotation/ContainedBy.java deleted file mode 100644 index 4f032863791..00000000000 --- a/jdk/src/share/classes/java/lang/annotation/ContainedBy.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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. - */ - -package java.lang.annotation; - -/** - * The annotation type {@code java.lang.annotation.ContainedBy} is - * used to indicate that the annotation type whose declaration it - * (meta-)annotates is repeatable. The value of - * {@code @ContainedBy} indicates the containing annotation - * type for the repeatable annotation type. - * - *

    The pair of annotation types {@code @ContainedBy} and - * {@link java.lang.annotation.ContainerFor @ContainerFor} are used to - * indicate that annotation types are repeatable. Specifically: - * - *

    - * - *

    - * An inconsistent pair of {@code @ContainedBy} and - * {@code @ContainerFor} annotations on a repeatable annotation type - * and its containing annotation type (JLS 9.6) will lead to - * compile-time errors and runtime exceptions when using reflection to - * read annotations of a repeatable type. - * - * @see java.lang.annotation.ContainerFor - * @since 1.8 - * @jls 9.6 Annotation Types - * @jls 9.7 Annotations - */ -@Documented -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.ANNOTATION_TYPE) -public @interface ContainedBy { - /** - * Indicates the containing annotation type for the - * repeatable annotation type. - */ - Class value(); -} diff --git a/jdk/src/share/classes/java/lang/annotation/ContainerFor.java b/jdk/src/share/classes/java/lang/annotation/ContainerFor.java deleted file mode 100644 index 62f3446e021..00000000000 --- a/jdk/src/share/classes/java/lang/annotation/ContainerFor.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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. - */ - -package java.lang.annotation; - -/** - * The annotation type {@code java.lang.annotation.ContainerFor} is - * used to indicate that the annotation type whose declaration it - * (meta-)annotates is a containing annotation type. The - * value of {@code @ContainerFor} indicates the repeatable - * annotation type for the containing annotation type. - * - *

    The pair of annotation types {@link - * java.lang.annotation.ContainedBy @ContainedBy} and - * {@code @ContainerFor} are used to indicate that annotation types - * are repeatable. Specifically: - * - *

      - *
    • The annotation type {@code @ContainedBy} is used on the - * declaration of a repeatable annotation type (JLS 9.6) to indicate - * its containing annotation type. - * - *
    • The annotation type {@code @ContainerFor} is used on the - * declaration of a containing annotation type (JLS 9.6) to indicate - * the repeatable annotation type for which it serves as the - * containing annotation type. - *
    - * - *

    - * An inconsistent pair of {@code @ContainedBy} and - * {@code @ContainerFor} annotations on a repeatable annotation type - * and its containing annotation type (JLS 9.6) will lead to - * compile-time errors and runtime exceptions when using reflection to - * read annotations of a repeatable type. - * - * @see java.lang.annotation.ContainedBy - * @since 1.8 - * @jls 9.6 Annotation Types - * @jls 9.7 Annotations - */ -@Documented -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.ANNOTATION_TYPE) -public @interface ContainerFor { - - /** - * Indicates the repeatable annotation type for the containing - * annotation type. - */ - Class value(); -} diff --git a/jdk/src/share/classes/java/lang/annotation/InvalidContainerAnnotationError.java b/jdk/src/share/classes/java/lang/annotation/InvalidContainerAnnotationError.java index b24e3034179..37d00a98b40 100644 --- a/jdk/src/share/classes/java/lang/annotation/InvalidContainerAnnotationError.java +++ b/jdk/src/share/classes/java/lang/annotation/InvalidContainerAnnotationError.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 @@ -27,10 +27,9 @@ package java.lang.annotation; import java.util.Objects; /** - * Thrown to indicate that an annotation type whose declaration is - * (meta-)annotated with a {@link ContainerFor} annotation is not, in - * fact, the containing annotation type of the type named by {@link - * ContainerFor}. + * Thrown to indicate that an annotation type expected to act as a + * container for another annotation type by virture of an @Repeatable + * annotation, does not act as a container. * * @see java.lang.reflect.AnnotatedElement * @since 1.8 diff --git a/jdk/src/share/classes/java/lang/reflect/AccessibleObject.java b/jdk/src/share/classes/java/lang/reflect/AccessibleObject.java index baaec298a85..d198d939d4b 100644 --- a/jdk/src/share/classes/java/lang/reflect/AccessibleObject.java +++ b/jdk/src/share/classes/java/lang/reflect/AccessibleObject.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -180,19 +180,12 @@ public class AccessibleObject implements AnnotatedElement { throw new AssertionError("All subclasses should override this method"); } - /** - * @throws NullPointerException {@inheritDoc} - * @since 1.5 - */ - public boolean isAnnotationPresent(Class annotationClass) { - return getAnnotation(annotationClass) != null; - } - /** * @throws NullPointerException {@inheritDoc} * @since 1.8 */ - public T[] getAnnotations(Class annotationClass) { + @Override + public T[] getAnnotationsByType(Class annotationClass) { throw new AssertionError("All subclasses should override this method"); } @@ -207,6 +200,7 @@ public class AccessibleObject implements AnnotatedElement { * @throws NullPointerException {@inheritDoc} * @since 1.8 */ + @Override public T getDeclaredAnnotation(Class annotationClass) { // Only annotations on classes are inherited, for all other // objects getDeclaredAnnotation is the same as @@ -218,11 +212,12 @@ public class AccessibleObject implements AnnotatedElement { * @throws NullPointerException {@inheritDoc} * @since 1.8 */ - public T[] getDeclaredAnnotations(Class annotationClass) { + @Override + public T[] getDeclaredAnnotationsByType(Class annotationClass) { // Only annotations on classes are inherited, for all other - // objects getDeclaredAnnotations is the same as - // getAnnotations. - return getAnnotations(annotationClass); + // objects getDeclaredAnnotationsByType is the same as + // getAnnotationsByType. + return getAnnotationsByType(annotationClass); } /** diff --git a/jdk/src/share/classes/java/lang/reflect/AnnotatedArrayType.java b/jdk/src/share/classes/java/lang/reflect/AnnotatedArrayType.java new file mode 100644 index 00000000000..e84a3360fdd --- /dev/null +++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedArrayType.java @@ -0,0 +1,43 @@ +/* + * 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. + */ + +package java.lang.reflect; + + +/** + * AnnotatedArrayType represents the use of an array type, whose component + * type may itself represent the annotated use of a type. + * + * @since 1.8 + */ +public interface AnnotatedArrayType extends AnnotatedType { + + /** + * Returns the annotated generic component type of this array type. + * + * @return the annotated generic component type of this array type + */ + AnnotatedType getAnnotatedGenericComponentType(); +} diff --git a/jdk/src/share/classes/java/lang/reflect/AnnotatedElement.java b/jdk/src/share/classes/java/lang/reflect/AnnotatedElement.java index 58a07350f36..d6cffec2f28 100644 --- a/jdk/src/share/classes/java/lang/reflect/AnnotatedElement.java +++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedElement.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 @@ -35,6 +35,45 @@ import java.lang.annotation.Annotation; * arrays returned by accessors for array-valued enum members; it will * have no affect on the arrays returned to other callers. * + *

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

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

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

      + *

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

    If an annotation returned by a method in this interface contains * (directly or indirectly) a {@link Class}-valued member referring to * a class that is not accessible in this VM, attempting to read the class @@ -50,7 +89,7 @@ import java.lang.annotation.Annotation; * containing annotation type of T will result in an * InvalidContainerAnnotationError. * - *

    Finally, Attempting to read a member whose definition has evolved + *

    Finally, attempting to read a member whose definition has evolved * incompatibly will result in a {@link * java.lang.annotation.AnnotationTypeMismatchException} or an * {@link java.lang.annotation.IncompleteAnnotationException}. @@ -70,6 +109,12 @@ public interface AnnotatedElement { * is present on this element, else false. This method * is designed primarily for convenient access to marker annotations. * + *

    The truth value returned by this method is equivalent to: + * {@code getAnnotation(annotationClass) != null} + * + *

    The body of the default method is specified to be the code + * above. + * * @param annotationClass the Class object corresponding to the * annotation type * @return true if an annotation for the specified annotation @@ -77,7 +122,9 @@ public interface AnnotatedElement { * @throws NullPointerException if the given annotation class is null * @since 1.5 */ - boolean isAnnotationPresent(Class annotationClass); + default boolean isAnnotationPresent(Class annotationClass) { + return getAnnotation(annotationClass) != null; + } /** * Returns this element's annotation for the specified type if @@ -93,12 +140,19 @@ public interface AnnotatedElement { T getAnnotation(Class annotationClass); /** - * Returns an array of all this element's annotations for the - * specified type if one or more of such annotation is present, - * else an array of length zero. + * Returns annotations that are present on this element. * - * The caller of this method is free to modify the returned array; - * it will have no effect on the arrays returned to other callers. + * If there are no annotations present on this element, the return + * value is an array of length 0. + * + * The difference between this method and {@link #getAnnotation(Class)} + * is that this method detects if its argument is a repeatable + * annotation type (JLS 9.6), and if so, attempts to find one or + * more annotations of that type by "looking through" a container + * annotation. + * + * The caller of this method is free to modify the returned array; it will + * have no effect on the arrays returned to other callers. * * @param annotationClass the Class object corresponding to the * annotation type @@ -107,15 +161,18 @@ public interface AnnotatedElement { * @throws NullPointerException if the given annotation class is null * @since 1.8 */ - T[] getAnnotations(Class annotationClass); + T[] getAnnotationsByType(Class annotationClass); /** - * Returns all annotations present on this element. (Returns an array - * of length zero if this element has no annotations.) The caller of - * this method is free to modify the returned array; it will have no - * effect on the arrays returned to other callers. + * Returns annotations that are present on this element. * - * @return all annotations present on this element + * If there are no annotations present on this element, the return + * value is an array of length 0. + * + * The caller of this method is free to modify the returned array; it will + * have no effect on the arrays returned to other callers. + * + * @return annotations present on this element * @since 1.5 */ Annotation[] getAnnotations(); @@ -136,16 +193,21 @@ public interface AnnotatedElement { */ T getDeclaredAnnotation(Class annotationClass); - /** - * Returns an array of all this element's annotations for the - * specified type if one or more of such annotation is directly - * present, else an array of length zero. + /** + * Returns annotations that are directly present on this element. + * This method ignores inherited annotations. * - * This method ignores inherited annotations. (Returns - * an array of length zero if no annotations are directly present - * on this element.) The caller of this method is free to modify - * the returned array; it will have no effect on the arrays - * returned to other callers. + * If there are no annotations directly present on this element, + * the return value is an array of length 0. + * + * The difference between this method and {@link + * #getDeclaredAnnotation(Class)} is that this method detects if its + * argument is a repeatable annotation type (JLS 9.6), and if so, + * attempts to find one or more annotations of that type by "looking + * through" a container annotation. + * + * The caller of this method is free to modify the returned array; it will + * have no effect on the arrays returned to other callers. * * @param annotationClass the Class object corresponding to the * annotation type @@ -154,17 +216,19 @@ public interface AnnotatedElement { * @throws NullPointerException if the given annotation class is null * @since 1.8 */ - T[] getDeclaredAnnotations(Class annotationClass); + T[] getDeclaredAnnotationsByType(Class annotationClass); /** - * Returns all annotations that are directly present on this - * element. This method ignores inherited annotations. (Returns - * an array of length zero if no annotations are directly present - * on this element.) The caller of this method is free to modify - * the returned array; it will have no effect on the arrays - * returned to other callers. + * Returns annotations that are directly present on this element. + * This method ignores inherited annotations. * - * @return All annotations directly present on this element + * If there are no annotations directly present on this element, + * the return value is an array of length 0. + * + * The caller of this method is free to modify the returned array; it will + * have no effect on the arrays returned to other callers. + * + * @return annotations directly present on this element * @since 1.5 */ Annotation[] getDeclaredAnnotations(); diff --git a/jdk/src/share/classes/java/lang/reflect/AnnotatedParameterizedType.java b/jdk/src/share/classes/java/lang/reflect/AnnotatedParameterizedType.java new file mode 100644 index 00000000000..4fa089e318c --- /dev/null +++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedParameterizedType.java @@ -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. + */ + +package java.lang.reflect; + +/** + * AnnotatedParameterizedType represents the use of a parameterized type, + * whose type arguments may themselves represent annotated uses of types. + * + * @since 1.8 + */ +public interface AnnotatedParameterizedType extends AnnotatedType { + + /** + * Returns the annotated actual type arguments of this parameterized type. + * + * @return the annotated actual type arguments of this parameterized type + */ + AnnotatedType[] getAnnotatedActualTypeArguments(); +} diff --git a/jdk/src/share/classes/java/lang/reflect/AnnotatedType.java b/jdk/src/share/classes/java/lang/reflect/AnnotatedType.java new file mode 100644 index 00000000000..d1ee79f14f4 --- /dev/null +++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedType.java @@ -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. + */ + +package java.lang.reflect; + +/** + * AnnotatedType represents the annotated use of a type in the program + * currently running in this VM. The use may be of any type in the Java + * programming language, including an array type, a parameterized type, a type + * variable, or a wildcard type. + * + * @since 1.8 + */ +public interface AnnotatedType extends AnnotatedElement { + + /** + * Returns the underlying type that this annotated type represents. + * + * @return the type this annotated type represents + */ + public Type getType(); +} diff --git a/jdk/src/share/classes/java/lang/reflect/AnnotatedTypeVariable.java b/jdk/src/share/classes/java/lang/reflect/AnnotatedTypeVariable.java new file mode 100644 index 00000000000..3580a14442f --- /dev/null +++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedTypeVariable.java @@ -0,0 +1,43 @@ +/* + * 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. + */ + +package java.lang.reflect; + +/** + * AnnotatedTypeVariable represents the use of a type variable, whose + * declaration may have bounds which themselves represent annotated uses of + * types. + * + * @since 1.8 + */ +public interface AnnotatedTypeVariable extends AnnotatedType { + + /** + * Returns the annotated bounds of this type variable. + * + * @return the annotated bounds of this type variable + */ + AnnotatedType[] getAnnotatedBounds(); +} diff --git a/jdk/src/share/classes/java/lang/reflect/AnnotatedWildcardType.java b/jdk/src/share/classes/java/lang/reflect/AnnotatedWildcardType.java new file mode 100644 index 00000000000..c357eb9d0bc --- /dev/null +++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedWildcardType.java @@ -0,0 +1,49 @@ +/* + * 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. + */ + +package java.lang.reflect; + +/** + * AnnotatedWildcardType represents the use of a wildcard type argument, whose + * upper or lower bounds may themselves represent annotated uses of types. + * + * @since 1.8 + */ +public interface AnnotatedWildcardType extends AnnotatedType { + + /** + * Returns the annotated lower bounds of this wildcard type. + * + * @return the annotated lower bounds of this wildcard type + */ + AnnotatedType[] getAnnotatedLowerBounds(); + + /** + * Returns the annotated upper bounds of this wildcard type. + * + * @return the annotated upper bounds of this wildcard type + */ + AnnotatedType[] getAnnotatedUpperBounds(); +} diff --git a/jdk/src/share/classes/java/lang/reflect/Constructor.java b/jdk/src/share/classes/java/lang/reflect/Constructor.java index 1973e820950..bbfd1d5ab9d 100644 --- a/jdk/src/share/classes/java/lang/reflect/Constructor.java +++ b/jdk/src/share/classes/java/lang/reflect/Constructor.java @@ -154,6 +154,10 @@ public final class Constructor extends Executable { byte[] getAnnotationBytes() { return annotations; } + @Override + byte[] getTypeAnnotationBytes() { + return typeAnnotations; + } /** * {@inheritDoc} @@ -523,4 +527,12 @@ public final class Constructor extends Executable { } } } + + /** + * {@inheritDoc} + * @since 1.8 + */ + public AnnotatedType getAnnotatedReturnType() { + return getAnnotatedReturnType0(getDeclaringClass()); + } } diff --git a/jdk/src/share/classes/java/lang/reflect/Executable.java b/jdk/src/share/classes/java/lang/reflect/Executable.java index f2befd2dcdd..83b5e9c87a4 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) 2013, 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 @@ -26,11 +26,12 @@ package java.lang.reflect; import java.lang.annotation.*; -import java.util.Collections; import java.util.Map; import java.util.Objects; import sun.reflect.annotation.AnnotationParser; import sun.reflect.annotation.AnnotationSupport; +import sun.reflect.annotation.TypeAnnotationParser; +import sun.reflect.annotation.TypeAnnotation; import sun.reflect.generics.repository.ConstructorRepository; /** @@ -50,6 +51,7 @@ public abstract class Executable extends AccessibleObject * Accessor method to allow code sharing */ abstract byte[] getAnnotationBytes(); + abstract byte[] getTypeAnnotationBytes(); /** * Does the Executable have generic information. @@ -276,6 +278,10 @@ public abstract class Executable extends AccessibleObject * this object. Returns an array of length 0 if the executable * has no parameters. * + * The parameters of the underlying executable do not necessarily + * have unique names, or names that are legal identifiers in the + * Java programming language (JLS 3.8). + * * @return an array of {@code Parameter} objects representing all * the parameters to the executable this object represents */ @@ -435,8 +441,7 @@ public abstract class Executable extends AccessibleObject */ public T getAnnotation(Class annotationClass) { Objects.requireNonNull(annotationClass); - - return AnnotationSupport.getOneAnnotation(declaredAnnotations(), annotationClass); + return annotationClass.cast(declaredAnnotations().get(annotationClass)); } /** @@ -444,7 +449,8 @@ public abstract class Executable extends AccessibleObject * @throws NullPointerException {@inheritDoc} * @since 1.8 */ - public T[] getAnnotations(Class annotationClass) { + @Override + public T[] getAnnotationsByType(Class annotationClass) { Objects.requireNonNull(annotationClass); return AnnotationSupport.getMultipleAnnotations(declaredAnnotations(), annotationClass); @@ -454,7 +460,7 @@ public abstract class Executable extends AccessibleObject * {@inheritDoc} */ public Annotation[] getDeclaredAnnotations() { - return AnnotationSupport.unpackToArray(declaredAnnotations()); + return AnnotationParser.toArray(declaredAnnotations()); } private transient Map, Annotation> declaredAnnotations; @@ -470,4 +476,86 @@ public abstract class Executable extends AccessibleObject return declaredAnnotations; } + + /* Helper for subclasses of Executable. + * + * Returns an AnnotatedType object that represents the use of a type to + * specify the return type of the method/constructor represented by this + * Executable. + * + * @since 1.8 + */ + AnnotatedType getAnnotatedReturnType0(Type returnType) { + return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes(), + sun.misc.SharedSecrets.getJavaLangAccess(). + getConstantPool(getDeclaringClass()), + this, + getDeclaringClass(), + returnType, + TypeAnnotation.TypeAnnotationTarget.METHOD_RETURN_TYPE); + } + + /** + * Returns an AnnotatedType object that represents the use of a type to + * specify the receiver type of the method/constructor represented by this + * Executable. The receiver type of a method/constructor is available only + * if the method/constructor declares a formal parameter called 'this'. + * + * Returns null if this Executable represents a constructor or instance + * method that either declares no formal parameter called 'this', or + * declares a formal parameter called 'this' with no annotations on its + * type. + * + * Returns null if this Executable represents a static method. + * + * @since 1.8 + */ + public AnnotatedType getAnnotatedReceiverType() { + return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes(), + sun.misc.SharedSecrets.getJavaLangAccess(). + getConstantPool(getDeclaringClass()), + this, + getDeclaringClass(), + getDeclaringClass(), + TypeAnnotation.TypeAnnotationTarget.METHOD_RECEIVER_TYPE); + } + + /** + * Returns an array of AnnotatedType objects that represent the use of + * types to specify formal parameter types of the method/constructor + * represented by this Executable. The order of the objects in the array + * corresponds to the order of the formal parameter types in the + * declaration of the method/constructor. + * + * Returns an array of length 0 if the method/constructor declares no + * parameters. + * + * @since 1.8 + */ + public AnnotatedType[] getAnnotatedParameterTypes() { + throw new UnsupportedOperationException("Not yet"); + } + + /** + * Returns an array of AnnotatedType objects that represent the use of + * types to specify the declared exceptions of the method/constructor + * represented by this Executable. The order of the objects in the array + * corresponds to the order of the exception types in the declaration of + * the method/constructor. + * + * Returns an array of length 0 if the method/constructor declares no + * exceptions. + * + * @since 1.8 + */ + public AnnotatedType[] getAnnotatedExceptionTypes() { + return TypeAnnotationParser.buildAnnotatedTypes(getTypeAnnotationBytes(), + sun.misc.SharedSecrets.getJavaLangAccess(). + getConstantPool(getDeclaringClass()), + this, + getDeclaringClass(), + getGenericExceptionTypes(), + TypeAnnotation.TypeAnnotationTarget.THROWS); + } + } diff --git a/jdk/src/share/classes/java/lang/reflect/Field.java b/jdk/src/share/classes/java/lang/reflect/Field.java index e5471459586..be13b076832 100644 --- a/jdk/src/share/classes/java/lang/reflect/Field.java +++ b/jdk/src/share/classes/java/lang/reflect/Field.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 @@ -36,7 +36,8 @@ import java.util.Map; import java.util.Objects; import sun.reflect.annotation.AnnotationParser; import sun.reflect.annotation.AnnotationSupport; - +import sun.reflect.annotation.TypeAnnotation; +import sun.reflect.annotation.TypeAnnotationParser; /** * A {@code Field} provides information about, and dynamic access to, a @@ -1020,8 +1021,7 @@ class Field extends AccessibleObject implements Member { */ public T getAnnotation(Class annotationClass) { Objects.requireNonNull(annotationClass); - - return AnnotationSupport.getOneAnnotation(declaredAnnotations(), annotationClass); + return annotationClass.cast(declaredAnnotations().get(annotationClass)); } /** @@ -1029,7 +1029,8 @@ class Field extends AccessibleObject implements Member { * @throws NullPointerException {@inheritDoc} * @since 1.8 */ - public T[] getAnnotations(Class annotationClass) { + @Override + public T[] getAnnotationsByType(Class annotationClass) { Objects.requireNonNull(annotationClass); return AnnotationSupport.getMultipleAnnotations(declaredAnnotations(), annotationClass); @@ -1039,7 +1040,7 @@ class Field extends AccessibleObject implements Member { * {@inheritDoc} */ public Annotation[] getDeclaredAnnotations() { - return AnnotationSupport.unpackToArray(declaredAnnotations()); + return AnnotationParser.toArray(declaredAnnotations()); } private transient Map, Annotation> declaredAnnotations; @@ -1053,4 +1054,20 @@ class Field extends AccessibleObject implements Member { } return declaredAnnotations; } + + /** + * Returns an AnnotatedType object that represents the use of a type to specify + * the declared type of the field represented by this Field. + * + * @since 1.8 + */ + public AnnotatedType getAnnotatedType() { + return TypeAnnotationParser.buildAnnotatedType(typeAnnotations, + sun.misc.SharedSecrets.getJavaLangAccess(). + getConstantPool(getDeclaringClass()), + this, + getDeclaringClass(), + getGenericType(), + TypeAnnotation.TypeAnnotationTarget.FIELD_TYPE); +} } diff --git a/jdk/src/share/classes/java/lang/reflect/Method.java b/jdk/src/share/classes/java/lang/reflect/Method.java index a7beb011400..1507c77194a 100644 --- a/jdk/src/share/classes/java/lang/reflect/Method.java +++ b/jdk/src/share/classes/java/lang/reflect/Method.java @@ -165,6 +165,10 @@ public final class Method extends Executable { byte[] getAnnotationBytes() { return annotations; } + @Override + byte[] getTypeAnnotationBytes() { + return typeAnnotations; + } /** * {@inheritDoc} @@ -621,6 +625,14 @@ public final class Method extends Executable { return sharedGetParameterAnnotations(parameterTypes, parameterAnnotations); } + /** + * {@inheritDoc} + * @since 1.8 + */ + public AnnotatedType getAnnotatedReturnType() { + return getAnnotatedReturnType0(getGenericReturnType()); + } + @Override void handleParameterNumberMismatch(int resultLength, int numParameters) { throw new AnnotationFormatError("Parameter annotations don't match number of parameters"); diff --git a/jdk/src/share/classes/java/lang/reflect/Modifier.java b/jdk/src/share/classes/java/lang/reflect/Modifier.java index 24cebe29f9f..8c2b2cc5f5e 100644 --- a/jdk/src/share/classes/java/lang/reflect/Modifier.java +++ b/jdk/src/share/classes/java/lang/reflect/Modifier.java @@ -342,13 +342,13 @@ class Modifier { static final int SYNTHETIC = 0x00001000; static final int ANNOTATION = 0x00002000; static final int ENUM = 0x00004000; - static final int SYNTHESIZED = 0x00010000; + static final int MANDATED = 0x00008000; static boolean isSynthetic(int mod) { return (mod & SYNTHETIC) != 0; } - static boolean isSynthesized(int mod) { - return (mod & SYNTHESIZED) != 0; + static boolean isMandated(int mod) { + return (mod & MANDATED) != 0; } /** diff --git a/jdk/src/share/classes/java/lang/reflect/Parameter.java b/jdk/src/share/classes/java/lang/reflect/Parameter.java index 6eed6926be0..9c808310c0c 100644 --- a/jdk/src/share/classes/java/lang/reflect/Parameter.java +++ b/jdk/src/share/classes/java/lang/reflect/Parameter.java @@ -44,7 +44,7 @@ public final class Parameter implements AnnotatedElement { private final String name; private final int modifiers; private final Executable executable; - private int index; + private final int index; /** * Package-private constructor for {@code Parameter}. @@ -95,9 +95,14 @@ public final class Parameter implements AnnotatedElement { } /** - * Returns a string representation of the parameter's modifiers, - * its attributes, its type, its name, and a trailing ... if it is - * a variadic parameter. + * Returns a string describing this parameter. The format is the + * modifiers for the parameter, if any, in canonical order as + * recommended by The Java™ Language + * Specification, followed by the fully- qualified type of + * the parameter (excluding the last [] if the parameter is + * variable arity), followed by "..." if the parameter is variable + * arity, followed by a space, followed by the name of the + * parameter. * * @return A string representation of the parameter and associated * information. @@ -118,7 +123,7 @@ public final class Parameter implements AnnotatedElement { sb.append(typename); sb.append(" "); - sb.append(name); + sb.append(getName()); return sb.toString(); } @@ -143,11 +148,23 @@ public final class Parameter implements AnnotatedElement { } /** - * Returns the name of the parameter represented by this - * {@code Parameter} object. + * Returns the name of the parameter. The names of the parameters + * of a single executable must all the be distinct. When names + * from the originating source are available, they are returned. + * Otherwise, an implementation of this method is free to create a + * name of this parameter, subject to the unquiness requirments. */ public String getName() { - return name; + // As per the spec, if a parameter has no name, return argX, + // where x is the index. + // + // Note: spec updates now outlaw empty strings as parameter + // names. The .equals("") is for compatibility with current + // JVM behavior. It may be removed at some point. + if(name == null || name.equals("")) + return "arg" + index; + else + return name; } /** @@ -190,20 +207,21 @@ public final class Parameter implements AnnotatedElement { private transient volatile Class parameterClassCache = null; /** - * Returns {@code true} if this parameter is a synthesized - * construct; returns {@code false} otherwise. + * Returns {@code true} if this parameter is implicitly declared + * in source code; returns {@code false} otherwise. * - * @return true if and only if this parameter is a synthesized - * construct as defined by - * The Java™ Language Specification. + * @return true if and only if this parameter is implicitly + * declared as defined by The Java™ Language + * Specification. */ - public boolean isSynthesized() { - return Modifier.isSynthesized(getModifiers()); + public boolean isImplicit() { + return Modifier.isMandated(getModifiers()); } /** - * Returns {@code true} if this parameter is a synthetic - * construct; returns {@code false} otherwise. + * Returns {@code true} if this parameter is neither implicitly + * nor explicitly declared in source code; returns {@code false} + * otherwise. * * @jls 13.1 The Form of a Binary * @return true if and only if this parameter is a synthetic @@ -233,15 +251,15 @@ public final class Parameter implements AnnotatedElement { */ public T getAnnotation(Class annotationClass) { Objects.requireNonNull(annotationClass); - - return AnnotationSupport.getOneAnnotation(declaredAnnotations(), annotationClass); + return annotationClass.cast(declaredAnnotations().get(annotationClass)); } /** * {@inheritDoc} * @throws NullPointerException {@inheritDoc} */ - public T[] getAnnotations(Class annotationClass) { + @Override + public T[] getAnnotationsByType(Class annotationClass) { Objects.requireNonNull(annotationClass); return AnnotationSupport.getMultipleAnnotations(declaredAnnotations(), annotationClass); @@ -267,11 +285,12 @@ public final class Parameter implements AnnotatedElement { /** * @throws NullPointerException {@inheritDoc} */ - public T[] getDeclaredAnnotations(Class annotationClass) { + @Override + public T[] getDeclaredAnnotationsByType(Class annotationClass) { // Only annotations on classes are inherited, for all other // objects getDeclaredAnnotations is the same as // getAnnotations. - return getAnnotations(annotationClass); + return getAnnotationsByType(annotationClass); } /** @@ -281,14 +300,6 @@ public final class Parameter implements AnnotatedElement { return getDeclaredAnnotations(); } - /** - * @throws NullPointerException {@inheritDoc} - */ - public boolean isAnnotationPresent( - Class annotationClass) { - return getAnnotation(annotationClass) != null; - } - private transient Map, Annotation> declaredAnnotations; private synchronized Map, Annotation> declaredAnnotations() { diff --git a/jdk/src/share/classes/java/lang/reflect/ReflectAccess.java b/jdk/src/share/classes/java/lang/reflect/ReflectAccess.java index 80311d240e6..c3ac1557b85 100644 --- a/jdk/src/share/classes/java/lang/reflect/ReflectAccess.java +++ b/jdk/src/share/classes/java/lang/reflect/ReflectAccess.java @@ -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 @@ -128,6 +128,10 @@ class ReflectAccess implements sun.reflect.LangReflectAccess { return c.getRawParameterAnnotations(); } + public byte[] getExecutableTypeAnnotationBytes(Executable ex) { + return ex.getTypeAnnotationBytes(); + } + // // Copying routines, needed to quickly fabricate new Field, // Method, and Constructor objects from templates diff --git a/jdk/src/share/classes/java/lang/reflect/TypeVariable.java b/jdk/src/share/classes/java/lang/reflect/TypeVariable.java index b0ff7880cda..42027e0041c 100644 --- a/jdk/src/share/classes/java/lang/reflect/TypeVariable.java +++ b/jdk/src/share/classes/java/lang/reflect/TypeVariable.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 @@ -86,4 +86,16 @@ public interface TypeVariable extends Type, Annota * @return the name of this type variable, as it appears in the source code */ String getName(); + + /** + * Returns an array of AnnotatedType objects that represent the use of + * types to denote the upper bounds of the type parameter represented by + * this TypeVariable. The order of the objects in the array corresponds to + * the order of the bounds in the declaration of the type parameter. + * + * Returns an array of length 0 if the type parameter declares no bounds. + * + * @since 1.8 + */ + AnnotatedType[] getAnnotatedBounds(); } diff --git a/jdk/src/share/classes/java/math/BigDecimal.java b/jdk/src/share/classes/java/math/BigDecimal.java index d95b1cb27b3..b7f6380948e 100644 --- a/jdk/src/share/classes/java/math/BigDecimal.java +++ b/jdk/src/share/classes/java/math/BigDecimal.java @@ -3537,13 +3537,25 @@ public class BigDecimal extends Number implements Comparable { else return expandBigIntegerTenPowers(n); } - // BigInteger.pow is slow, so make 10**n by constructing a - // BigInteger from a character string (still not very fast) - char tenpow[] = new char[n + 1]; - tenpow[0] = '1'; - for (int i = 1; i <= n; i++) - tenpow[i] = '0'; - return new BigInteger(tenpow,1, tenpow.length); + + if (n < 1024*524288) { + // BigInteger.pow is slow, so make 10**n by constructing a + // BigInteger from a character string (still not very fast) + // which occupies no more than 1GB (!) of memory. + char tenpow[] = new char[n + 1]; + tenpow[0] = '1'; + for (int i = 1; i <= n; i++) { + tenpow[i] = '0'; + } + return new BigInteger(tenpow, 1, tenpow.length); + } + + if ((n & 0x1) == 0x1) { + return BigInteger.TEN.multiply(bigTenToThe(n - 1)); + } else { + BigInteger tmp = bigTenToThe(n/2); + return tmp.multiply(tmp); + } } /** diff --git a/jdk/src/share/classes/java/nio/file/DirectoryStream.java b/jdk/src/share/classes/java/nio/file/DirectoryStream.java index dd13c9a3f6b..48da97e7b4d 100644 --- a/jdk/src/share/classes/java/nio/file/DirectoryStream.java +++ b/jdk/src/share/classes/java/nio/file/DirectoryStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -117,8 +117,7 @@ import java.io.IOException; */ public interface DirectoryStream - extends Closeable, Iterable -{ + extends Closeable, Iterable { /** * An interface that is implemented by objects that decide if a directory * entry should be accepted or filtered. A {@code Filter} is passed as the @@ -130,6 +129,7 @@ public interface DirectoryStream * * @since 1.7 */ + @FunctionalInterface public static interface Filter { /** * Decides if the given directory entry should be accepted or filtered. diff --git a/jdk/src/share/classes/java/nio/file/PathMatcher.java b/jdk/src/share/classes/java/nio/file/PathMatcher.java index ab4b7ce0f00..24e61493c8b 100644 --- a/jdk/src/share/classes/java/nio/file/PathMatcher.java +++ b/jdk/src/share/classes/java/nio/file/PathMatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ package java.nio.file; * @see FileSystem#getPathMatcher * @see Files#newDirectoryStream(Path,String) */ - +@FunctionalInterface public interface PathMatcher { /** * Tells if given path matches this matcher's pattern. diff --git a/jdk/src/share/classes/java/security/KeyStore.java b/jdk/src/share/classes/java/security/KeyStore.java index 96565684b0e..75d405771a7 100644 --- a/jdk/src/share/classes/java/security/KeyStore.java +++ b/jdk/src/share/classes/java/security/KeyStore.java @@ -218,6 +218,150 @@ public class KeyStore { public ProtectionParameter getProtectionParameter(); } + /** + * Configuration data that specifies the keystores in a keystore domain. + * A keystore domain is a collection of keystores that are presented as a + * single logical keystore. The configuration data is used during + * {@code KeyStore} + * {@link #load(KeyStore.LoadStoreParameter) load} and + * {@link #store(KeyStore.LoadStoreParameter) store} operations. + *

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

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

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

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

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

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

    +     *
    +     * domain app1 {
    +     *     keystore app1-truststore
    +     *         keystoreURI="file:///app1/etc/truststore.jks"
    +     *
    +     *     keystore system-truststore
    +     *         keystoreURI="${java.home}/lib/security/cacerts"
    +     *
    +     *     keystore app1-keystore
    +     *         keystoreType="PKCS12"
    +     *         keystoreURI="file:///app1/etc/keystore.p12"
    +     * };
    +     *
    +     * 
    + * @since 1.8 + */ + public static final class DomainLoadStoreParameter + implements LoadStoreParameter { + + private final URI configuration; + private final Map protectionParams; + + /** + * Constructs a DomainLoadStoreParameter for a keystore domain with + * the parameters used to protect keystore data. + * + * @param configuration identifier for the domain configuration data. + * The name of the target domain should be specified in the + * {@code java.net.URI} fragment component when it is necessary + * to distinguish between several domain configurations at the + * same location. + * + * @param protectionParams the map from keystore name to the parameter + * used to protect keystore data. + * A {@code java.util.Collections.EMPTY_MAP} should be used + * when protection parameters are not required or when they have + * been specified by properties in the domain configuration data. + * It is cloned to prevent subsequent modification. + * + * @exception NullPointerExcetion if {@code configuration} or + * {@code protectionParams} is {@code null} + */ + public DomainLoadStoreParameter(URI configuration, + Map protectionParams) { + if (configuration == null || protectionParams == null) { + throw new NullPointerException("invalid null input"); + } + this.configuration = configuration; + this.protectionParams = + Collections.unmodifiableMap(new HashMap<>(protectionParams)); + } + + /** + * Gets the identifier for the domain configuration data. + * + * @return the identifier for the configuration data + */ + public URI getConfiguration() { + return configuration; + } + + /** + * Gets the keystore protection parameters for keystores in this + * domain. + * + * @return an unmodifiable map of keystore names to protection + * parameters + */ + public Map getProtectionParams() { + return protectionParams; + } + + /** + * Gets the keystore protection parameters for this domain. + * Keystore domains do not support a protection parameter. + * + * @return always returns {@code null} + */ + @Override + public KeyStore.ProtectionParameter getProtectionParameter() { + return null; + } + } + /** * A marker interface for keystore protection parameters. * diff --git a/jdk/src/share/classes/java/sql/Date.java b/jdk/src/share/classes/java/sql/Date.java index 4c0e6e9d23f..0133fbe87ef 100644 --- a/jdk/src/share/classes/java/sql/Date.java +++ b/jdk/src/share/classes/java/sql/Date.java @@ -25,6 +25,9 @@ package java.sql; +import java.time.Instant; +import java.time.LocalDate; + /** *

    A thin wrapper around a millisecond value that allows * JDBC to identify this as an SQL DATE value. A @@ -113,7 +116,6 @@ public class Date extends java.util.Date { int firstDash; int secondDash; Date d = null; - if (s == null) { throw new java.lang.IllegalArgumentException(); } @@ -255,4 +257,50 @@ public class Date extends java.util.Date { * compatibility. */ static final long serialVersionUID = 1511598038487230103L; + + /** + * Obtains an instance of {@code Date} from a {@link LocalDate} object + * with the same year, month and day of month value as the given + * {@code LocalDate}. + *

    + * The provided {@code LocalDate} is interpreted as the local date + * in the local time zone. + * + * @param date a {@code LocalDate} to convert + * @return a {@code Date} object + * @exception NullPointerException if {@code date} is null + * @since 1.8 + */ + @SuppressWarnings("deprecation") + public static Date valueOf(LocalDate date) { + return new Date(date.getYear() - 1900, date.getMonthValue() -1, + date.getDayOfMonth()); + } + + /** + * Converts this {@code Date} object to a {@code LocalDate} + *

    + * The conversion creates a {@code LocalDate} that represents the same + * date value as this {@code Date} in local time zone + * + * @return a {@code LocalDate} object representing the same date value + * + * @since 1.8 + */ + @SuppressWarnings("deprecation") + public LocalDate toLocalDate() { + return LocalDate.of(getYear() + 1900, getMonth() + 1, getDate()); + } + + /** + * This method always throws an UnsupportedOperationException and should + * not be used because SQL {@code Date} values do not have a time + * component. + * + * @exception java.lang.UnsupportedOperationException if this method is invoked + */ + @Override + public Instant toInstant() { + throw new java.lang.UnsupportedOperationException(); + } } diff --git a/jdk/src/share/classes/java/sql/JDBCType.java b/jdk/src/share/classes/java/sql/JDBCType.java index f1453059605..74ee8e01682 100644 --- a/jdk/src/share/classes/java/sql/JDBCType.java +++ b/jdk/src/share/classes/java/sql/JDBCType.java @@ -190,7 +190,17 @@ public enum JDBCType implements SQLType { /** * Identifies the generic SQL type {@code REF_CURSOR}. */ - REF_CURSOR(Types.REF_CURSOR); + REF_CURSOR(Types.REF_CURSOR), + + /** + * Identifies the generic SQL type {@code TIME_WITH_TIMEZONE}. + */ + TIME_WITH_TIMEZONE(Types.TIME_WITH_TIMEZONE), + + /** + * Identifies the generic SQL type {@code TIMESTAMP_WITH_TIMEZONE}. + */ + TIMESTAMP_WITH_TIMEZONE(Types.TIMESTAMP_WITH_TIMEZONE); /** * The Integer value for the JDBCType. It maps to a value in diff --git a/jdk/src/share/classes/java/sql/SQLInput.java b/jdk/src/share/classes/java/sql/SQLInput.java index c607e83cbcb..8d2540dc499 100644 --- a/jdk/src/share/classes/java/sql/SQLInput.java +++ b/jdk/src/share/classes/java/sql/SQLInput.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -421,4 +421,38 @@ public interface SQLInput { */ RowId readRowId() throws SQLException; + //--------------------------JDBC 4.2 ----------------------------- + + /** + * Reads the next attribute in the stream and returns it as an + * {@code Object} in the Java programming language. The + * actual type of the object returned is determined by the specified + * Java data type, and any customizations present in this + * stream's type map. + * + *

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

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

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

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

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

    + * The default implementation will throw {@code SQLFeatureNotSupportedException} + * + * @param x the object containing the input parameter value + * @param targetSqlType the SQL type to be sent to the database. + * @exception SQLException if a database access error occurs or + * if the Java Object specified by x is an InputStream + * or Reader object and the value of the scale parameter is less + * than zero + * @exception SQLFeatureNotSupportedException if + * the JDBC driver does not support this data type + * @see JDBCType + * @see SQLType + * @since 1.8 + */ + default void writeObject(Object x, SQLType targetSqlType) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } } + diff --git a/jdk/src/share/classes/java/sql/Time.java b/jdk/src/share/classes/java/sql/Time.java index 01f046a0927..de187e99a76 100644 --- a/jdk/src/share/classes/java/sql/Time.java +++ b/jdk/src/share/classes/java/sql/Time.java @@ -25,6 +25,9 @@ package java.sql; +import java.time.Instant; +import java.time.LocalTime; + /** *

    A thin wrapper around the java.util.Date class that allows the JDBC * API to identify this as an SQL TIME value. The Time @@ -246,4 +249,45 @@ public class Time extends java.util.Date { * compatibility. */ static final long serialVersionUID = 8397324403548013681L; + + /** + * Obtains an instance of {@code Time} from a {@link LocalTime} object + * with the same hour, minute and second time value as the given + * {@code LocalTime}. + * + * @param time a {@code LocalTime} to convert + * @return a {@code Time} object + * @exception NullPointerException if {@code time} is null + * @since 1.8 + */ + @SuppressWarnings("deprecation") + public static Time valueOf(LocalTime time) { + return new Time(time.getHour(), time.getMinute(), time.getSecond()); + } + + /** + * Converts this {@code Time} object to a {@code LocalTime}. + *

    + * The conversion creates a {@code LocalTime} that represents the same + * hour, minute, and second time value as this {@code Time}. + * + * @return a {@code LocalTime} object representing the same time value + * @since 1.8 + */ + @SuppressWarnings("deprecation") + public LocalTime toLocalTime() { + return LocalTime.of(getHours(), getMinutes(), getSeconds()); + } + + /** + * This method always throws an UnsupportedOperationException and should + * not be used because SQL {@code Time} values do not have a date + * component. + * + * @exception java.lang.UnsupportedOperationException if this method is invoked + */ + @Override + public Instant toInstant() { + throw new java.lang.UnsupportedOperationException(); + } } diff --git a/jdk/src/share/classes/java/sql/Timestamp.java b/jdk/src/share/classes/java/sql/Timestamp.java index 18b61edd6a7..afa56ee7918 100644 --- a/jdk/src/share/classes/java/sql/Timestamp.java +++ b/jdk/src/share/classes/java/sql/Timestamp.java @@ -25,6 +25,8 @@ package java.sql; +import java.time.Instant; +import java.time.LocalDateTime; import java.util.StringTokenizer; /** @@ -485,7 +487,6 @@ public class Timestamp extends java.util.Date { } } return i; - } /** @@ -530,4 +531,89 @@ public class Timestamp extends java.util.Date { static final long serialVersionUID = 2745179027874758501L; + private static final int MILLIS_PER_SECOND = 1000; + + /** + * Obtains an instance of {@code Timestamp} from a {@code LocalDateTime} + * object, with the same year, month, day of month, hours, minutes, + * seconds and nanos date-time value as the provided {@code LocalDateTime}. + *

    + * The provided {@code LocalDateTime} is interpreted as the local + * date-time in the local time zone. + * + * @param dateTime a {@code LocalDateTime} to convert + * @return a {@code Timestamp} object + * @exception NullPointerException if {@code dateTime} is null. + * @since 1.8 + */ + @SuppressWarnings("deprecation") + public static Timestamp valueOf(LocalDateTime dateTime) { + return new Timestamp(dateTime.getYear() - 1900, + dateTime.getMonthValue() - 1, + dateTime.getDayOfMonth(), + dateTime.getHour(), + dateTime.getMinute(), + dateTime.getSecond(), + dateTime.getNano()); + } + + /** + * Converts this {@code Timestamp} object to a {@code LocalDateTime}. + *

    + * The conversion creates a {@code LocalDateTime} that represents the + * same year, month, day of month, hours, minutes, seconds and nanos + * date-time value as this {@code Timestamp} in the local time zone. + * + * @return a {@code LocalDateTime} object representing the same date-time value + * @since 1.8 + */ + @SuppressWarnings("deprecation") + public LocalDateTime toLocalDateTime() { + return LocalDateTime.of(getYear() + 1900, + getMonth() + 1, + getDate(), + getHours(), + getMinutes(), + getSeconds(), + getNanos()); + } + + /** + * Obtains an instance of {@code Timestamp} from an {@link Instant} object. + *

    + * {@code Instant} can store points on the time-line further in the future + * and further in the past than {@code Date}. In this scenario, this method + * will throw an exception. + * + * @param instant the instant to convert + * @return an {@code Timestamp} representing the same point on the time-line as + * the provided instant + * @exception NullPointerException if {@code instant} is null. + * @exception IllegalArgumentException if the instant is too large to + * represent as a {@code Timesamp} + * @since 1.8 + */ + public static Timestamp from(Instant instant) { + try { + Timestamp stamp = new Timestamp(instant.getEpochSecond() * MILLIS_PER_SECOND); + stamp.nanos = instant.getNano(); + return stamp; + } catch (ArithmeticException ex) { + throw new IllegalArgumentException(ex); + } + } + + /** + * Converts this {@code Timestamp} object to an {@code Instant}. + *

    + * The conversion creates an {@code Instant} that represents the same + * point on the time-line as this {@code Timestamp}. + * + * @return an instant representing the same point on the time-line + * @since 1.8 + */ + @Override + public Instant toInstant() { + return Instant.ofEpochSecond(super.getTime() / MILLIS_PER_SECOND, nanos); + } } diff --git a/jdk/src/share/classes/java/sql/Types.java b/jdk/src/share/classes/java/sql/Types.java index d6fc80a3232..f12ff0dc1da 100644 --- a/jdk/src/share/classes/java/sql/Types.java +++ b/jdk/src/share/classes/java/sql/Types.java @@ -319,6 +319,24 @@ public class Types { */ public static final int REF_CURSOR = 2012; + /** + * The constant in the Java programming language, sometimes referred to + * as a type code, that identifies the generic SQL type + * {@code TIME WITH TIMEZONE}. + * + * @since 1.8 + */ + public static final int TIME_WITH_TIMEZONE = 2013; + + /** + * The constant in the Java programming language, sometimes referred to + * as a type code, that identifies the generic SQL type + * {@code TIMESTAMP WITH TIMEZONE}. + * + * @since 1.8 + */ + public static final int TIMESTAMP_WITH_TIMEZONE = 2014; + // Prevent instantiation private Types() {} } diff --git a/jdk/src/share/classes/java/time/Clock.java b/jdk/src/share/classes/java/time/Clock.java index e4006075ddc..c0be4b0e42e 100644 --- a/jdk/src/share/classes/java/time/Clock.java +++ b/jdk/src/share/classes/java/time/Clock.java @@ -377,60 +377,57 @@ public abstract class Clock { * an instant on the time-line rather than a raw millisecond value. * This method is provided to allow the use of the clock in high performance use cases * where the creation of an object would be unacceptable. + *

    + * The default implementation currently calls {@link #instant}. * * @return the current millisecond instant from this clock, measured from * the Java epoch of 1970-01-01T00:00 UTC, not null * @throws DateTimeException if the instant cannot be obtained, not thrown by most implementations */ - public abstract long millis(); + public long millis() { + return instant().toEpochMilli(); + } //----------------------------------------------------------------------- /** * Gets the current instant of the clock. *

    * This returns an instant representing the current instant as defined by the clock. - *

    - * The default implementation currently calls {@link #millis}. * * @return the current instant from this clock, not null * @throws DateTimeException if the instant cannot be obtained, not thrown by most implementations */ - public Instant instant() { - return Instant.ofEpochMilli(millis()); - } + public abstract Instant instant(); //----------------------------------------------------------------------- /** * Checks if this clock is equal to another clock. *

    - * Clocks must compare equal based on their state and behavior. + * Clocks should override this method to compare equals based on + * their state and to meet the contract of {@link Object#equals}. + * If not overridden, the behavior is defined by {@link Object#equals} * * @param obj the object to check, null returns false * @return true if this is equal to the other clock */ @Override - public abstract boolean equals(Object obj); + public boolean equals(Object obj) { + return super.equals(obj); + } /** * A hash code for this clock. + *

    + * Clocks should override this method based on + * their state and to meet the contract of {@link Object#hashCode}. + * If not overridden, the behavior is defined by {@link Object#hashCode} * * @return a suitable hash code */ @Override - public abstract int hashCode(); - - //----------------------------------------------------------------------- - /** - * Returns a string describing this clock. - *

    - * Clocks must have a string representation based on their state and behavior. - * For example, 'System[Europe/Paris]' could be used to represent the System - * clock in the 'Europe/Paris' time-zone. - * - * @return a string representation of this clock, not null - */ - @Override - public abstract String toString(); + public int hashCode() { + return super.hashCode(); + } //----------------------------------------------------------------------- /** @@ -460,6 +457,10 @@ public abstract class Clock { return System.currentTimeMillis(); } @Override + public Instant instant() { + return Instant.ofEpochMilli(millis()); + } + @Override public boolean equals(Object obj) { if (obj instanceof SystemClock) { return zone.equals(((SystemClock) obj).zone); diff --git a/jdk/src/share/classes/java/time/DayOfWeek.java b/jdk/src/share/classes/java/time/DayOfWeek.java index 5d1f3f34772..c616a31431d 100644 --- a/jdk/src/share/classes/java/time/DayOfWeek.java +++ b/jdk/src/share/classes/java/time/DayOfWeek.java @@ -170,8 +170,9 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster { /** * Obtains an instance of {@code DayOfWeek} 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 DayOfWeek}. + * This obtains a day-of-week based on the specified temporal. + * A {@code TemporalAccessor} represents an arbitrary set of date and time information, + * which this factory converts to an instance of {@code DayOfWeek}. *

    * The conversion extracts the {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} field. *

    @@ -206,8 +207,9 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster { /** * Gets the textual representation, such as 'Mon' or 'Friday'. *

    - * This returns the textual name used to identify the day-of-week. - * The parameters control the length of the returned text and the locale. + * This returns the textual name used to identify the day-of-week, + * suitable for presentation to the user. + * 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. * @@ -215,8 +217,8 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster { * @param locale the locale to use, not null * @return the text value of the day-of-week, not null */ - public String getText(TextStyle style, Locale locale) { - return new DateTimeFormatterBuilder().appendText(DAY_OF_WEEK, style).toFormatter(locale).print(this); + public String getDisplayName(TextStyle style, Locale locale) { + return new DateTimeFormatterBuilder().appendText(DAY_OF_WEEK, style).toFormatter(locale).format(this); } //----------------------------------------------------------------------- @@ -232,7 +234,7 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster { * 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)} + * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} * passing {@code this} as the argument. * Whether the field is supported is determined by the field. * @@ -244,7 +246,7 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster { if (field instanceof ChronoField) { return field == DAY_OF_WEEK; } - return field != null && field.doIsSupported(this); + return field != null && field.isSupportedBy(this); } /** @@ -260,7 +262,7 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster { * 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)} + * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)} * passing {@code this} as the argument. * Whether the range can be obtained is determined by the field. * @@ -289,15 +291,13 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster { * 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)} + * is obtained by invoking {@code TemporalField.getFrom(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, 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 */ @Override @@ -320,7 +320,7 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster { * 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)} + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} * passing {@code this} as the argument. Whether the value can be obtained, * and what the value represents, is determined by the field. * @@ -336,7 +336,7 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster { } else if (field instanceof ChronoField) { throw new DateTimeException("Unsupported field: " + field.getName()); } - return field.doGet(this); + return field.getFrom(this); } //----------------------------------------------------------------------- diff --git a/jdk/src/share/classes/java/time/Duration.java b/jdk/src/share/classes/java/time/Duration.java index e8d75fadba1..86e410f2b30 100644 --- a/jdk/src/share/classes/java/time/Duration.java +++ b/jdk/src/share/classes/java/time/Duration.java @@ -61,10 +61,14 @@ */ package java.time; +import static java.time.LocalTime.NANOS_PER_SECOND; import static java.time.LocalTime.SECONDS_PER_DAY; -import static java.time.temporal.ChronoField.INSTANT_SECONDS; +import static java.time.LocalTime.SECONDS_PER_HOUR; +import static java.time.LocalTime.SECONDS_PER_MINUTE; 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 java.io.DataInput; import java.io.DataOutput; @@ -79,17 +83,23 @@ import java.time.format.DateTimeParseException; import java.time.temporal.ChronoField; import java.time.temporal.ChronoUnit; import java.time.temporal.Temporal; -import java.time.temporal.TemporalAccessor; -import java.time.temporal.TemporalAdder; -import java.time.temporal.TemporalSubtractor; +import java.time.temporal.TemporalAmount; import java.time.temporal.TemporalUnit; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** - * A duration between two instants on the time-line. + * A time-based amount of time, such as '34.5 seconds'. *

    - * This class models a duration of time and is not tied to any instant. - * The model is of a directed duration, meaning that the duration may be negative. + * This class models a quantity or amount of time in terms of seconds and nanoseconds. + * It can be accessed using other duration-based units, such as minutes and hours. + * In addition, the {@link ChronoUnit#DAYS DAYS} unit can be used and is treated as + * exactly equal to 24 hours, thus ignoring daylight savings effects. + * See {@link Period} for the date-based equivalent to this class. *

    * A physical duration could be of infinite length. * For practicality, the duration is stored with constraints similar to {@link Instant}. @@ -99,6 +109,7 @@ import java.util.Objects; * The range of a duration requires the storage of a number larger than a {@code long}. * To achieve this, the class stores a {@code long} representing seconds and an {@code int} * representing nanosecond-of-second, which will always be between 0 and 999,999,999. + * The model is of a directed duration, meaning that the duration may be negative. *

    * The duration is measured in "seconds", but these are not necessarily identical to * the scientific "SI second" definition based on atomic clocks. @@ -112,7 +123,7 @@ import java.util.Objects; * @since 1.8 */ public final class Duration - implements TemporalAdder, TemporalSubtractor, Comparable, Serializable { + implements TemporalAmount, Comparable, Serializable { /** * Constant for a duration of zero. @@ -122,14 +133,17 @@ public final class Duration * Serialization version. */ private static final long serialVersionUID = 3078945930695997490L; - /** - * Constant for nanos per second. - */ - private static final int NANOS_PER_SECOND = 1000_000_000; /** * Constant for nanos per second. */ private static final BigInteger BI_NANOS_PER_SECOND = BigInteger.valueOf(NANOS_PER_SECOND); + /** + * The pattern for parsing. + */ + private final static Pattern PATTERN = + Pattern.compile("([-+]?)P(?:([-+]?[0-9]+)D)?" + + "(T(?:([-+]?[0-9]+)H)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)(?:[.,]([0-9]{0,9}))?S)?)?", + Pattern.CASE_INSENSITIVE); /** * The number of seconds in the duration. @@ -143,7 +157,53 @@ public final class Duration //----------------------------------------------------------------------- /** - * Obtains an instance of {@code Duration} from a number of seconds. + * Obtains a {@code Duration} representing a number of standard 24 hour days. + *

    + * The seconds are calculated based on the standard definition of a day, + * where each day is 86400 seconds which implies a 24 hour day. + * The nanosecond in second field is set to zero. + * + * @param days the number of days, positive or negative + * @return a {@code Duration}, not null + * @throws ArithmeticException if the input days exceeds the capacity of {@code Duration} + */ + public static Duration ofDays(long days) { + return create(Math.multiplyExact(days, SECONDS_PER_DAY), 0); + } + + /** + * Obtains a {@code Duration} representing a number of standard hours. + *

    + * The seconds are calculated based on the standard definition of an hour, + * where each hour is 3600 seconds. + * The nanosecond in second field is set to zero. + * + * @param hours the number of hours, positive or negative + * @return a {@code Duration}, not null + * @throws ArithmeticException if the input hours exceeds the capacity of {@code Duration} + */ + public static Duration ofHours(long hours) { + return create(Math.multiplyExact(hours, SECONDS_PER_HOUR), 0); + } + + /** + * Obtains a {@code Duration} representing a number of standard minutes. + *

    + * The seconds are calculated based on the standard definition of a minute, + * where each minute is 60 seconds. + * The nanosecond in second field is set to zero. + * + * @param minutes the number of minutes, positive or negative + * @return a {@code Duration}, not null + * @throws ArithmeticException if the input minutes exceeds the capacity of {@code Duration} + */ + public static Duration ofMinutes(long minutes) { + return create(Math.multiplyExact(minutes, SECONDS_PER_MINUTE), 0); + } + + //----------------------------------------------------------------------- + /** + * Obtains a {@code Duration} representing a number of seconds. *

    * The nanosecond in second field is set to zero. * @@ -155,8 +215,8 @@ public final class Duration } /** - * Obtains an instance of {@code Duration} from a number of seconds - * and an adjustment in nanoseconds. + * Obtains a {@code Duration} representing a number of seconds and an + * adjustment in nanoseconds. *

    * This method allows an arbitrary number of nanoseconds to be passed in. * The factory will alter the values of the second and nanosecond in order @@ -175,13 +235,13 @@ public final class Duration */ public static Duration ofSeconds(long seconds, long nanoAdjustment) { long secs = Math.addExact(seconds, Math.floorDiv(nanoAdjustment, NANOS_PER_SECOND)); - int nos = (int)Math.floorMod(nanoAdjustment, NANOS_PER_SECOND); + int nos = (int) Math.floorMod(nanoAdjustment, NANOS_PER_SECOND); return create(secs, nos); } //----------------------------------------------------------------------- /** - * Obtains an instance of {@code Duration} from a number of milliseconds. + * Obtains a {@code Duration} representing a number of milliseconds. *

    * The seconds and nanoseconds are extracted from the specified milliseconds. * @@ -200,7 +260,7 @@ public final class Duration //----------------------------------------------------------------------- /** - * Obtains an instance of {@code Duration} from a number of nanoseconds. + * Obtains a {@code Duration} representing a number of nanoseconds. *

    * The seconds and nanoseconds are extracted from the specified nanoseconds. * @@ -219,53 +279,7 @@ public final class Duration //----------------------------------------------------------------------- /** - * Obtains an instance of {@code Duration} from a number of standard length minutes. - *

    - * The seconds are calculated based on the standard definition of a minute, - * where each minute is 60 seconds. - * The nanosecond in second field is set to zero. - * - * @param minutes the number of minutes, positive or negative - * @return a {@code Duration}, not null - * @throws ArithmeticException if the input minutes exceeds the capacity of {@code Duration} - */ - public static Duration ofMinutes(long minutes) { - return create(Math.multiplyExact(minutes, 60), 0); - } - - /** - * Obtains an instance of {@code Duration} from a number of standard length hours. - *

    - * The seconds are calculated based on the standard definition of an hour, - * where each hour is 3600 seconds. - * The nanosecond in second field is set to zero. - * - * @param hours the number of hours, positive or negative - * @return a {@code Duration}, not null - * @throws ArithmeticException if the input hours exceeds the capacity of {@code Duration} - */ - public static Duration ofHours(long hours) { - return create(Math.multiplyExact(hours, 3600), 0); - } - - /** - * Obtains an instance of {@code Duration} from a number of standard 24 hour days. - *

    - * The seconds are calculated based on the standard definition of a day, - * where each day is 86400 seconds which implies a 24 hour day. - * The nanosecond in second field is set to zero. - * - * @param days the number of days, positive or negative - * @return a {@code Duration}, not null - * @throws ArithmeticException if the input days exceeds the capacity of {@code Duration} - */ - public static Duration ofDays(long days) { - return create(Math.multiplyExact(days, 86400), 0); - } - - //----------------------------------------------------------------------- - /** - * Obtains an instance of {@code Duration} from a duration in the specified unit. + * Obtains a {@code Duration} representing an amount in the specified unit. *

    * The parameters represent the two parts of a phrase like '6 Hours'. For example: *

    @@ -288,110 +302,139 @@ public final class Duration
     
         //-----------------------------------------------------------------------
         /**
    -     * Obtains an instance of {@code Duration} representing the duration between two instants.
    +     * Obtains a {@code Duration} representing the duration between two instants.
          * 

    - * A {@code Duration} represents a directed distance between two points on the time-line. - * As such, this method will return a negative duration if the end is before the start. - * To guarantee to obtain a positive duration call {@link #abs()} on the result of this factory. + * This calculates the duration between two temporal objects of the same type. + * The difference in seconds is calculated using + * {@link Temporal#periodUntil(Temporal, TemporalUnit)}. + * The difference in nanoseconds is calculated using by querying the + * {@link ChronoField#NANO_OF_SECOND NANO_OF_SECOND} field. + *

    + * The result of this method can be a negative period if the end is before the start. + * To guarantee to obtain a positive duration call {@link #abs()} on the result. * * @param startInclusive the start instant, inclusive, not null * @param endExclusive the end instant, exclusive, not null * @return a {@code Duration}, not null * @throws ArithmeticException if the calculation exceeds the capacity of {@code Duration} */ - public static Duration between(TemporalAccessor startInclusive, TemporalAccessor endExclusive) { - long secs = Math.subtractExact(endExclusive.getLong(INSTANT_SECONDS), startInclusive.getLong(INSTANT_SECONDS)); - long nanos = endExclusive.getLong(NANO_OF_SECOND) - startInclusive.getLong(NANO_OF_SECOND); - secs = Math.addExact(secs, Math.floorDiv(nanos, NANOS_PER_SECOND)); - nanos = Math.floorMod(nanos, NANOS_PER_SECOND); - return create(secs, (int) nanos); // safe from overflow + public static Duration between(Temporal startInclusive, Temporal endExclusive) { + long secs = startInclusive.periodUntil(endExclusive, SECONDS); + long nanos; + try { + nanos = endExclusive.getLong(NANO_OF_SECOND) - startInclusive.getLong(NANO_OF_SECOND); + } catch (DateTimeException ex) { + nanos = 0; + } + return ofSeconds(secs, nanos); } //----------------------------------------------------------------------- /** - * Obtains an instance of {@code Duration} by parsing a text string. + * Obtains a {@code Duration} from a text string such as {@code PnDTnHnMn.nS}. *

    - * This will parse the string produced by {@link #toString()} which is - * the ISO-8601 format {@code PTnS} where {@code n} is - * the number of seconds with optional decimal part. - * The number must consist of ASCII numerals. - * There must only be a negative sign at the start of the number and it can - * only be present if the value is less than zero. - * There must be at least one digit before any decimal point. - * There must be between 1 and 9 inclusive digits after any decimal point. - * The letters (P, T and S) will be accepted in upper or lower case. + * This will parse a textual representation of a duration, including the + * string produced by {@code toString()}. The formats accepted are based + * on the ISO-8601 duration format {@code PnDTnHnMn.nS} with days + * considered to be exactly 24 hours. + *

    + * The string starts with an optional sign, denoted by the ASCII negative + * or positive symbol. If negative, the whole period is negated. + * The ASCII letter "P" is next in upper or lower case. + * There are then four sections, each consisting of a number and a suffix. + * The sections have suffixes in ASCII of "D", "H", "M" and "S" for + * days, hours, minutes and seconds, accepted in upper or lower case. + * The suffixes must occur in order. The ASCII letter "T" must occur before + * the first occurrence, if any, of an hour, minute or second section. + * At least one of the four sections must be present, and if "T" is present + * there must be at least one section after the "T". + * The number part of each section must consist of one or more ASCII digits. + * The number may be prefixed by the ASCII negative or positive symbol. + * The number of days, hours and minutes must parse to an {@code long}. + * The number of seconds must parse to an {@code long} with optional fraction. * The decimal point may be either a dot or a comma. + * The fractional part may have from zero to 9 digits. + *

    + * The leading plus/minus sign, and negative values for other units are + * not part of the ISO-8601 standard. + *

    + * Examples: + *

    +     *    "PT20.345S" -> parses as "20.345 seconds"
    +     *    "PT15M"     -> parses as "15 minutes" (where a minute is 60 seconds)
    +     *    "PT10H"     -> parses as "10 hours" (where an hour is 3600 seconds)
    +     *    "P2D"       -> parses as "2 days" (where a day is 24 hours or 86400 seconds)
    +     *    "P2DT3H4M"  -> parses as "2 days, 3 hours and 4 minutes"
    +     *    "P-6H3M"    -> parses as "-6 hours and +3 minutes"
    +     *    "-P6H3M"    -> parses as "-6 hours and -3 minutes"
    +     *    "-P-6H+3M"  -> parses as "+6 hours and -3 minutes"
    +     * 
    * * @param text the text to parse, not null - * @return a {@code Duration}, not null - * @throws DateTimeParseException if the text cannot be parsed to a {@code Duration} + * @return the parsed duration, not null + * @throws DateTimeParseException if the text cannot be parsed to a duration */ - public static Duration parse(final CharSequence text) { + public static Duration parse(CharSequence text) { Objects.requireNonNull(text, "text"); - int len = text.length(); - if (len < 4 || - (text.charAt(0) != 'P' && text.charAt(0) != 'p') || - (text.charAt(1) != 'T' && text.charAt(1) != 't') || - (text.charAt(len - 1) != 'S' && text.charAt(len - 1) != 's') || - (len == 5 && text.charAt(2) == '-' && text.charAt(3) == '0')) { - throw new DateTimeParseException("Duration could not be parsed: " + text, text, 0); - } - String numberText = text.subSequence(2, len - 1).toString().replace(',', '.'); - if (numberText.charAt(0) == '+') { - throw new DateTimeParseException("Duration could not be parsed: " + text, text, 2); - } - int dot = numberText.indexOf('.'); - try { - if (dot == -1) { - // no decimal places - if (numberText.startsWith("-0")) { - throw new DateTimeParseException("Duration could not be parsed: " + text, text, 2); + Matcher matcher = PATTERN.matcher(text); + if (matcher.matches()) { + // check for letter T but no time sections + if ("T".equals(matcher.group(3)) == false) { + boolean negate = "-".equals(matcher.group(1)); + String dayMatch = matcher.group(2); + String hourMatch = matcher.group(4); + String minuteMatch = matcher.group(5); + String secondMatch = matcher.group(6); + String fractionMatch = matcher.group(7); + if (dayMatch != null || hourMatch != null || minuteMatch != null || secondMatch != null) { + long daysAsSecs = parseNumber(text, dayMatch, SECONDS_PER_DAY, "days"); + long hoursAsSecs = parseNumber(text, hourMatch, SECONDS_PER_HOUR, "hours"); + long minsAsSecs = parseNumber(text, minuteMatch, SECONDS_PER_MINUTE, "minutes"); + long seconds = parseNumber(text, secondMatch, 1, "seconds"); + int nanos = parseFraction(text, fractionMatch, seconds < 0 ? -1 : 1); + try { + return create(negate, daysAsSecs, hoursAsSecs, minsAsSecs, seconds, nanos); + } catch (ArithmeticException ex) { + throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: overflow", text, 0).initCause(ex); + } } - return create(Long.parseLong(numberText), 0); } - // decimal places - boolean negative = false; - if (numberText.charAt(0) == '-') { - negative = true; - } - long secs = Long.parseLong(numberText.substring(0, dot)); - numberText = numberText.substring(dot + 1); - len = numberText.length(); - if (len == 0 || len > 9 || numberText.charAt(0) == '-' || numberText.charAt(0) == '+') { - throw new DateTimeParseException("Duration could not be parsed: " + text, text, 2); - } - int nanos = Integer.parseInt(numberText); - switch (len) { - case 1: - nanos *= 100000000; - break; - case 2: - nanos *= 10000000; - break; - case 3: - nanos *= 1000000; - break; - case 4: - nanos *= 100000; - break; - case 5: - nanos *= 10000; - break; - case 6: - nanos *= 1000; - break; - case 7: - nanos *= 100; - break; - case 8: - nanos *= 10; - break; - } - return negative ? ofSeconds(secs, -nanos) : create(secs, nanos); - - } catch (ArithmeticException | NumberFormatException ex) { - throw new DateTimeParseException("Duration could not be parsed: " + text, text, 2, ex); } + throw new DateTimeParseException("Text cannot be parsed to a Duration", text, 0); + } + + private static long parseNumber(CharSequence text, String parsed, int multiplier, String errorText) { + // regex limits to [-+]?[0-9]+ + if (parsed == null) { + return 0; + } + try { + long val = Long.parseLong(parsed); + return Math.multiplyExact(val, multiplier); + } catch (NumberFormatException | ArithmeticException ex) { + throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: " + errorText, text, 0).initCause(ex); + } + } + + private static int parseFraction(CharSequence text, String parsed, int negate) { + // regex limits to [0-9]{0,9} + if (parsed == null || parsed.length() == 0) { + return 0; + } + try { + parsed = (parsed + "000000000").substring(0, 9); + return Integer.parseInt(parsed) * negate; + } catch (NumberFormatException | ArithmeticException ex) { + throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: fraction", text, 0).initCause(ex); + } + } + + private static Duration create(boolean negate, long daysAsSecs, long hoursAsSecs, long minsAsSecs, long secs, int nanos) { + long seconds = Math.addExact(daysAsSecs, Math.addExact(hoursAsSecs, Math.addExact(minsAsSecs, secs))); + if (negate) { + return ofSeconds(seconds, nanos).negated(); + } + return ofSeconds(seconds, nanos); } //----------------------------------------------------------------------- @@ -420,6 +463,56 @@ public final class Duration this.nanos = nanos; } + //----------------------------------------------------------------------- + /** + * Gets the value of the requested unit. + *

    + * This returns a value for each of the two supported units, + * {@link ChronoUnit#SECONDS SECONDS} and {@link ChronoUnit#NANOS NANOS}. + * All other units throw an exception. + * + * @param unit the {@code TemporalUnit} for which to return the value + * @return the long value of the unit + * @throws DateTimeException if the unit is not supported + */ + @Override + public long get(TemporalUnit unit) { + if (unit == SECONDS) { + return seconds; + } else if (unit == NANOS) { + return nanos; + } else { + throw new DateTimeException("Unsupported unit: " + unit.getName()); + } + } + + /** + * Gets the set of units supported by this duration. + *

    + * The supported units are {@link ChronoUnit#SECONDS SECONDS}, + * and {@link ChronoUnit#NANOS NANOS}. + * They are returned in the order seconds, nanos. + *

    + * This set can be used in conjunction with {@link #get(TemporalUnit)} + * to access the entire state of the period. + * + * @return a list containing the seconds and nanos units, not null + */ + @Override + public List getUnits() { + return DurationUnits.UNITS; + } + + /** + * Private class to delay initialization of this list until needed. + * The circular dependency between Duration and ChronoUnit prevents + * the simple initialization in Duration. + */ + private static class DurationUnits { + final static List UNITS = + Collections.unmodifiableList(Arrays.asList(SECONDS, NANOS)); + } + //----------------------------------------------------------------------- /** * Checks if this duration is zero length. @@ -434,19 +527,6 @@ public final class Duration return (seconds | nanos) == 0; } - /** - * Checks if this duration is positive, excluding zero. - *

    - * A {@code Duration} represents a directed distance between two points on - * the time-line and can therefore be positive, zero or negative. - * This method checks whether the length is greater than zero. - * - * @return true if this duration has a total length greater than zero - */ - public boolean isPositive() { - return seconds >= 0 && ((seconds | nanos) != 0); - } - /** * Checks if this duration is negative, excluding zero. *

    @@ -497,6 +577,39 @@ public final class Duration return nanos; } + //----------------------------------------------------------------------- + /** + * Returns a copy of this duration with the specified amount of seconds. + *

    + * This returns a duration with the specified seconds, retaining the + * nano-of-second part of this duration. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param seconds the seconds to represent, may be negative + * @return a {@code Duration} based on this period with the requested seconds, not null + */ + public Duration withSeconds(long seconds) { + return create(seconds, nanos); + } + + /** + * Returns a copy of this duration with the specified nano-of-second. + *

    + * This returns a duration with the specified nano-of-second, retaining the + * seconds part of this duration. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param nanoOfSecond the nano-of-second to represent, from 0 to 999,999,999 + * @return a {@code Duration} based on this period with the requested nano-of-second, not null + * @throws DateTimeException if the nano-of-second is invalid + */ + public Duration withNanos(int nanoOfSecond) { + NANO_OF_SECOND.checkValidIntValue(nanoOfSecond); + return create(seconds, nanoOfSecond); + } + //----------------------------------------------------------------------- /** * Returns a copy of this duration with the specified duration added. @@ -551,6 +664,48 @@ public final class Duration } //----------------------------------------------------------------------- + /** + * Returns a copy of this duration with the specified duration in standard 24 hour days added. + *

    + * The number of days is multiplied by 86400 to obtain the number of seconds to add. + * This is based on the standard definition of a day as 24 hours. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param daysToAdd the days to add, positive or negative + * @return a {@code Duration} based on this duration with the specified days added, not null + * @throws ArithmeticException if numeric overflow occurs + */ + public Duration plusDays(long daysToAdd) { + return plus(Math.multiplyExact(daysToAdd, SECONDS_PER_DAY), 0); + } + + /** + * Returns a copy of this duration with the specified duration in hours added. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param hoursToAdd the hours to add, positive or negative + * @return a {@code Duration} based on this duration with the specified hours added, not null + * @throws ArithmeticException if numeric overflow occurs + */ + public Duration plusHours(long hoursToAdd) { + return plus(Math.multiplyExact(hoursToAdd, SECONDS_PER_HOUR), 0); + } + + /** + * Returns a copy of this duration with the specified duration in minutes added. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param minutesToAdd the minutes to add, positive or negative + * @return a {@code Duration} based on this duration with the specified minutes added, not null + * @throws ArithmeticException if numeric overflow occurs + */ + public Duration plusMinutes(long minutesToAdd) { + return plus(Math.multiplyExact(minutesToAdd, SECONDS_PER_MINUTE), 0); + } + /** * Returns a copy of this duration with the specified duration in seconds added. *

    @@ -650,6 +805,52 @@ public final class Duration } //----------------------------------------------------------------------- + /** + * Returns a copy of this duration with the specified duration in standard 24 hour days subtracted. + *

    + * The number of days is multiplied by 86400 to obtain the number of seconds to subtract. + * This is based on the standard definition of a day as 24 hours. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param daysToSubtract the days to subtract, positive or negative + * @return a {@code Duration} based on this duration with the specified days subtracted, not null + * @throws ArithmeticException if numeric overflow occurs + */ + public Duration minusDays(long daysToSubtract) { + return (daysToSubtract == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-daysToSubtract)); + } + + /** + * Returns a copy of this duration with the specified duration in hours subtracted. + *

    + * The number of hours is multiplied by 3600 to obtain the number of seconds to subtract. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param hoursToSubtract the hours to subtract, positive or negative + * @return a {@code Duration} based on this duration with the specified hours subtracted, not null + * @throws ArithmeticException if numeric overflow occurs + */ + public Duration minusHours(long hoursToSubtract) { + return (hoursToSubtract == Long.MIN_VALUE ? plusHours(Long.MAX_VALUE).plusHours(1) : plusHours(-hoursToSubtract)); + } + + /** + * Returns a copy of this duration with the specified duration in minutes subtracted. + *

    + * The number of hours is multiplied by 60 to obtain the number of seconds to subtract. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param minutesToSubtract the minutes to subtract, positive or negative + * @return a {@code Duration} based on this duration with the specified minutes subtracted, not null + * @throws ArithmeticException if numeric overflow occurs + */ + public Duration minusMinutes(long minutesToSubtract) { + return (minutesToSubtract == Long.MIN_VALUE ? plusMinutes(Long.MAX_VALUE).plusMinutes(1) : plusMinutes(-minutesToSubtract)); + } + /** * Returns a copy of this duration with the specified duration in seconds subtracted. *

    @@ -716,8 +917,7 @@ public final class Duration * * @param divisor the value to divide the duration by, positive or negative, not zero * @return a {@code Duration} based on this duration divided by the specified divisor, not null - * @throws ArithmeticException if the divisor is zero - * @throws ArithmeticException if numeric overflow occurs + * @throws ArithmeticException if the divisor is zero or if numeric overflow occurs */ public Duration dividedBy(long divisor) { if (divisor == 0) { @@ -794,15 +994,15 @@ public final class Duration * with this duration added. *

    * In most cases, it is clearer to reverse the calling pattern by using - * {@link Temporal#plus(TemporalAdder)}. + * {@link Temporal#plus(TemporalAmount)}. *

          *   // these two lines are equivalent, but the second approach is recommended
          *   dateTime = thisDuration.addTo(dateTime);
          *   dateTime = dateTime.plus(thisDuration);
          * 
    *

    - * A {@code Duration} can only be added to a {@code Temporal} that - * represents an instant and can supply {@link ChronoField#INSTANT_SECONDS}. + * The calculation will add the seconds, then nanos. + * Only non-zero amounts will be added. *

    * This instance is immutable and unaffected by this method call. * @@ -813,13 +1013,13 @@ public final class Duration */ @Override public Temporal addTo(Temporal temporal) { - long instantSecs = temporal.getLong(INSTANT_SECONDS); - long instantNanos = temporal.getLong(NANO_OF_SECOND); - instantSecs = Math.addExact(instantSecs, seconds); - instantNanos = Math.addExact(instantNanos, nanos); - instantSecs = Math.addExact(instantSecs, Math.floorDiv(instantNanos, NANOS_PER_SECOND)); - instantNanos = Math.floorMod(instantNanos, NANOS_PER_SECOND); - return temporal.with(INSTANT_SECONDS, instantSecs).with(NANO_OF_SECOND, instantNanos); + if (seconds != 0) { + temporal = temporal.plus(seconds, SECONDS); + } + if (nanos != 0) { + temporal = temporal.plus(nanos, NANOS); + } + return temporal; } /** @@ -829,15 +1029,15 @@ public final class Duration * with this duration subtracted. *

    * In most cases, it is clearer to reverse the calling pattern by using - * {@link Temporal#minus(TemporalSubtractor)}. + * {@link Temporal#minus(TemporalAmount)}. *

          *   // these two lines are equivalent, but the second approach is recommended
          *   dateTime = thisDuration.subtractFrom(dateTime);
          *   dateTime = dateTime.minus(thisDuration);
          * 
    *

    - * A {@code Duration} can only be subtracted from a {@code Temporal} that - * represents an instant and can supply {@link ChronoField#INSTANT_SECONDS}. + * The calculation will subtract the seconds, then nanos. + * Only non-zero amounts will be added. *

    * This instance is immutable and unaffected by this method call. * @@ -848,16 +1048,59 @@ public final class Duration */ @Override public Temporal subtractFrom(Temporal temporal) { - long instantSecs = temporal.getLong(INSTANT_SECONDS); - long instantNanos = temporal.getLong(NANO_OF_SECOND); - instantSecs = Math.subtractExact(instantSecs, seconds); - instantNanos = Math.subtractExact(instantNanos, nanos); - instantSecs = Math.addExact(instantSecs, Math.floorDiv(instantNanos, NANOS_PER_SECOND)); - instantNanos = Math.floorMod(instantNanos, NANOS_PER_SECOND); - return temporal.with(INSTANT_SECONDS, instantSecs).with(NANO_OF_SECOND, instantNanos); + if (seconds != 0) { + temporal = temporal.minus(seconds, SECONDS); + } + if (nanos != 0) { + temporal = temporal.minus(nanos, NANOS); + } + return temporal; } //----------------------------------------------------------------------- + /** + * Gets the number of minutes in this duration. + *

    + * This returns the total number of minutes in the duration by dividing the + * number of seconds by 86400. + * This is based on the standard definition of a day as 24 hours. + *

    + * This instance is immutable and unaffected by this method call. + * + * @return the number of minutes in the duration, may be negative + */ + public long toDays() { + return seconds / SECONDS_PER_DAY; + } + + /** + * Gets the number of minutes in this duration. + *

    + * This returns the total number of minutes in the duration by dividing the + * number of seconds by 3600. + *

    + * This instance is immutable and unaffected by this method call. + * + * @return the number of minutes in the duration, may be negative + */ + public long toHours() { + return seconds / SECONDS_PER_HOUR; + } + + /** + * Gets the number of minutes in this duration. + *

    + * This returns the total number of minutes in the duration by dividing the + * number of seconds by 60. + *

    + * This instance is immutable and unaffected by this method call. + * + * @return the number of minutes in the duration, may be negative + */ + public long toMinutes() { + return seconds / SECONDS_PER_MINUTE; + } + /** * Converts this duration to the total length in milliseconds. *

    @@ -887,7 +1130,7 @@ public final class Duration * @throws ArithmeticException if numeric overflow occurs */ public long toNanos() { - long millis = Math.multiplyExact(seconds, 1000_000_000); + long millis = Math.multiplyExact(seconds, NANOS_PER_SECOND); millis = Math.addExact(millis, nanos); return millis; } @@ -911,30 +1154,6 @@ public final class Duration return nanos - otherDuration.nanos; } - /** - * Checks if this duration is greater than the specified {@code Duration}. - *

    - * The comparison is based on the total length of the durations. - * - * @param otherDuration the other duration to compare to, not null - * @return true if this duration is greater than the specified duration - */ - public boolean isGreaterThan(Duration otherDuration) { - return compareTo(otherDuration) > 0; - } - - /** - * Checks if this duration is less than the specified {@code Duration}. - *

    - * The comparison is based on the total length of the durations. - * - * @param otherDuration the other duration to compare to, not null - * @return true if this duration is less than the specified duration - */ - public boolean isLessThan(Duration otherDuration) { - return compareTo(otherDuration) < 0; - } - //----------------------------------------------------------------------- /** * Checks if this duration is equal to the specified {@code Duration}. @@ -970,29 +1189,57 @@ public final class Duration //----------------------------------------------------------------------- /** * A string representation of this duration using ISO-8601 seconds - * based representation, such as {@code PT12.345S}. + * based representation, such as {@code PT8H6M12.345S}. *

    - * The format of the returned string will be {@code PTnS} where n is - * the seconds and fractional seconds of the duration. + * The format of the returned string will be {@code PTnHnMnS}, where n is + * the relevant hours, minutes or seconds part of the duration. + * Any fractional seconds are placed after a decimal point i the seconds section. + * If a section has a zero value, it is omitted. + * The hours, minutes and seconds will all have the same sign. + *

    + * Examples: + *

    +     *    "20.345 seconds"                 -> "PT20.345S
    +     *    "15 minutes" (15 * 60 seconds)   -> "PT15M"
    +     *    "10 hours" (10 * 3600 seconds)   -> "PT10H"
    +     *    "2 days" (2 * 86400 seconds)     -> "PT48H"
    +     * 
    + * Note that multiples of 24 hours are not output as days to avoid confusion + * with {@code Period}. * * @return an ISO-8601 representation of this duration, not null */ @Override public String toString() { + if (this == ZERO) { + return "PT0S"; + } + long hours = seconds / SECONDS_PER_HOUR; + int minutes = (int) ((seconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE); + int secs = (int) (seconds % SECONDS_PER_MINUTE); StringBuilder buf = new StringBuilder(24); buf.append("PT"); - if (seconds < 0 && nanos > 0) { - if (seconds == -1) { + if (hours != 0) { + buf.append(hours).append('H'); + } + if (minutes != 0) { + buf.append(minutes).append('M'); + } + if (secs == 0 && nanos == 0 && buf.length() > 2) { + return buf.toString(); + } + if (secs < 0 && nanos > 0) { + if (secs == -1) { buf.append("-0"); } else { - buf.append(seconds + 1); + buf.append(secs + 1); } } else { - buf.append(seconds); + buf.append(secs); } if (nanos > 0) { int pos = buf.length(); - if (seconds < 0) { + if (secs < 0) { buf.append(2 * NANOS_PER_SECOND - nanos); } else { buf.append(nanos + NANOS_PER_SECOND); diff --git a/jdk/src/share/classes/java/time/Instant.java b/jdk/src/share/classes/java/time/Instant.java index f253eb58e51..81b74eb0722 100644 --- a/jdk/src/share/classes/java/time/Instant.java +++ b/jdk/src/share/classes/java/time/Instant.java @@ -61,6 +61,7 @@ */ package java.time; +import static java.time.LocalTime.NANOS_PER_SECOND; import static java.time.LocalTime.SECONDS_PER_DAY; import static java.time.LocalTime.SECONDS_PER_HOUR; import static java.time.LocalTime.SECONDS_PER_MINUTE; @@ -76,18 +77,17 @@ import java.io.IOException; import java.io.InvalidObjectException; import java.io.ObjectStreamException; import java.io.Serializable; -import java.time.format.DateTimeFormatters; +import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.time.temporal.ChronoField; import java.time.temporal.ChronoUnit; import java.time.temporal.Queries; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; -import java.time.temporal.TemporalAdder; import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalAmount; import java.time.temporal.TemporalField; import java.time.temporal.TemporalQuery; -import java.time.temporal.TemporalSubtractor; import java.time.temporal.TemporalUnit; import java.time.temporal.ValueRange; import java.util.Objects; @@ -225,10 +225,6 @@ public final class Instant * Serialization version. */ private static final long serialVersionUID = -665713676816604388L; - /** - * Constant for nanos per second. - */ - private static final int NANOS_PER_SECOND = 1000_000_000; /** * The number of seconds from the epoch of 1970-01-01T00:00:00Z. @@ -333,8 +329,9 @@ public final class Instant /** * Obtains an instance of {@code Instant} 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 Instant}. + * This obtains an instant based on the specified temporal. + * A {@code TemporalAccessor} represents an arbitrary set of date and time information, + * which this factory converts to an instance of {@code Instant}. *

    * The conversion extracts the {@link ChronoField#INSTANT_SECONDS INSTANT_SECONDS} * and {@link ChronoField#NANO_OF_SECOND NANO_OF_SECOND} fields. @@ -358,14 +355,14 @@ public final class Instant * {@code 2007-12-03T10:15:30:00}. *

    * The string must represent a valid instant in UTC and is parsed using - * {@link DateTimeFormatters#isoInstant()}. + * {@link DateTimeFormatter#ISO_INSTANT}. * * @param text the text to parse, not null * @return the parsed instant, not null * @throws DateTimeParseException if the text cannot be parsed */ public static Instant parse(final CharSequence text) { - return DateTimeFormatters.isoInstant().parse(text, Instant::from); + return DateTimeFormatter.ISO_INSTANT.parse(text, Instant::from); } //----------------------------------------------------------------------- @@ -418,7 +415,7 @@ public final class Instant * 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)} + * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} * passing {@code this} as the argument. * Whether the field is supported is determined by the field. * @@ -430,7 +427,7 @@ public final class Instant if (field instanceof ChronoField) { return field == INSTANT_SECONDS || field == NANO_OF_SECOND || field == MICRO_OF_SECOND || field == MILLI_OF_SECOND; } - return field != null && field.doIsSupported(this); + return field != null && field.isSupportedBy(this); } /** @@ -447,7 +444,7 @@ public final class Instant * 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)} + * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)} * passing {@code this} as the argument. * Whether the range can be obtained is determined by the field. * @@ -475,7 +472,7 @@ public final class Instant * 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)} + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} * passing {@code this} as the argument. Whether the value can be obtained, * and what the value represents, is determined by the field. * @@ -495,7 +492,7 @@ public final class Instant } throw new DateTimeException("Unsupported field: " + field.getName()); } - return range(field).checkValidIntValue(field.doGet(this), field); + return range(field).checkValidIntValue(field.getFrom(this), field); } /** @@ -511,7 +508,7 @@ public final class Instant * 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)} + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} * passing {@code this} as the argument. Whether the value can be obtained, * and what the value represents, is determined by the field. * @@ -531,7 +528,7 @@ public final class Instant } throw new DateTimeException("Unsupported field: " + field.getName()); } - return field.doGet(this); + return field.getFrom(this); } //----------------------------------------------------------------------- @@ -565,7 +562,7 @@ public final class Instant /** * Returns an adjusted copy of this instant. *

    - * This returns a new {@code Instant}, based on this one, with the date adjusted. + * This returns an {@code Instant}, based on this one, with the instant adjusted. * The adjustment takes place using the specified adjuster strategy object. * Read the documentation of the adjuster to understand what adjustment will be made. *

    @@ -588,7 +585,7 @@ public final class Instant /** * Returns a copy of this instant with the specified field set to a new value. *

    - * This returns a new {@code Instant}, based on this one, with the value + * This returns an {@code Instant}, 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. @@ -616,7 +613,7 @@ public final class Instant * 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)} + * is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)} * passing {@code this} as the argument. In this case, the field determines * whether and how to adjust the instant. *

    @@ -647,24 +644,130 @@ public final class Instant } throw new DateTimeException("Unsupported field: " + field.getName()); } - return field.doWith(this, newValue); + return field.adjustInto(this, newValue); } //----------------------------------------------------------------------- /** - * {@inheritDoc} - * @throws DateTimeException {@inheritDoc} - * @throws ArithmeticException {@inheritDoc} + * Returns a copy of this {@code Instant} truncated to the specified unit. + *

    + * Truncating the instant returns a copy of the original with fields + * smaller than the specified unit set to zero. + * The fields are calculated on the basis of using a UTC offset as seen + * in {@code toString}. + * For example, truncating with the {@link ChronoUnit#MINUTES MINUTES} unit will + * round down to the nearest minute, setting the seconds and nanoseconds to zero. + *

    + * The unit must have a {@linkplain TemporalUnit#getDuration() duration} + * that divides into the length of a standard day without remainder. + * This includes all supplied time units on {@link ChronoUnit} and + * {@link ChronoUnit#DAYS DAYS}. Other units throw an exception. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param unit the unit to truncate to, not null + * @return an {@code Instant} based on this instant with the time truncated, not null + * @throws DateTimeException if the unit is invalid for truncation + */ + public Instant truncatedTo(TemporalUnit unit) { + if (unit == ChronoUnit.NANOS) { + return this; + } + Duration unitDur = unit.getDuration(); + if (unitDur.getSeconds() > LocalTime.SECONDS_PER_DAY) { + throw new DateTimeException("Unit is too large to be used for truncation"); + } + long dur = unitDur.toNanos(); + if ((LocalTime.NANOS_PER_DAY % dur) != 0) { + throw new DateTimeException("Unit must divide into a standard day without remainder"); + } + long nod = (seconds % LocalTime.SECONDS_PER_DAY) * LocalTime.NANOS_PER_SECOND + nanos; + long result = (nod / dur) * dur; + return plusNanos(result - nod); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this instant with the specified amount added. + *

    + * This returns an {@code Instant}, based on this one, with the specified amount added. + * The amount is typically {@link Duration} but may be any other type implementing + * the {@link TemporalAmount} interface. + *

    + * The calculation is delegated to the amount object by calling + * {@link TemporalAmount#addTo(Temporal)}. The amount implementation is free + * to implement the addition in any way it wishes, however it typically + * calls back to {@link #plus(long, TemporalUnit)}. Consult the documentation + * of the amount implementation to determine if it can be successfully added. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param amountToAdd the amount to add, not null + * @return an {@code Instant} based on this instant with the addition made, not null + * @throws DateTimeException if the addition cannot be made + * @throws ArithmeticException if numeric overflow occurs */ @Override - public Instant plus(TemporalAdder adder) { - return (Instant) adder.addTo(this); + public Instant plus(TemporalAmount amountToAdd) { + return (Instant) amountToAdd.addTo(this); } /** - * {@inheritDoc} - * @throws DateTimeException {@inheritDoc} - * @throws ArithmeticException {@inheritDoc} + * Returns a copy of this instant with the specified amount added. + *

    + * This returns an {@code Instant}, based on this one, with the amount + * in terms of the unit added. If it is not possible to add the amount, because the + * unit is not supported or for some other reason, an exception is thrown. + *

    + * If the field is a {@link ChronoUnit} then the addition is implemented here. + * The supported fields behave as follows: + *

      + *
    • {@code NANOS} - + * Returns a {@code Instant} with the specified number of nanoseconds added. + * This is equivalent to {@link #plusNanos(long)}. + *
    • {@code MICROS} - + * Returns a {@code Instant} with the specified number of microseconds added. + * This is equivalent to {@link #plusNanos(long)} with the amount + * multiplied by 1,000. + *
    • {@code MILLIS} - + * Returns a {@code Instant} with the specified number of milliseconds added. + * This is equivalent to {@link #plusNanos(long)} with the amount + * multiplied by 1,000,000. + *
    • {@code SECONDS} - + * Returns a {@code Instant} with the specified number of seconds added. + * This is equivalent to {@link #plusSeconds(long)}. + *
    • {@code MINUTES} - + * Returns a {@code Instant} with the specified number of minutes added. + * This is equivalent to {@link #plusSeconds(long)} with the amount + * multiplied by 60. + *
    • {@code HOURS} - + * Returns a {@code Instant} with the specified number of hours added. + * This is equivalent to {@link #plusSeconds(long)} with the amount + * multiplied by 3,600. + *
    • {@code HALF_DAYS} - + * Returns a {@code Instant} with the specified number of half-days added. + * This is equivalent to {@link #plusSeconds(long)} with the amount + * multiplied by 43,200 (12 hours). + *
    • {@code DAYS} - + * Returns a {@code Instant} with the specified number of days added. + * This is equivalent to {@link #plusSeconds(long)} with the amount + * multiplied by 86,400 (24 hours). + *
    + *

    + * All other {@code ChronoUnit} instances will throw a {@code DateTimeException}. + *

    + * If the field is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)} + * passing {@code this} as the argument. In this case, the unit determines + * whether and how to perform the addition. + *

    + * 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 amount to add, not null + * @return an {@code Instant} based on this instant with the specified amount added, not null + * @throws DateTimeException if the addition cannot be made + * @throws ArithmeticException if numeric overflow occurs */ @Override public Instant plus(long amountToAdd, TemporalUnit unit) { @@ -681,7 +784,7 @@ public final class Instant } throw new DateTimeException("Unsupported unit: " + unit.getName()); } - return unit.doPlus(this, amountToAdd); + return unit.addTo(this, amountToAdd); } //----------------------------------------------------------------------- @@ -751,19 +854,47 @@ public final class Instant //----------------------------------------------------------------------- /** - * {@inheritDoc} - * @throws DateTimeException {@inheritDoc} - * @throws ArithmeticException {@inheritDoc} + * Returns a copy of this instant with the specified amount subtracted. + *

    + * This returns an {@code Instant}, based on this one, with the specified amount subtracted. + * The amount is typically {@link Duration} but may be any other type implementing + * the {@link TemporalAmount} interface. + *

    + * The calculation is delegated to the amount object by calling + * {@link TemporalAmount#subtractFrom(Temporal)}. The amount implementation is free + * to implement the subtraction in any way it wishes, however it typically + * calls back to {@link #minus(long, TemporalUnit)}. Consult the documentation + * of the amount implementation to determine if it can be successfully subtracted. + *

    + * This instance is immutable and unaffected by this method call. + * + * @param amountToSubtract the amount to subtract, not null + * @return an {@code Instant} based on this instant with the subtraction made, not null + * @throws DateTimeException if the subtraction cannot be made + * @throws ArithmeticException if numeric overflow occurs */ @Override - public Instant minus(TemporalSubtractor subtractor) { - return (Instant) subtractor.subtractFrom(this); + public Instant minus(TemporalAmount amountToSubtract) { + return (Instant) amountToSubtract.subtractFrom(this); } /** - * {@inheritDoc} - * @throws DateTimeException {@inheritDoc} - * @throws ArithmeticException {@inheritDoc} + * Returns a copy of this instant with the specified amount subtracted. + *

    + * This returns a {@code Instant}, based on this one, with the amount + * in terms of the unit subtracted. If it is not possible to subtract the amount, + * because the unit is not supported or for some other reason, an exception is thrown. + *

    + * This method is equivalent to {@link #plus(long, TemporalUnit)} with the amount negated. + * See that method for a full description of how addition, and thus subtraction, works. + *

    + * 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 amount to subtract, not null + * @return an {@code Instant} based on this instant with the specified amount subtracted, not null + * @throws DateTimeException if the subtraction cannot be made + * @throws ArithmeticException if numeric overflow occurs */ @Override public Instant minus(long amountToSubtract, TemporalUnit unit) { @@ -848,7 +979,7 @@ public final class Instant return (R) NANOS; } // inline TemporalAccessor.super.query(query) as an optimization - if (query == Queries.chrono() || query == Queries.zoneId() || query == Queries.zone() || query == Queries.offset()) { + if (query == Queries.chronology() || query == Queries.zoneId() || query == Queries.zone() || query == Queries.offset()) { return null; } return query.queryFrom(this); @@ -945,7 +1076,7 @@ public final class Instant } throw new DateTimeException("Unsupported unit: " + unit.getName()); } - return unit.between(this, endInstant).getAmount(); + return unit.between(this, endInstant); } private long nanosUntil(Instant end) { @@ -957,6 +1088,43 @@ public final class Instant return Math.subtractExact(end.seconds, seconds); } + //----------------------------------------------------------------------- + /** + * Combines this instant with an offset to create an {@code OffsetDateTime}. + *

    + * This returns an {@code OffsetDateTime} formed from this instant at the + * specified offset from UTC/Greenwich. An exception will be thrown if the + * instant is too large to fit into an offset date-time. + *

    + * This method is equivalent to + * {@link OffsetDateTime#ofInstant(Instant, ZoneId) OffsetDateTime.ofInstant(this, offset)}. + * + * @param offset the offset to combine with, not null + * @return the offset date-time formed from this instant and the specified offset, not null + * @throws DateTimeException if the result exceeds the supported range + */ + public OffsetDateTime atOffset(ZoneOffset offset) { + return OffsetDateTime.ofInstant(this, offset); + } + + /** + * Combines this instant with a time-zone to create a {@code ZonedDateTime}. + *

    + * This returns an {@code ZonedDateTime} formed from this instant at the + * specified time-zone. An exception will be thrown if the instant is too + * large to fit into a zoned date-time. + *

    + * This method is equivalent to + * {@link ZonedDateTime#ofInstant(Instant, ZoneId) ZonedDateTime.ofInstant(this, zone)}. + * + * @param zone the zone to combine with, not null + * @return the zoned date-time formed from this instant and the specified zone, not null + * @throws DateTimeException if the result exceeds the supported range + */ + public ZonedDateTime atZone(ZoneId zone) { + return ZonedDateTime.ofInstant(this, zone); + } + //----------------------------------------------------------------------- /** * Converts this instant to the number of milliseconds from the epoch @@ -1059,13 +1227,13 @@ public final class Instant /** * A string representation of this instant using ISO-8601 representation. *

    - * The format used is the same as {@link DateTimeFormatters#isoInstant()}. + * The format used is the same as {@link DateTimeFormatter#ISO_INSTANT}. * * @return an ISO-8601 representation of this instant, not null */ @Override public String toString() { - return DateTimeFormatters.isoInstant().print(this); + return DateTimeFormatter.ISO_INSTANT.format(this); } // ----------------------------------------------------------------------- diff --git a/jdk/src/share/classes/java/time/LocalDate.java b/jdk/src/share/classes/java/time/LocalDate.java index 8d40f72871f..65287898ac1 100644 --- a/jdk/src/share/classes/java/time/LocalDate.java +++ b/jdk/src/share/classes/java/time/LocalDate.java @@ -80,26 +80,22 @@ import java.io.IOException; import java.io.InvalidObjectException; import java.io.ObjectStreamException; import java.io.Serializable; -import java.time.format.DateTimeBuilder; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.Era; +import java.time.chrono.IsoChronology; import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatters; import java.time.format.DateTimeParseException; import java.time.temporal.ChronoField; -import java.time.temporal.ChronoLocalDate; import java.time.temporal.ChronoUnit; -import java.time.temporal.Era; -import java.time.temporal.ISOChrono; -import java.time.temporal.OffsetDate; +import java.time.temporal.Queries; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; -import java.time.temporal.TemporalAdder; import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalAmount; import java.time.temporal.TemporalField; import java.time.temporal.TemporalQuery; -import java.time.temporal.TemporalSubtractor; import java.time.temporal.TemporalUnit; import java.time.temporal.ValueRange; -import java.time.temporal.Year; import java.time.zone.ZoneOffsetTransition; import java.time.zone.ZoneRules; import java.util.Objects; @@ -131,7 +127,7 @@ import java.util.Objects; * @since 1.8 */ public final class LocalDate - implements Temporal, TemporalAdjuster, ChronoLocalDate, Serializable { + implements Temporal, TemporalAdjuster, ChronoLocalDate, Serializable { /** * The minimum supported {@code LocalDate}, '-999999999-01-01'. @@ -216,7 +212,7 @@ public final class LocalDate */ public static LocalDate now(Clock clock) { Objects.requireNonNull(clock, "clock"); - // inline OffsetDate factory to avoid creating object and InstantProvider checks + // inline to avoid creating object and Instant checks final Instant now = clock.instant(); // called once ZoneOffset offset = clock.getZone().getRules().getOffset(now); long epochSec = now.getEpochSecond() + offset.getTotalSeconds(); // overflow caught later @@ -228,14 +224,15 @@ public final class LocalDate /** * Obtains an instance of {@code LocalDate} from a year, month and day. *

    + * This returns a {@code LocalDate} with the specified year, month and day-of-month. * 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, not null * @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 + * @throws DateTimeException if the value of any field is out of range, + * or if the day-of-month is invalid for the month-year */ public static LocalDate of(int year, Month month, int dayOfMonth) { YEAR.checkValidValue(year); @@ -247,14 +244,15 @@ public final class LocalDate /** * Obtains an instance of {@code LocalDate} from a year, month and day. *

    + * This returns a {@code LocalDate} with the specified year, month and day-of-month. * 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 + * @throws DateTimeException if the value of any field is out of range, + * or if the day-of-month is invalid for the month-year */ public static LocalDate of(int year, int month, int dayOfMonth) { YEAR.checkValidValue(year); @@ -267,18 +265,19 @@ public final class LocalDate /** * Obtains an instance of {@code LocalDate} from a year and day-of-year. *

    + * This returns a {@code LocalDate} with the specified year and day-of-year. * The day-of-year must be valid for the year, otherwise an exception will be thrown. * * @param year the year to represent, from MIN_YEAR to MAX_YEAR * @param dayOfYear the day-of-year to represent, from 1 to 366 * @return the local date, not null - * @throws DateTimeException if the value of any field is out of range - * @throws DateTimeException if the day-of-year is invalid for the month-year + * @throws DateTimeException if the value of any field is out of range, + * or if the day-of-year is invalid for the month-year */ public static LocalDate ofYearDay(int year, int dayOfYear) { YEAR.checkValidValue(year); DAY_OF_YEAR.checkValidValue(dayOfYear); - boolean leap = ISOChrono.INSTANCE.isLeapYear(year); + boolean leap = IsoChronology.INSTANCE.isLeapYear(year); if (dayOfYear == 366 && leap == false) { throw new DateTimeException("Invalid date 'DayOfYear 366' as '" + year + "' is not a leap year"); } @@ -295,8 +294,9 @@ public final class LocalDate /** * 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. + * This returns a {@code LocalDate} with the specified epoch-day. + * The {@link ChronoField#EPOCH_DAY EPOCH_DAY} 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 @@ -338,10 +338,12 @@ public final class LocalDate /** * Obtains an instance of {@code LocalDate} 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 LocalDate}. + * This obtains a local date based on the specified temporal. + * A {@code TemporalAccessor} represents an arbitrary set of date and time information, + * which this factory converts to an instance of {@code LocalDate}. *

    - * The conversion extracts the {@link ChronoField#EPOCH_DAY EPOCH_DAY} field. + * The conversion uses the {@link Queries#localDate()} query, which relies + * on extracting the {@link ChronoField#EPOCH_DAY EPOCH_DAY} field. *

    * This method matches the signature of the functional interface {@link TemporalQuery} * allowing it to be used as a query via method reference, {@code LocalDate::from}. @@ -351,26 +353,11 @@ public final class LocalDate * @throws DateTimeException if unable to convert to a {@code LocalDate} */ public static LocalDate from(TemporalAccessor temporal) { - if (temporal instanceof LocalDate) { - return (LocalDate) temporal; - } else if (temporal instanceof LocalDateTime) { - return ((LocalDateTime) temporal).getDate(); - } else if (temporal instanceof ZonedDateTime) { - return ((ZonedDateTime) temporal).getDate(); - } - // handle builder as a special case - if (temporal instanceof DateTimeBuilder) { - DateTimeBuilder builder = (DateTimeBuilder) temporal; - LocalDate date = builder.extract(LocalDate.class); - if (date != null) { - return date; - } - } - try { - return ofEpochDay(temporal.getLong(EPOCH_DAY)); - } catch (DateTimeException ex) { - throw new DateTimeException("Unable to obtain LocalDate from TemporalAccessor: " + temporal.getClass(), ex); + LocalDate date = temporal.query(Queries.localDate()); + if (date == null) { + throw new DateTimeException("Unable to obtain LocalDate from TemporalAccessor: " + temporal.getClass()); } + return date; } //----------------------------------------------------------------------- @@ -378,14 +365,14 @@ public final class LocalDate * Obtains an instance of {@code LocalDate} from a text string such as {@code 2007-12-03}. *

    * The string must represent a valid date and is parsed using - * {@link java.time.format.DateTimeFormatters#isoLocalDate()}. + * {@link java.time.format.DateTimeFormatter#ISO_LOCAL_DATE}. * * @param text the text to parse such as "2007-12-03", not null * @return the parsed local date, not null * @throws DateTimeParseException if the text cannot be parsed */ public static LocalDate parse(CharSequence text) { - return parse(text, DateTimeFormatters.isoLocalDate()); + return parse(text, DateTimeFormatter.ISO_LOCAL_DATE); } /** @@ -414,7 +401,7 @@ public final class LocalDate * @throws DateTimeException if the day-of-month is invalid for the month-year */ private static LocalDate create(int year, Month month, int dayOfMonth) { - if (dayOfMonth > 28 && dayOfMonth > month.length(ISOChrono.INSTANCE.isLeapYear(year))) { + if (dayOfMonth > 28 && dayOfMonth > month.length(IsoChronology.INSTANCE.isLeapYear(year))) { if (dayOfMonth == 29) { throw new DateTimeException("Invalid date 'February 29' as '" + year + "' is not a leap year"); } else { @@ -435,7 +422,7 @@ public final class LocalDate private static LocalDate resolvePreviousValid(int year, int month, int day) { switch (month) { case 2: - day = Math.min(day, ISOChrono.INSTANCE.isLeapYear(year) ? 29 : 28); + day = Math.min(day, IsoChronology.INSTANCE.isLeapYear(year) ? 29 : 28); break; case 4: case 6: @@ -469,8 +456,6 @@ public final class LocalDate * {@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: *

    The default location and file name can be overridden by setting * following two Java system properties. *
    -     *   Location: java.time.calendar.HijrahDate.deviationConfigDir
    -     *   File name: java.time.calendar.HijrahDate.File. + typeid
    +     *   Location: java.time.chrono.HijrahDate.deviationConfigDir
    +     *   File name: java.time.chrono.HijrahDate.File. + typeid
          * 
    Regarding the file format, see readDeviationConfig() method for * details. * @@ -209,10 +208,9 @@ final class HijrahDeviationReader { */ private static InputStream getConfigFileInputStream(final String typeId) throws IOException { try { - InputStream stream = - (InputStream)AccessController - .doPrivileged((java.security.PrivilegedExceptionAction) () -> { - String propFilename = "java.time.calendar.HijrahChrono.File." + typeId; + InputStream stream = AccessController + .doPrivileged((java.security.PrivilegedExceptionAction) () -> { + String propFilename = "java.time.chrono.HijrahChronology.File." + typeId; String filename = System.getProperty(propFilename); File file = null; if (filename != null) { diff --git a/jdk/src/share/classes/java/time/calendar/HijrahEra.java b/jdk/src/share/classes/java/time/chrono/HijrahEra.java similarity index 71% rename from jdk/src/share/classes/java/time/calendar/HijrahEra.java rename to jdk/src/share/classes/java/time/chrono/HijrahEra.java index 5c622f78e8e..1ac2569281e 100644 --- a/jdk/src/share/classes/java/time/calendar/HijrahEra.java +++ b/jdk/src/share/classes/java/time/chrono/HijrahEra.java @@ -54,23 +54,12 @@ * 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.calendar; - -import static java.time.temporal.ChronoField.ERA; +package java.time.chrono; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.time.DateTimeException; -import java.time.format.DateTimeFormatterBuilder; -import java.time.format.TextStyle; -import java.time.temporal.ChronoField; -import java.time.temporal.ChronoLocalDate; -import java.time.temporal.Era; -import java.time.temporal.Temporal; -import java.time.temporal.TemporalField; -import java.time.temporal.ValueRange; -import java.util.Locale; /** * An era in the Hijrah calendar system. @@ -86,7 +75,7 @@ import java.util.Locale; * * @since 1.8 */ -enum HijrahEra implements Era { +enum HijrahEra implements Era { /** * The singleton instance for the era before the current one, 'Before Anno Hegirae', @@ -135,71 +124,23 @@ enum HijrahEra implements Era { } @Override - public HijrahChrono getChrono() { - return HijrahChrono.INSTANCE; + public HijrahChronology getChronology() { + return HijrahChronology.INSTANCE; } // JDK8 default methods: //----------------------------------------------------------------------- @Override - public ChronoLocalDate date(int year, int month, int day) { - return getChrono().date(this, year, month, day); + public HijrahDate date(int year, int month, int day) { + return (HijrahDate)(getChronology().date(this, year, month, day)); } @Override - public ChronoLocalDate dateYearDay(int year, int dayOfYear) { - return getChrono().dateYearDay(this, year, dayOfYear); - } - - //----------------------------------------------------------------------- - @Override - public boolean isSupported(TemporalField field) { - if (field instanceof ChronoField) { - return field == ERA; - } - return field != null && field.doIsSupported(this); - } - - @Override - public ValueRange range(TemporalField field) { - if (field == ERA) { - return field.range(); - } else if (field instanceof ChronoField) { - throw new DateTimeException("Unsupported field: " + field.getName()); - } - return field.doRange(this); - } - - @Override - public int get(TemporalField field) { - if (field == ERA) { - return getValue(); - } - return range(field).checkValidIntValue(getLong(field), field); - } - - @Override - public long getLong(TemporalField field) { - if (field == ERA) { - return getValue(); - } else if (field instanceof ChronoField) { - throw new DateTimeException("Unsupported field: " + field.getName()); - } - return field.doGet(this); + public HijrahDate dateYearDay(int year, int dayOfYear) { + return (HijrahDate)(getChronology().dateYearDay(this, year, dayOfYear)); } //------------------------------------------------------------------------- - @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); - } - /** * Returns the proleptic year from this era and year of era. * diff --git a/jdk/src/share/classes/java/time/temporal/ISOChrono.java b/jdk/src/share/classes/java/time/chrono/IsoChronology.java similarity index 92% rename from jdk/src/share/classes/java/time/temporal/ISOChrono.java rename to jdk/src/share/classes/java/time/chrono/IsoChronology.java index c290e4e1dbb..883db3ee31c 100644 --- a/jdk/src/share/classes/java/time/temporal/ISOChrono.java +++ b/jdk/src/share/classes/java/time/chrono/IsoChronology.java @@ -59,7 +59,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package java.time.temporal; +package java.time.chrono; import java.io.Serializable; import java.time.Clock; @@ -69,6 +69,9 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZonedDateTime; +import java.time.temporal.ChronoField; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.ValueRange; import java.util.Arrays; import java.util.List; import java.util.Locale; @@ -102,26 +105,26 @@ import java.util.Objects; * * @since 1.8 */ -public final class ISOChrono extends Chrono implements Serializable { +public final class IsoChronology extends Chronology implements Serializable { /** * Singleton instance of the ISO chronology. */ - public static final ISOChrono INSTANCE = new ISOChrono(); + public static final IsoChronology INSTANCE = new IsoChronology(); /** * 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; + 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; + public static final Era ERA_CE = IsoEra.CE; /** * Serialization version. @@ -131,7 +134,7 @@ public final class ISOChrono extends Chrono implements Serializable { /** * Restricted constructor. */ - private ISOChrono() { + private IsoChronology() { } /** @@ -147,8 +150,8 @@ public final class ISOChrono extends Chrono implements Serializable { /** * 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)}. + * The ID uniquely identifies the {@code Chronology}. + * It can be used to lookup the {@code Chronology} using {@link #of(String)}. * * @return the chronology ID - 'ISO' * @see #getCalendarType() @@ -163,7 +166,7 @@ public final class ISOChrono extends Chrono implements Serializable { *

    * The calendar type is an identifier defined by the * Unicode Locale Data Markup Language (LDML) specification. - * It can be used to lookup the {@code Chrono} using {@link #of(String)}. + * It can be used to lookup the {@code Chronology} using {@link #of(String)}. * It can also be used as part of a locale, accessible via * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'. * @@ -188,7 +191,7 @@ public final class ISOChrono extends Chrono implements Serializable { * @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) { + public LocalDate date(Era era, int yearOfEra, int month, int dayOfMonth) { return date(prolepticYear(era, yearOfEra), month, dayOfMonth); } @@ -219,7 +222,7 @@ public final class ISOChrono extends Chrono implements Serializable { * @throws DateTimeException if unable to create the date */ @Override // override with covariant return type - public LocalDate dateYearDay(Era era, int yearOfEra, int dayOfYear) { + public LocalDate dateYearDay(Era era, int yearOfEra, int dayOfYear) { return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear); } @@ -291,6 +294,7 @@ public final class ISOChrono extends Chrono implements Serializable { * @return the zoned date-time, not null * @throws DateTimeException if the result exceeds the supported range */ + @Override public ZonedDateTime zonedDateTime(Instant instant, ZoneId zone) { return ZonedDateTime.ofInstant(instant, zone); } @@ -373,21 +377,21 @@ public final class ISOChrono extends Chrono implements Serializable { } @Override - public int prolepticYear(Era era, int yearOfEra) { - if (era instanceof ISOEra == false) { - throw new DateTimeException("Era must be ISOEra"); + 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); + return (era == IsoEra.CE ? yearOfEra : 1 - yearOfEra); } @Override - public Era eraOf(int eraValue) { - return ISOEra.of(eraValue); + public Era eraOf(int eraValue) { + return IsoEra.of(eraValue); } @Override - public List> eras() { - return Arrays.>asList(ISOEra.values()); + public List eras() { + return Arrays.asList(IsoEra.values()); } //----------------------------------------------------------------------- diff --git a/jdk/src/share/classes/java/time/temporal/ISOEra.java b/jdk/src/share/classes/java/time/chrono/IsoEra.java similarity index 69% rename from jdk/src/share/classes/java/time/temporal/ISOEra.java rename to jdk/src/share/classes/java/time/chrono/IsoEra.java index 21009f6b183..8a81067bdc8 100644 --- a/jdk/src/share/classes/java/time/temporal/ISOEra.java +++ b/jdk/src/share/classes/java/time/chrono/IsoEra.java @@ -59,14 +59,11 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package java.time.temporal; +package java.time.chrono; -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; +import java.time.LocalDate; /** * An era in the ISO calendar system. @@ -75,7 +72,7 @@ import java.util.Locale; * 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}. + * Do not use {@code ordinal()} to obtain the numeric representation of {@code IsoEra}. * Use {@code getValue()} instead. * *

    Specification for implementors

    @@ -83,7 +80,7 @@ import java.util.Locale; * * @since 1.8 */ -enum ISOEra implements Era { +enum IsoEra implements Era { /** * The singleton instance for the era BCE, 'Before Current Era'. @@ -102,16 +99,16 @@ enum ISOEra implements Era { //----------------------------------------------------------------------- /** - * Obtains an instance of {@code ISOEra} from an {@code int} value. + * Obtains an instance of {@code IsoEra} from an {@code int} value. *

    - * {@code ISOEra} is an enum representing the ISO eras of BCE/CE. + * {@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) { + public static IsoEra of(int era) { switch (era) { case 0: return BCE; @@ -136,69 +133,20 @@ enum ISOEra implements Era { } @Override - public ISOChrono getChrono() { - return ISOChrono.INSTANCE; + public IsoChronology getChronology() { + return IsoChronology.INSTANCE; } // JDK8 default methods: //----------------------------------------------------------------------- @Override - public ChronoLocalDate date(int year, int month, int day) { - return getChrono().date(this, year, month, day); + public LocalDate date(int year, int month, int day) { + return getChronology().date(this, year, month, day); } @Override - public ChronoLocalDate dateYearDay(int year, int dayOfYear) { - return getChrono().dateYearDay(this, year, dayOfYear); - } - - //----------------------------------------------------------------------- - @Override - public boolean isSupported(TemporalField field) { - if (field instanceof ChronoField) { - return field == ERA; - } - return field != null && field.doIsSupported(this); - } - - @Override - public ValueRange range(TemporalField field) { - if (field == ERA) { - return field.range(); - } else if (field instanceof ChronoField) { - throw new DateTimeException("Unsupported field: " + field.getName()); - } - return field.doRange(this); - } - - @Override - public int get(TemporalField field) { - if (field == ERA) { - return getValue(); - } - return range(field).checkValidIntValue(getLong(field), field); - } - - @Override - public long getLong(TemporalField field) { - if (field == ERA) { - return getValue(); - } else if (field instanceof ChronoField) { - throw new DateTimeException("Unsupported field: " + field.getName()); - } - return field.doGet(this); - } - - //------------------------------------------------------------------------- - @Override - public Temporal adjustInto(Temporal temporal) { - return temporal.with(ERA, getValue()); - } - - //----------------------------------------------------------------------- - @Override - public String getText(TextStyle style, Locale locale) { - return new DateTimeFormatterBuilder().appendText(ERA, style).toFormatter(locale).print(this); + public LocalDate dateYearDay(int year, int dayOfYear) { + return getChronology().dateYearDay(this, year, dayOfYear); } } diff --git a/jdk/src/share/classes/java/time/calendar/JapaneseChrono.java b/jdk/src/share/classes/java/time/chrono/JapaneseChronology.java similarity index 81% rename from jdk/src/share/classes/java/time/calendar/JapaneseChrono.java rename to jdk/src/share/classes/java/time/chrono/JapaneseChronology.java index 12073c66b79..bb16d891476 100644 --- a/jdk/src/share/classes/java/time/calendar/JapaneseChrono.java +++ b/jdk/src/share/classes/java/time/chrono/JapaneseChronology.java @@ -54,25 +54,22 @@ * 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.calendar; +package java.time.chrono; import java.io.Serializable; +import java.time.Clock; import java.time.DateTimeException; +import java.time.Instant; import java.time.LocalDate; -import java.time.temporal.Chrono; import java.time.temporal.ChronoField; -import java.time.temporal.ChronoLocalDate; -import java.time.temporal.Era; -import java.time.temporal.ISOChrono; import java.time.temporal.TemporalAccessor; import java.time.temporal.ValueRange; -import java.time.temporal.Year; +import java.time.Year; +import java.time.ZoneId; import java.util.Arrays; import java.util.Calendar; -import java.util.HashMap; import java.util.List; import java.util.Locale; -import java.util.Map; import sun.util.calendar.CalendarSystem; import sun.util.calendar.LocalGregorianCalendar; @@ -93,7 +90,7 @@ import sun.util.calendar.LocalGregorianCalendar; * * @since 1.8 */ -public final class JapaneseChrono extends Chrono implements Serializable { +public final class JapaneseChronology extends Chronology implements Serializable { // TODO: definition for unknown era may break requirement that year-of-era >= 1 static final LocalGregorianCalendar JCAL = @@ -105,33 +102,33 @@ public final class JapaneseChrono extends Chrono implements Seri /** * Singleton instance for Japanese chronology. */ - public static final JapaneseChrono INSTANCE = new JapaneseChrono(); + public static final JapaneseChronology INSTANCE = new JapaneseChronology(); /** * The singleton instance for the before Meiji era ( - 1868-09-07) * which has the value -999. */ - public static final Era ERA_SEIREKI = JapaneseEra.SEIREKI; + public static final Era ERA_SEIREKI = JapaneseEra.SEIREKI; /** * The singleton instance for the Meiji era (1868-09-08 - 1912-07-29) * which has the value -1. */ - public static final Era ERA_MEIJI = JapaneseEra.MEIJI; + public static final Era ERA_MEIJI = JapaneseEra.MEIJI; /** * The singleton instance for the Taisho era (1912-07-30 - 1926-12-24) * which has the value 0. */ - public static final Era ERA_TAISHO = JapaneseEra.TAISHO; + public static final Era ERA_TAISHO = JapaneseEra.TAISHO; /** * The singleton instance for the Showa era (1926-12-25 - 1989-01-07) * which has the value 1. */ - public static final Era ERA_SHOWA = JapaneseEra.SHOWA; + public static final Era ERA_SHOWA = JapaneseEra.SHOWA; /** * The singleton instance for the Heisei era (1989-01-08 - current) * which has the value 2. */ - public static final Era ERA_HEISEI = JapaneseEra.HEISEI; + public static final Era ERA_HEISEI = JapaneseEra.HEISEI; /** * Serialization version. */ @@ -141,7 +138,7 @@ public final class JapaneseChrono extends Chrono implements Seri /** * Restricted constructor. */ - private JapaneseChrono() { + private JapaneseChronology() { } /** @@ -157,8 +154,8 @@ public final class JapaneseChrono extends Chrono implements Seri /** * Gets the ID of the chronology - 'Japanese'. *

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

    * The calendar type is an identifier defined by the * Unicode Locale Data Markup Language (LDML) specification. - * It can be used to lookup the {@code Chrono} using {@link #of(String)}. + * It can be used to lookup the {@code Chronology} using {@link #of(String)}. * It can also be used as part of a locale, accessible via * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'. * @@ -187,7 +184,7 @@ public final class JapaneseChrono extends Chrono implements Seri //----------------------------------------------------------------------- @Override - public ChronoLocalDate date(Era era, int yearOfEra, int month, int dayOfMonth) { + public JapaneseDate date(Era era, int yearOfEra, int month, int dayOfMonth) { if (era instanceof JapaneseEra == false) { throw new DateTimeException("Era must be JapaneseEra"); } @@ -195,24 +192,59 @@ public final class JapaneseChrono extends Chrono implements Seri } @Override - public ChronoLocalDate date(int prolepticYear, int month, int dayOfMonth) { + public JapaneseDate date(int prolepticYear, int month, int dayOfMonth) { return new JapaneseDate(LocalDate.of(prolepticYear, month, dayOfMonth)); } @Override - public ChronoLocalDate dateYearDay(int prolepticYear, int dayOfYear) { + public JapaneseDate dateYearDay(int prolepticYear, int dayOfYear) { LocalDate date = LocalDate.ofYearDay(prolepticYear, dayOfYear); return date(prolepticYear, date.getMonthValue(), date.getDayOfMonth()); } @Override - public ChronoLocalDate date(TemporalAccessor temporal) { + public JapaneseDate date(TemporalAccessor temporal) { if (temporal instanceof JapaneseDate) { return (JapaneseDate) temporal; } return new JapaneseDate(LocalDate.from(temporal)); } + @Override + public JapaneseDate dateYearDay(Era era, int yearOfEra, int dayOfYear) { + return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear); + } + + @Override + public JapaneseDate dateNow() { + return dateNow(Clock.systemDefaultZone()); + } + + @Override + public JapaneseDate dateNow(ZoneId zone) { + return dateNow(Clock.system(zone)); + } + + @Override + public JapaneseDate dateNow(Clock clock) { + return date(LocalDate.now(clock)); + } + + @Override + public ChronoLocalDateTime localDateTime(TemporalAccessor temporal) { + return (ChronoLocalDateTime)super.localDateTime(temporal); + } + + @Override + public ChronoZonedDateTime zonedDateTime(TemporalAccessor temporal) { + return (ChronoZonedDateTime)super.zonedDateTime(temporal); + } + + @Override + public ChronoZonedDateTime zonedDateTime(Instant instant, ZoneId zone) { + return (ChronoZonedDateTime)super.zonedDateTime(instant, zone); + } + //----------------------------------------------------------------------- /** * Checks if the specified year is a leap year. @@ -226,11 +258,11 @@ public final class JapaneseChrono extends Chrono implements Seri */ @Override public boolean isLeapYear(long prolepticYear) { - return ISOChrono.INSTANCE.isLeapYear(prolepticYear); + return IsoChronology.INSTANCE.isLeapYear(prolepticYear); } @Override - public int prolepticYear(Era era, int yearOfEra) { + public int prolepticYear(Era era, int yearOfEra) { if (era instanceof JapaneseEra == false) { throw new DateTimeException("Era must be JapaneseEra"); } @@ -261,13 +293,13 @@ public final class JapaneseChrono extends Chrono implements Seri * @throws DateTimeException if {@code eraValue} is invalid */ @Override - public Era eraOf(int eraValue) { + public Era eraOf(int eraValue) { return JapaneseEra.of(eraValue); } @Override - public List> eras() { - return Arrays.>asList(JapaneseEra.values()); + public List eras() { + return Arrays.asList(JapaneseEra.values()); } //----------------------------------------------------------------------- diff --git a/jdk/src/share/classes/java/time/calendar/JapaneseDate.java b/jdk/src/share/classes/java/time/chrono/JapaneseDate.java similarity index 52% rename from jdk/src/share/classes/java/time/calendar/JapaneseDate.java rename to jdk/src/share/classes/java/time/chrono/JapaneseDate.java index d923c88f1c6..75cd0a5aa74 100644 --- a/jdk/src/share/classes/java/time/calendar/JapaneseDate.java +++ b/jdk/src/share/classes/java/time/chrono/JapaneseDate.java @@ -54,7 +54,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package java.time.calendar; +package java.time.chrono; import static java.time.temporal.ChronoField.DAY_OF_MONTH; import static java.time.temporal.ChronoField.MONTH_OF_YEAR; @@ -63,13 +63,20 @@ import static java.time.temporal.ChronoField.YEAR; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; -import java.io.ObjectInputStream; import java.io.Serializable; +import java.time.Clock; import java.time.DateTimeException; import java.time.LocalDate; +import java.time.LocalTime; +import java.time.Period; +import java.time.ZoneId; import java.time.temporal.ChronoField; -import java.time.temporal.ChronoLocalDate; +import java.time.temporal.TemporalQuery; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalAmount; import java.time.temporal.TemporalField; +import java.time.temporal.TemporalUnit; import java.time.temporal.ValueRange; import java.util.Calendar; import java.util.Objects; @@ -79,19 +86,27 @@ import sun.util.calendar.LocalGregorianCalendar; /** * A date in the Japanese Imperial calendar system. *

    - * This implements {@code ChronoLocalDate} for the - * {@linkplain JapaneseChrono Japanese Imperial calendar}. + * This date operates using the {@linkplain JapaneseChronology Japanese Imperial calendar}. + * This calendar system is primarily used in Japan. + *

    + * The Japanese Imperial calendar system is the same as the ISO calendar system + * apart from the era-based year numbering. The proleptic-year is defined to be + * equal to the ISO proleptic-year. + *

    + * For example, the Japanese year "Heisei 24" corresponds to ISO year "2012".
    + * Calling {@code japaneseDate.get(YEAR_OF_ERA)} will return 24.
    + * Calling {@code japaneseDate.get(YEAR)} will return 2012.
    + * Calling {@code japaneseDate.get(ERA)} will return 2, corresponding to + * {@code JapaneseChronology.ERA_HEISEI}.
    * *

    Specification for implementors

    * This class is immutable and thread-safe. * * @since 1.8 */ -final class JapaneseDate - extends ChronoDateImpl - implements ChronoLocalDate, Serializable { - // this class is package-scoped so that future conversion to public - // would not change serialization +public final class JapaneseDate + extends ChronoDateImpl + implements ChronoLocalDate, Serializable { /** * Serialization version. @@ -111,29 +126,159 @@ final class JapaneseDate */ private transient int yearOfEra; + //----------------------------------------------------------------------- /** - * Obtains an instance of {@code JapaneseDate} from the era, year-of-era, - * month-of-year and day-of-month. + * Obtains the current {@code JapaneseDate} 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. * - * @param era the era to represent, not null - * @param yearOfEra the year-of-era to represent - * @param month the month-of-year to represent - * @param dayOfMonth the day-of-month to represent, from 1 to 31 - * @return the Japanese date, never null - * @throws DateTimeException if the value of any field is out of range, or - * if the day-of-month is invalid for the month-year + * @return the current date using the system clock and default time-zone, not null + */ + public static JapaneseDate now() { + return now(Clock.systemDefaultZone()); + } + + /** + * Obtains the current {@code JapaneseDate} 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 date using the system clock, not null + */ + public static JapaneseDate now(ZoneId zone) { + return now(Clock.system(zone)); + } + + /** + * Obtains the current {@code JapaneseDate} 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 {@linkplain Clock dependency injection}. + * + * @param clock the clock to use, not null + * @return the current date, not null + * @throws DateTimeException if the current date cannot be obtained + */ + public static JapaneseDate now(Clock clock) { + return JapaneseChronology.INSTANCE.date(LocalDate.now(clock)); + } + + /** + * Obtains a {@code JapaneseDate} representing a date in the Japanese calendar + * system from the era, year-of-era, month-of-year and day-of-month fields. + *

    + * This returns a {@code JapaneseDate} with the specified fields. + * The day must be valid for the year and month, otherwise an exception will be thrown. + * + * @param era the Japanese era, not null + * @param yearOfEra the Japanese year-of-era + * @param month the Japanese month-of-year, from 1 to 12 + * @param dayOfMonth the Japanese day-of-month, from 1 to 31 + * @return the date in Japanese calendar system, not null + * @throws DateTimeException if the value of any field is out of range, + * or if the day-of-month is invalid for the month-year, + * or if the date is not a Japanese era + */ + public static JapaneseDate of(Era era, int yearOfEra, int month, int dayOfMonth) { + if (era instanceof JapaneseEra == false) { + throw new DateTimeException("Era must be JapaneseEra"); + } + return JapaneseDate.of((JapaneseEra) era, yearOfEra, month, dayOfMonth); + } + + /** + * Obtains a {@code JapaneseDate} representing a date in the Japanese calendar + * system from the proleptic-year, month-of-year and day-of-month fields. + *

    + * This returns a {@code JapaneseDate} with the specified fields. + * The day must be valid for the year and month, otherwise an exception will be thrown. + * + * @param prolepticYear the Japanese proleptic-year + * @param month the Japanese month-of-year, from 1 to 12 + * @param dayOfMonth the Japanese day-of-month, from 1 to 31 + * @return the date in Japanese calendar system, not null + * @throws DateTimeException if the value of any field is out of range, + * or if the day-of-month is invalid for the month-year + */ + public static JapaneseDate of(int prolepticYear, int month, int dayOfMonth) { + return new JapaneseDate(LocalDate.of(prolepticYear, month, dayOfMonth)); + } + + /** + * Obtains a {@code JapaneseDate} representing a date in the Japanese calendar + * system from the proleptic-year and day-of-year fields. + *

    + * This returns a {@code JapaneseDate} with the specified fields. + * The day must be valid for the year, otherwise an exception will be thrown. + * + * @param prolepticYear the chronology proleptic-year + * @param dayOfYear the chronology day-of-year, from 1 to 366 + * @return the date in Japanese calendar system, not null + * @throws DateTimeException if the value of any field is out of range, + * or if the day-of-year is invalid for the year + */ + public static JapaneseDate ofYearDay(int prolepticYear, int dayOfYear) { + LocalDate date = LocalDate.ofYearDay(prolepticYear, dayOfYear); + return of(prolepticYear, date.getMonthValue(), date.getDayOfMonth()); + } + + /** + * Obtains a {@code JapaneseDate} representing a date in the Japanese calendar + * system from the era, year-of-era, month-of-year and day-of-month fields. + *

    + * This returns a {@code JapaneseDate} with the specified fields. + * The day must be valid for the year and month, otherwise an exception will be thrown. + * + * @param era the Japanese era, not null + * @param yearOfEra the Japanese year-of-era + * @param month the Japanese month-of-year, from 1 to 12 + * @param dayOfMonth the Japanese day-of-month, from 1 to 31 + * @return the date in Japanese calendar system, not null + * @throws DateTimeException if the value of any field is out of range, + * or if the day-of-month is invalid for the month-year */ static JapaneseDate of(JapaneseEra era, int yearOfEra, int month, int dayOfMonth) { Objects.requireNonNull(era, "era"); - LocalGregorianCalendar.Date jdate = JapaneseChrono.JCAL.newCalendarDate(null); + LocalGregorianCalendar.Date jdate = JapaneseChronology.JCAL.newCalendarDate(null); jdate.setEra(era.getPrivateEra()).setDate(yearOfEra, month, dayOfMonth); - if (!JapaneseChrono.JCAL.validate(jdate)) { + if (!JapaneseChronology.JCAL.validate(jdate)) { throw new IllegalArgumentException(); } LocalDate date = LocalDate.of(jdate.getNormalizedYear(), month, dayOfMonth); return new JapaneseDate(era, yearOfEra, date); } + /** + * Obtains a {@code JapaneseDate} from a temporal object. + *

    + * This obtains a date in the Japanese calendar system based on the specified temporal. + * A {@code TemporalAccessor} represents an arbitrary set of date and time information, + * which this factory converts to an instance of {@code JapaneseDate}. + *

    + * The conversion typically uses the {@link ChronoField#EPOCH_DAY EPOCH_DAY} + * field, which is standardized across calendar systems. + *

    + * This method matches the signature of the functional interface {@link TemporalQuery} + * allowing it to be used as a query via method reference, {@code JapaneseDate::from}. + * + * @param temporal the temporal object to convert, not null + * @return the date in Japanese calendar system, not null + * @throws DateTimeException if unable to convert to a {@code JapaneseDate} + */ + public static JapaneseDate from(TemporalAccessor temporal) { + return JapaneseChronology.INSTANCE.date(temporal); + } + //----------------------------------------------------------------------- /** * Creates an instance from an ISO date. @@ -163,8 +308,8 @@ final class JapaneseDate //----------------------------------------------------------------------- @Override - public JapaneseChrono getChrono() { - return JapaneseChrono.INSTANCE; + public JapaneseChronology getChronology() { + return JapaneseChronology.INSTANCE; } @Override @@ -183,15 +328,15 @@ final class JapaneseDate case YEAR_OF_ERA: return actualRange(Calendar.YEAR); } - return getChrono().range(f); + return getChronology().range(f); } throw new DateTimeException("Unsupported field: " + field.getName()); } - return field.doRange(this); + return field.rangeRefinedBy(this); } private ValueRange actualRange(int calendarField) { - Calendar jcal = Calendar.getInstance(JapaneseChrono.LOCALE); + Calendar jcal = Calendar.getInstance(JapaneseChronology.LOCALE); jcal.set(Calendar.ERA, era.getValue() + JapaneseEra.ERA_OFFSET); jcal.set(yearOfEra, isoDate.getMonthValue() - 1, isoDate.getDayOfMonth()); return ValueRange.of(jcal.getActualMinimum(calendarField), @@ -208,13 +353,13 @@ final class JapaneseDate return era.getValue(); case DAY_OF_YEAR: { LocalGregorianCalendar.Date jdate = toPrivateJapaneseDate(isoDate); - return JapaneseChrono.JCAL.getDayOfYear(jdate); + return JapaneseChronology.JCAL.getDayOfYear(jdate); } } // TODO: review other fields return isoDate.getLong(field); } - return field.doGet(this); + return field.getFrom(this); } /** @@ -224,14 +369,14 @@ final class JapaneseDate * @return a {@code LocalGregorianCalendar.Date}, not null */ private static LocalGregorianCalendar.Date toPrivateJapaneseDate(LocalDate isoDate) { - LocalGregorianCalendar.Date jdate = JapaneseChrono.JCAL.newCalendarDate(null); + LocalGregorianCalendar.Date jdate = JapaneseChronology.JCAL.newCalendarDate(null); sun.util.calendar.Era sunEra = JapaneseEra.privateEraFrom(isoDate); int year = isoDate.getYear(); if (sunEra != null) { year -= sunEra.getSinceDate().getYear() - 1; } jdate.setEra(sunEra).setYear(year).setMonth(isoDate.getMonthValue()).setDayOfMonth(isoDate.getDayOfMonth()); - JapaneseChrono.JCAL.normalize(jdate); + JapaneseChronology.JCAL.normalize(jdate); return jdate; } @@ -266,6 +411,40 @@ final class JapaneseDate return (JapaneseDate) ChronoLocalDate.super.with(field, newValue); } + @Override + public Era getEra() { + return era; + } + + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + public JapaneseDate with(TemporalAdjuster adjuster) { + return (JapaneseDate)super.with(adjuster); + } + + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + public JapaneseDate plus(TemporalAmount amount) { + return (JapaneseDate)super.plus(amount); + } + + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + public JapaneseDate minus(TemporalAmount amount) { + return (JapaneseDate)super.minus(amount); + } //----------------------------------------------------------------------- /** * Returns a copy of this date with the year altered. @@ -282,7 +461,7 @@ final class JapaneseDate * @throws DateTimeException if {@code year} is invalid */ private JapaneseDate withYear(JapaneseEra era, int yearOfEra) { - int year = JapaneseChrono.INSTANCE.prolepticYear(era, yearOfEra); + int year = JapaneseChronology.INSTANCE.prolepticYear(era, yearOfEra); return with(isoDate.withYear(year)); } @@ -314,15 +493,60 @@ final class JapaneseDate return with(isoDate.plusMonths(months)); } + @Override + JapaneseDate plusWeeks(long weeksToAdd) { + return with(isoDate.plusWeeks(weeksToAdd)); + } + @Override JapaneseDate plusDays(long days) { return with(isoDate.plusDays(days)); } + @Override + public JapaneseDate plus(long amountToAdd, TemporalUnit unit) { + return (JapaneseDate)super.plus(amountToAdd, unit); + } + + @Override + public JapaneseDate minus(long amountToAdd, TemporalUnit unit) { + return (JapaneseDate)super.minus(amountToAdd, unit); + } + + @Override + JapaneseDate minusYears(long yearsToSubtract) { + return (JapaneseDate)super.minusYears(yearsToSubtract); + } + + @Override + JapaneseDate minusMonths(long monthsToSubtract) { + return (JapaneseDate)super.minusMonths(monthsToSubtract); + } + + @Override + JapaneseDate minusWeeks(long weeksToSubtract) { + return (JapaneseDate)super.minusWeeks(weeksToSubtract); + } + + @Override + JapaneseDate minusDays(long daysToSubtract) { + return (JapaneseDate)super.minusDays(daysToSubtract); + } + private JapaneseDate with(LocalDate newDate) { return (newDate.equals(isoDate) ? this : new JapaneseDate(newDate)); } + @Override // for javadoc and covariant return type + public final ChronoLocalDateTime atTime(LocalTime localTime) { + return (ChronoLocalDateTime)super.atTime(localTime); + } + + @Override + public Period periodUntil(ChronoLocalDate endDate) { + return isoDate.periodUntil(endDate); + } + @Override // override for performance public long toEpochDay() { return isoDate.toEpochDay(); @@ -343,13 +567,13 @@ final class JapaneseDate @Override // override for performance public int hashCode() { - return getChrono().getId().hashCode() ^ isoDate.hashCode(); + return getChronology().getId().hashCode() ^ isoDate.hashCode(); } @Override public String toString() { if (era == JapaneseEra.SEIREKI) { - return getChrono().getId() + " " + isoDate.toString(); + return getChronology().getId() + " " + isoDate.toString(); } return super.toString(); } @@ -360,18 +584,17 @@ final class JapaneseDate } void writeExternal(DataOutput out) throws IOException { - // JapaneseChrono is implicit in the JAPANESE_DATE_TYPE + // JapaneseChronology is implicit in the JAPANESE_DATE_TYPE out.writeInt(get(YEAR)); out.writeByte(get(MONTH_OF_YEAR)); out.writeByte(get(DAY_OF_MONTH)); } - static ChronoLocalDate readExternal(DataInput in) throws IOException { + static JapaneseDate readExternal(DataInput in) throws IOException { int year = in.readInt(); int month = in.readByte(); int dayOfMonth = in.readByte(); - return JapaneseChrono.INSTANCE.date(year, month, dayOfMonth); + return JapaneseChronology.INSTANCE.date(year, month, dayOfMonth); } - } diff --git a/jdk/src/share/classes/java/time/calendar/JapaneseEra.java b/jdk/src/share/classes/java/time/chrono/JapaneseEra.java similarity index 97% rename from jdk/src/share/classes/java/time/calendar/JapaneseEra.java rename to jdk/src/share/classes/java/time/chrono/JapaneseEra.java index 3bc4fd720f7..675f0d664ea 100644 --- a/jdk/src/share/classes/java/time/calendar/JapaneseEra.java +++ b/jdk/src/share/classes/java/time/chrono/JapaneseEra.java @@ -54,7 +54,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package java.time.calendar; +package java.time.chrono; import java.io.DataInput; import java.io.DataOutput; @@ -64,7 +64,6 @@ import java.io.ObjectStreamException; import java.io.Serializable; import java.time.DateTimeException; import java.time.LocalDate; -import java.time.temporal.Era; import java.util.Arrays; import sun.util.calendar.CalendarDate; @@ -86,7 +85,7 @@ import sun.util.calendar.CalendarDate; * @since 1.8 */ final class JapaneseEra - implements Era, Serializable { + implements Era, Serializable { // The offset value to 0-based index from the era value. // i.e., getValue() + ERA_OFFSET == 0-based index; except that -999 is mapped to zero @@ -133,7 +132,7 @@ final class JapaneseEra private static final JapaneseEra[] KNOWN_ERAS; static { - sun.util.calendar.Era[] sunEras = JapaneseChrono.JCAL.getEras(); + sun.util.calendar.Era[] sunEras = JapaneseChronology.JCAL.getEras(); ERA_CONFIG = new sun.util.calendar.Era[sunEras.length + 1]; for (int i = 1; i < ERA_CONFIG.length; i++) { ERA_CONFIG[i] = sunEras[i - 1]; @@ -292,8 +291,8 @@ final class JapaneseEra } @Override - public JapaneseChrono getChrono() { - return JapaneseChrono.INSTANCE; + public JapaneseChronology getChronology() { + return JapaneseChronology.INSTANCE; } //----------------------------------------------------------------------- diff --git a/jdk/src/share/classes/java/time/calendar/MinguoChrono.java b/jdk/src/share/classes/java/time/chrono/MinguoChronology.java similarity index 77% rename from jdk/src/share/classes/java/time/calendar/MinguoChrono.java rename to jdk/src/share/classes/java/time/chrono/MinguoChronology.java index 70fa85a6d43..7dcf8c44344 100644 --- a/jdk/src/share/classes/java/time/calendar/MinguoChrono.java +++ b/jdk/src/share/classes/java/time/chrono/MinguoChronology.java @@ -54,18 +54,17 @@ * 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.calendar; +package java.time.chrono; import static java.time.temporal.ChronoField.YEAR; import java.io.Serializable; +import java.time.Clock; import java.time.DateTimeException; +import java.time.Instant; import java.time.LocalDate; -import java.time.temporal.Chrono; +import java.time.ZoneId; import java.time.temporal.ChronoField; -import java.time.temporal.ChronoLocalDate; -import java.time.temporal.Era; -import java.time.temporal.ISOChrono; import java.time.temporal.TemporalAccessor; import java.time.temporal.ValueRange; import java.util.Arrays; @@ -77,7 +76,7 @@ import java.util.Locale; *

    * This chronology defines the rules of the Minguo calendar system. * This calendar system is primarily used in the Republic of China, often known as Taiwan. - * Dates are aligned such that {@code 0001-01-01 (Minguo)} is {@code 1911-01-01 (ISO)}. + * Dates are aligned such that {@code 0001-01-01 (Minguo)} is {@code 1912-01-01 (ISO)}. *

    * The fields are defined as follows: *

      @@ -100,22 +99,22 @@ import java.util.Locale; * * @since 1.8 */ -public final class MinguoChrono extends Chrono implements Serializable { +public final class MinguoChronology extends Chronology implements Serializable { /** * Singleton instance for the Minguo chronology. */ - public static final MinguoChrono INSTANCE = new MinguoChrono(); + public static final MinguoChronology INSTANCE = new MinguoChronology(); /** * The singleton instance for the era ROC. */ - public static final Era ERA_ROC = MinguoEra.ROC; + public static final Era ERA_ROC = MinguoEra.ROC; /** * The singleton instance for the era BEFORE_ROC. */ - public static final Era ERA_BEFORE_ROC = MinguoEra.BEFORE_ROC; + public static final Era ERA_BEFORE_ROC = MinguoEra.BEFORE_ROC; /** * Serialization version. @@ -129,7 +128,7 @@ public final class MinguoChrono extends Chrono implements Serializ /** * Restricted constructor. */ - private MinguoChrono() { + private MinguoChronology() { } /** @@ -145,8 +144,8 @@ public final class MinguoChrono extends Chrono implements Serializ /** * Gets the ID of the chronology - 'Minguo'. *

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

      * The calendar type is an identifier defined by the * Unicode Locale Data Markup Language (LDML) specification. - * It can be used to lookup the {@code Chrono} using {@link #of(String)}. + * It can be used to lookup the {@code Chronology} using {@link #of(String)}. * It can also be used as part of a locale, accessible via * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'. * @@ -175,22 +174,62 @@ public final class MinguoChrono extends Chrono implements Serializ //----------------------------------------------------------------------- @Override - public ChronoLocalDate date(int prolepticYear, int month, int dayOfMonth) { + public MinguoDate date(int prolepticYear, int month, int dayOfMonth) { return new MinguoDate(LocalDate.of(prolepticYear + YEARS_DIFFERENCE, month, dayOfMonth)); } @Override - public ChronoLocalDate dateYearDay(int prolepticYear, int dayOfYear) { + public MinguoDate dateYearDay(int prolepticYear, int dayOfYear) { return new MinguoDate(LocalDate.ofYearDay(prolepticYear + YEARS_DIFFERENCE, dayOfYear)); } @Override - public ChronoLocalDate date(TemporalAccessor temporal) { + public MinguoDate date(TemporalAccessor temporal) { if (temporal instanceof MinguoDate) { return (MinguoDate) temporal; } return new MinguoDate(LocalDate.from(temporal)); } + @Override + public MinguoDate date(Era era, int yearOfEra, int month, int dayOfMonth) { + return date(prolepticYear(era, yearOfEra), month, dayOfMonth); + + } + + @Override + public MinguoDate dateYearDay(Era era, int yearOfEra, int dayOfYear) { + return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear); + } + + @Override + public MinguoDate dateNow() { + return dateNow(Clock.systemDefaultZone()); + } + + @Override + public MinguoDate dateNow(ZoneId zone) { + return dateNow(Clock.system(zone)); + } + + @Override + public MinguoDate dateNow(Clock clock) { + return date(LocalDate.now(clock)); + } + + @Override + public ChronoLocalDateTime localDateTime(TemporalAccessor temporal) { + return (ChronoLocalDateTime)super.localDateTime(temporal); + } + + @Override + public ChronoZonedDateTime zonedDateTime(TemporalAccessor temporal) { + return (ChronoZonedDateTime)super.zonedDateTime(temporal); + } + + @Override + public ChronoZonedDateTime zonedDateTime(Instant instant, ZoneId zone) { + return (ChronoZonedDateTime)super.zonedDateTime(instant, zone); + } //----------------------------------------------------------------------- /** @@ -205,11 +244,11 @@ public final class MinguoChrono extends Chrono implements Serializ */ @Override public boolean isLeapYear(long prolepticYear) { - return ISOChrono.INSTANCE.isLeapYear(prolepticYear + YEARS_DIFFERENCE); + return IsoChronology.INSTANCE.isLeapYear(prolepticYear + YEARS_DIFFERENCE); } @Override - public int prolepticYear(Era era, int yearOfEra) { + public int prolepticYear(Era era, int yearOfEra) { if (era instanceof MinguoEra == false) { throw new DateTimeException("Era must be MinguoEra"); } @@ -217,13 +256,13 @@ public final class MinguoChrono extends Chrono implements Serializ } @Override - public Era eraOf(int eraValue) { + public Era eraOf(int eraValue) { return MinguoEra.of(eraValue); } @Override - public List> eras() { - return Arrays.>asList(MinguoEra.values()); + public List eras() { + return Arrays.asList(MinguoEra.values()); } //----------------------------------------------------------------------- diff --git a/jdk/src/share/classes/java/time/calendar/MinguoDate.java b/jdk/src/share/classes/java/time/chrono/MinguoDate.java similarity index 53% rename from jdk/src/share/classes/java/time/calendar/MinguoDate.java rename to jdk/src/share/classes/java/time/chrono/MinguoDate.java index 39981d63353..a02bbd21cc8 100644 --- a/jdk/src/share/classes/java/time/calendar/MinguoDate.java +++ b/jdk/src/share/classes/java/time/chrono/MinguoDate.java @@ -54,9 +54,9 @@ * 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.calendar; +package java.time.chrono; -import static java.time.calendar.MinguoChrono.YEARS_DIFFERENCE; +import static java.time.chrono.MinguoChronology.YEARS_DIFFERENCE; 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; @@ -65,29 +65,37 @@ import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.io.Serializable; +import java.time.Clock; import java.time.DateTimeException; import java.time.LocalDate; +import java.time.LocalTime; +import java.time.Period; +import java.time.ZoneId; import java.time.temporal.ChronoField; -import java.time.temporal.ChronoLocalDate; +import java.time.temporal.TemporalQuery; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalAmount; import java.time.temporal.TemporalField; +import java.time.temporal.TemporalUnit; import java.time.temporal.ValueRange; import java.util.Objects; /** * A date in the Minguo calendar system. *

      - * This implements {@code ChronoLocalDate} for the {@link MinguoChrono Minguo calendar}. + * This date operates using the {@linkplain MinguoChronology Minguo calendar}. + * This calendar system is primarily used in the Republic of China, often known as Taiwan. + * Dates are aligned such that {@code 0001-01-01 (Minguo)} is {@code 1912-01-01 (ISO)}. * *

      Specification for implementors

      * This class is immutable and thread-safe. * * @since 1.8 */ -final class MinguoDate - extends ChronoDateImpl - implements ChronoLocalDate, Serializable { - // this class is package-scoped so that future conversion to public - // would not change serialization +public final class MinguoDate + extends ChronoDateImpl + implements ChronoLocalDate, Serializable { /** * Serialization version. @@ -99,6 +107,93 @@ final class MinguoDate */ private final LocalDate isoDate; + //----------------------------------------------------------------------- + /** + * Obtains the current {@code MinguoDate} 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 date using the system clock and default time-zone, not null + */ + public static MinguoDate now() { + return now(Clock.systemDefaultZone()); + } + + /** + * Obtains the current {@code MinguoDate} 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 date using the system clock, not null + */ + public static MinguoDate now(ZoneId zone) { + return now(Clock.system(zone)); + } + + /** + * Obtains the current {@code MinguoDate} 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 {@linkplain Clock dependency injection}. + * + * @param clock the clock to use, not null + * @return the current date, not null + * @throws DateTimeException if the current date cannot be obtained + */ + public static MinguoDate now(Clock clock) { + return MinguoChronology.INSTANCE.date(LocalDate.now(clock)); + } + + /** + * Obtains a {@code MinguoDate} representing a date in the Minguo calendar + * system from the proleptic-year, month-of-year and day-of-month fields. + *

      + * This returns a {@code MinguoDate} with the specified fields. + * The day must be valid for the year and month, otherwise an exception will be thrown. + * + * @param prolepticYear the Minguo proleptic-year + * @param month the Minguo month-of-year, from 1 to 12 + * @param dayOfMonth the Minguo day-of-month, from 1 to 31 + * @return the date in Minguo calendar system, not null + * @throws DateTimeException if the value of any field is out of range, + * or if the day-of-month is invalid for the month-year + */ + public static MinguoDate of(int prolepticYear, int month, int dayOfMonth) { + return new MinguoDate(LocalDate.of(prolepticYear + YEARS_DIFFERENCE, month, dayOfMonth)); + } + + /** + * Obtains a {@code MinguoDate} from a temporal object. + *

      + * This obtains a date in the Minguo calendar system based on the specified temporal. + * A {@code TemporalAccessor} represents an arbitrary set of date and time information, + * which this factory converts to an instance of {@code MinguoDate}. + *

      + * The conversion typically uses the {@link ChronoField#EPOCH_DAY EPOCH_DAY} + * field, which is standardized across calendar systems. + *

      + * This method matches the signature of the functional interface {@link TemporalQuery} + * allowing it to be used as a query via method reference, {@code MinguoDate::from}. + * + * @param temporal the temporal object to convert, not null + * @return the date in Minguo calendar system, not null + * @throws DateTimeException if unable to convert to a {@code MinguoDate} + */ + public static MinguoDate from(TemporalAccessor temporal) { + return MinguoChronology.INSTANCE.date(temporal); + } + + //----------------------------------------------------------------------- /** * Creates an instance from an ISO date. * @@ -111,8 +206,8 @@ final class MinguoDate //----------------------------------------------------------------------- @Override - public MinguoChrono getChrono() { - return MinguoChrono.INSTANCE; + public MinguoChronology getChronology() { + return MinguoChronology.INSTANCE; } @Override @@ -136,11 +231,11 @@ final class MinguoDate return ValueRange.of(1, max); } } - return getChrono().range(f); + return getChronology().range(f); } throw new DateTimeException("Unsupported field: " + field.getName()); } - return field.doRange(this); + return field.rangeRefinedBy(this); } @Override @@ -158,7 +253,7 @@ final class MinguoDate } return isoDate.getLong(field); } - return field.doGet(this); + return field.getFrom(this); } private int getProlepticYear() { @@ -194,6 +289,36 @@ final class MinguoDate return (MinguoDate) ChronoLocalDate.super.with(field, newValue); } + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + public MinguoDate with(TemporalAdjuster adjuster) { + return (MinguoDate)super.with(adjuster); + } + + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + public MinguoDate plus(TemporalAmount amount) { + return (MinguoDate)super.plus(amount); + } + + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + public MinguoDate minus(TemporalAmount amount) { + return (MinguoDate)super.minus(amount); + } + //----------------------------------------------------------------------- @Override MinguoDate plusYears(long years) { @@ -210,10 +335,55 @@ final class MinguoDate return with(isoDate.plusDays(days)); } + @Override + public MinguoDate plus(long amountToAdd, TemporalUnit unit) { + return (MinguoDate)super.plus(amountToAdd, unit); + } + + @Override + public MinguoDate minus(long amountToAdd, TemporalUnit unit) { + return (MinguoDate)super.minus(amountToAdd, unit); + } + + @Override + MinguoDate plusWeeks(long weeksToAdd) { + return (MinguoDate)super.plusWeeks(weeksToAdd); + } + + @Override + MinguoDate minusYears(long yearsToSubtract) { + return (MinguoDate)super.minusYears(yearsToSubtract); + } + + @Override + MinguoDate minusMonths(long monthsToSubtract) { + return (MinguoDate)super.minusMonths(monthsToSubtract); + } + + @Override + MinguoDate minusWeeks(long weeksToSubtract) { + return (MinguoDate)super.minusWeeks(weeksToSubtract); + } + + @Override + MinguoDate minusDays(long daysToSubtract) { + return (MinguoDate)super.minusDays(daysToSubtract); + } + private MinguoDate with(LocalDate newDate) { return (newDate.equals(isoDate) ? this : new MinguoDate(newDate)); } + @Override // for javadoc and covariant return type + public final ChronoLocalDateTime atTime(LocalTime localTime) { + return (ChronoLocalDateTime)super.atTime(localTime); + } + + @Override + public Period periodUntil(ChronoLocalDate endDate) { + return isoDate.periodUntil(endDate); + } + @Override // override for performance public long toEpochDay() { return isoDate.toEpochDay(); @@ -234,7 +404,7 @@ final class MinguoDate @Override // override for performance public int hashCode() { - return getChrono().getId().hashCode() ^ isoDate.hashCode(); + return getChronology().getId().hashCode() ^ isoDate.hashCode(); } //----------------------------------------------------------------------- @@ -243,19 +413,17 @@ final class MinguoDate } void writeExternal(DataOutput out) throws IOException { - // MinguoChrono is implicit in the MINGUO_DATE_TYPE + // MinguoChronology is implicit in the MINGUO_DATE_TYPE out.writeInt(get(YEAR)); out.writeByte(get(MONTH_OF_YEAR)); out.writeByte(get(DAY_OF_MONTH)); - } - static ChronoLocalDate readExternal(DataInput in) throws IOException { + static ChronoLocalDate readExternal(DataInput in) throws IOException { int year = in.readInt(); int month = in.readByte(); int dayOfMonth = in.readByte(); - return MinguoChrono.INSTANCE.date(year, month, dayOfMonth); + return MinguoChronology.INSTANCE.date(year, month, dayOfMonth); } - } diff --git a/jdk/src/share/classes/java/time/calendar/MinguoEra.java b/jdk/src/share/classes/java/time/chrono/MinguoEra.java similarity index 69% rename from jdk/src/share/classes/java/time/calendar/MinguoEra.java rename to jdk/src/share/classes/java/time/chrono/MinguoEra.java index 7cbf430eeea..a3646f7a3c9 100644 --- a/jdk/src/share/classes/java/time/calendar/MinguoEra.java +++ b/jdk/src/share/classes/java/time/chrono/MinguoEra.java @@ -54,23 +54,12 @@ * 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.calendar; - -import static java.time.temporal.ChronoField.ERA; +package java.time.chrono; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.time.DateTimeException; -import java.time.format.DateTimeFormatterBuilder; -import java.time.format.TextStyle; -import java.time.temporal.ChronoField; -import java.time.temporal.ChronoLocalDate; -import java.time.temporal.Era; -import java.time.temporal.Temporal; -import java.time.temporal.TemporalField; -import java.time.temporal.ValueRange; -import java.util.Locale; /** * An era in the Minguo calendar system. @@ -86,7 +75,7 @@ import java.util.Locale; * * @since 1.8 */ -enum MinguoEra implements Era { +enum MinguoEra implements Era { /** * The singleton instance for the era BEFORE_ROC, 'Before Republic of China'. @@ -135,72 +124,23 @@ enum MinguoEra implements Era { } @Override - public MinguoChrono getChrono() { - return MinguoChrono.INSTANCE; + public MinguoChronology getChronology() { + return MinguoChronology.INSTANCE; } // JDK8 default methods: //----------------------------------------------------------------------- @Override - public ChronoLocalDate date(int year, int month, int day) { - return getChrono().date(this, year, month, day); + public MinguoDate date(int year, int month, int day) { + return (MinguoDate)(getChronology().date(this, year, month, day)); } @Override - public ChronoLocalDate dateYearDay(int year, int dayOfYear) { - return getChrono().dateYearDay(this, year, dayOfYear); - } - - //----------------------------------------------------------------------- - @Override - public boolean isSupported(TemporalField field) { - if (field instanceof ChronoField) { - return field == ERA; - } - return field != null && field.doIsSupported(this); - } - - @Override - public ValueRange range(TemporalField field) { - if (field == ERA) { - return field.range(); - } else if (field instanceof ChronoField) { - throw new DateTimeException("Unsupported field: " + field.getName()); - } - return field.doRange(this); - } - - @Override - public int get(TemporalField field) { - if (field == ERA) { - return getValue(); - } - return range(field).checkValidIntValue(getLong(field), field); - } - - @Override - public long getLong(TemporalField field) { - if (field == ERA) { - return getValue(); - } else if (field instanceof ChronoField) { - throw new DateTimeException("Unsupported field: " + field.getName()); - } - return field.doGet(this); + public MinguoDate dateYearDay(int year, int dayOfYear) { + return (MinguoDate)(getChronology().dateYearDay(this, year, dayOfYear)); } //------------------------------------------------------------------------- - @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); - } - - //----------------------------------------------------------------------- private Object writeReplace() { return new Ser(Ser.MINGUO_ERA_TYPE, this); } diff --git a/jdk/src/share/classes/java/time/calendar/Ser.java b/jdk/src/share/classes/java/time/chrono/Ser.java similarity index 85% rename from jdk/src/share/classes/java/time/calendar/Ser.java rename to jdk/src/share/classes/java/time/chrono/Ser.java index 48f5c81fe05..5fec32da1a3 100644 --- a/jdk/src/share/classes/java/time/calendar/Ser.java +++ b/jdk/src/share/classes/java/time/chrono/Ser.java @@ -54,7 +54,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package java.time.calendar; +package java.time.chrono; import java.io.Externalizable; import java.io.IOException; @@ -72,7 +72,7 @@ import java.time.LocalDateTime; * 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 JAPANESE_DATE_TYPE_VERSION_2 = 21}. + * 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 @@ -94,16 +94,19 @@ final class Ser implements Externalizable { /** * Serialization version. */ - private static final long serialVersionUID = 7857518227608961174L; + private static final long serialVersionUID = -6103370247208168577L; - static final byte JAPANESE_DATE_TYPE = 1; - static final byte JAPANESE_ERA_TYPE = 2; - static final byte HIJRAH_DATE_TYPE = 3; - static final byte HIJRAH_ERA_TYPE = 4; - static final byte MINGUO_DATE_TYPE = 5; - static final byte MINGUO_ERA_TYPE = 6; - static final byte THAIBUDDHIST_DATE_TYPE = 7; - static final byte THAIBUDDHIST_ERA_TYPE = 8; + static final byte CHRONO_TYPE = 1; + static final byte CHRONO_LOCAL_DATE_TIME_TYPE = 2; + static final byte CHRONO_ZONE_DATE_TIME_TYPE = 3; + static final byte JAPANESE_DATE_TYPE = 4; + static final byte JAPANESE_ERA_TYPE = 5; + static final byte HIJRAH_DATE_TYPE = 6; + static final byte HIJRAH_ERA_TYPE = 7; + static final byte MINGUO_DATE_TYPE = 8; + static final byte MINGUO_ERA_TYPE = 9; + static final byte THAIBUDDHIST_DATE_TYPE = 10; + static final byte THAIBUDDHIST_ERA_TYPE = 11; /** The type being serialized. */ private byte type; @@ -141,6 +144,15 @@ final class Ser implements Externalizable { private static void writeInternal(byte type, Object object, ObjectOutput out) throws IOException { out.writeByte(type); switch (type) { + case CHRONO_TYPE: + ((Chronology) 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 JAPANESE_DATE_TYPE: ((JapaneseDate) object).writeExternal(out); break; @@ -189,6 +201,9 @@ final class Ser implements Externalizable { private static Object readInternal(byte type, ObjectInput in) throws IOException, ClassNotFoundException { switch (type) { + case CHRONO_TYPE: return Chronology.readExternal(in); + case CHRONO_LOCAL_DATE_TIME_TYPE: return ChronoLocalDateTimeImpl.readExternal(in); + case CHRONO_ZONE_DATE_TIME_TYPE: return ChronoZonedDateTimeImpl.readExternal(in); case JAPANESE_DATE_TYPE: return JapaneseDate.readExternal(in); case JAPANESE_ERA_TYPE: return JapaneseEra.readExternal(in); case HIJRAH_DATE_TYPE: return HijrahDate.readExternal(in); @@ -197,8 +212,7 @@ final class Ser implements Externalizable { case MINGUO_ERA_TYPE: return MinguoEra.readExternal(in); case THAIBUDDHIST_DATE_TYPE: return ThaiBuddhistDate.readExternal(in); case THAIBUDDHIST_ERA_TYPE: return ThaiBuddhistEra.readExternal(in); - default: - throw new StreamCorruptedException("Unknown serialized type"); + default: throw new StreamCorruptedException("Unknown serialized type"); } } diff --git a/jdk/src/share/classes/java/time/calendar/ThaiBuddhistChrono.java b/jdk/src/share/classes/java/time/chrono/ThaiBuddhistChronology.java similarity index 79% rename from jdk/src/share/classes/java/time/calendar/ThaiBuddhistChrono.java rename to jdk/src/share/classes/java/time/chrono/ThaiBuddhistChronology.java index 1fadb5e57c4..daf4cf91e24 100644 --- a/jdk/src/share/classes/java/time/calendar/ThaiBuddhistChrono.java +++ b/jdk/src/share/classes/java/time/chrono/ThaiBuddhistChronology.java @@ -54,18 +54,17 @@ * 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.calendar; +package java.time.chrono; import static java.time.temporal.ChronoField.YEAR; import java.io.Serializable; +import java.time.Clock; import java.time.DateTimeException; +import java.time.Instant; import java.time.LocalDate; -import java.time.temporal.Chrono; +import java.time.ZoneId; import java.time.temporal.ChronoField; -import java.time.temporal.ChronoLocalDate; -import java.time.temporal.Era; -import java.time.temporal.ISOChrono; import java.time.temporal.TemporalAccessor; import java.time.temporal.ValueRange; import java.util.Arrays; @@ -101,21 +100,21 @@ import java.util.Locale; * * @since 1.8 */ -public final class ThaiBuddhistChrono extends Chrono implements Serializable { +public final class ThaiBuddhistChronology extends Chronology implements Serializable { /** * Singleton instance of the Buddhist chronology. */ - public static final ThaiBuddhistChrono INSTANCE = new ThaiBuddhistChrono(); + public static final ThaiBuddhistChronology INSTANCE = new ThaiBuddhistChronology(); /** * The singleton instance for the era before the current one - Before Buddhist - * which has the value 0. */ - public static final Era ERA_BEFORE_BE = ThaiBuddhistEra.BEFORE_BE; + public static final Era ERA_BEFORE_BE = ThaiBuddhistEra.BEFORE_BE; /** * The singleton instance for the current era - Buddhist - which has the value 1. */ - public static final Era ERA_BE = ThaiBuddhistEra.BE; + public static final Era ERA_BE = ThaiBuddhistEra.BE; /** * Serialization version. @@ -164,7 +163,7 @@ public final class ThaiBuddhistChrono extends Chrono impleme /** * Restricted constructor. */ - private ThaiBuddhistChrono() { + private ThaiBuddhistChronology() { } /** @@ -180,8 +179,8 @@ public final class ThaiBuddhistChrono extends Chrono impleme /** * Gets the ID of the chronology - 'ThaiBuddhist'. *

      - * The ID uniquely identifies the {@code Chrono}. - * It can be used to lookup the {@code Chrono} using {@link #of(String)}. + * The ID uniquely identifies the {@code Chronology}. + * It can be used to lookup the {@code Chronology} using {@link #of(String)}. * * @return the chronology ID - 'ThaiBuddhist' * @see #getCalendarType() @@ -196,7 +195,7 @@ public final class ThaiBuddhistChrono extends Chrono impleme *

      * The calendar type is an identifier defined by the * Unicode Locale Data Markup Language (LDML) specification. - * It can be used to lookup the {@code Chrono} using {@link #of(String)}. + * It can be used to lookup the {@code Chronology} using {@link #of(String)}. * It can also be used as part of a locale, accessible via * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'. * @@ -210,22 +209,62 @@ public final class ThaiBuddhistChrono extends Chrono impleme //----------------------------------------------------------------------- @Override - public ChronoLocalDate date(int prolepticYear, int month, int dayOfMonth) { + public ThaiBuddhistDate date(int prolepticYear, int month, int dayOfMonth) { return new ThaiBuddhistDate(LocalDate.of(prolepticYear - YEARS_DIFFERENCE, month, dayOfMonth)); } @Override - public ChronoLocalDate dateYearDay(int prolepticYear, int dayOfYear) { + public ThaiBuddhistDate dateYearDay(int prolepticYear, int dayOfYear) { return new ThaiBuddhistDate(LocalDate.ofYearDay(prolepticYear - YEARS_DIFFERENCE, dayOfYear)); } @Override - public ChronoLocalDate date(TemporalAccessor temporal) { + public ThaiBuddhistDate date(TemporalAccessor temporal) { if (temporal instanceof ThaiBuddhistDate) { return (ThaiBuddhistDate) temporal; } return new ThaiBuddhistDate(LocalDate.from(temporal)); } + @Override + public ThaiBuddhistDate date(Era era, int yearOfEra, int month, int dayOfMonth) { + return date(prolepticYear(era, yearOfEra), month, dayOfMonth); + + } + + @Override + public ThaiBuddhistDate dateYearDay(Era era, int yearOfEra, int dayOfYear) { + return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear); + } + + @Override + public ThaiBuddhistDate dateNow() { + return dateNow(Clock.systemDefaultZone()); + } + + @Override + public ThaiBuddhistDate dateNow(ZoneId zone) { + return dateNow(Clock.system(zone)); + } + + @Override + public ThaiBuddhistDate dateNow(Clock clock) { + return date(LocalDate.now(clock)); + } + + @Override + public ChronoLocalDateTime localDateTime(TemporalAccessor temporal) { + return (ChronoLocalDateTime)super.localDateTime(temporal); + } + + @Override + public ChronoZonedDateTime zonedDateTime(TemporalAccessor temporal) { + return (ChronoZonedDateTime)super.zonedDateTime(temporal); + } + + @Override + public ChronoZonedDateTime zonedDateTime(Instant instant, ZoneId zone) { + return (ChronoZonedDateTime)super.zonedDateTime(instant, zone); + } //----------------------------------------------------------------------- /** @@ -240,11 +279,11 @@ public final class ThaiBuddhistChrono extends Chrono impleme */ @Override public boolean isLeapYear(long prolepticYear) { - return ISOChrono.INSTANCE.isLeapYear(prolepticYear - YEARS_DIFFERENCE); + return IsoChronology.INSTANCE.isLeapYear(prolepticYear - YEARS_DIFFERENCE); } @Override - public int prolepticYear(Era era, int yearOfEra) { + public int prolepticYear(Era era, int yearOfEra) { if (era instanceof ThaiBuddhistEra == false) { throw new DateTimeException("Era must be BuddhistEra"); } @@ -252,13 +291,13 @@ public final class ThaiBuddhistChrono extends Chrono impleme } @Override - public Era eraOf(int eraValue) { + public Era eraOf(int eraValue) { return ThaiBuddhistEra.of(eraValue); } @Override - public List> eras() { - return Arrays.>asList(ThaiBuddhistEra.values()); + public List eras() { + return Arrays.asList(ThaiBuddhistEra.values()); } //----------------------------------------------------------------------- diff --git a/jdk/src/share/classes/java/time/calendar/ThaiBuddhistDate.java b/jdk/src/share/classes/java/time/chrono/ThaiBuddhistDate.java similarity index 52% rename from jdk/src/share/classes/java/time/calendar/ThaiBuddhistDate.java rename to jdk/src/share/classes/java/time/chrono/ThaiBuddhistDate.java index 14723f66a60..e1645c5bf36 100644 --- a/jdk/src/share/classes/java/time/calendar/ThaiBuddhistDate.java +++ b/jdk/src/share/classes/java/time/chrono/ThaiBuddhistDate.java @@ -54,9 +54,9 @@ * 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.calendar; +package java.time.chrono; -import static java.time.calendar.ThaiBuddhistChrono.YEARS_DIFFERENCE; +import static java.time.chrono.ThaiBuddhistChronology.YEARS_DIFFERENCE; 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; @@ -65,29 +65,37 @@ import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.io.Serializable; +import java.time.Clock; import java.time.DateTimeException; import java.time.LocalDate; +import java.time.LocalTime; +import java.time.Period; +import java.time.ZoneId; import java.time.temporal.ChronoField; -import java.time.temporal.ChronoLocalDate; +import java.time.temporal.TemporalQuery; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalAmount; import java.time.temporal.TemporalField; +import java.time.temporal.TemporalUnit; import java.time.temporal.ValueRange; import java.util.Objects; /** * A date in the Thai Buddhist calendar system. *

      - * This implements {@code ChronoLocalDate} for the {@link ThaiBuddhistChrono Thai Buddhist calendar}. + * This date operates using the {@linkplain ThaiBuddhistChronology Thai Buddhist calendar}. + * This calendar system is primarily used in Thailand. + * Dates are aligned such that {@code 2484-01-01 (Buddhist)} is {@code 1941-01-01 (ISO)}. * *

      Specification for implementors

      * This class is immutable and thread-safe. * * @since 1.8 */ -final class ThaiBuddhistDate - extends ChronoDateImpl - implements ChronoLocalDate, Serializable { - // this class is package-scoped so that future conversion to public - // would not change serialization +public final class ThaiBuddhistDate + extends ChronoDateImpl + implements ChronoLocalDate, Serializable { /** * Serialization version. @@ -99,6 +107,93 @@ final class ThaiBuddhistDate */ private final LocalDate isoDate; + //----------------------------------------------------------------------- + /** + * Obtains the current {@code ThaiBuddhistDate} 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 date using the system clock and default time-zone, not null + */ + public static ThaiBuddhistDate now() { + return now(Clock.systemDefaultZone()); + } + + /** + * Obtains the current {@code ThaiBuddhistDate} 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 date using the system clock, not null + */ + public static ThaiBuddhistDate now(ZoneId zone) { + return now(Clock.system(zone)); + } + + /** + * Obtains the current {@code ThaiBuddhistDate} 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 {@linkplain Clock dependency injection}. + * + * @param clock the clock to use, not null + * @return the current date, not null + * @throws DateTimeException if the current date cannot be obtained + */ + public static ThaiBuddhistDate now(Clock clock) { + return ThaiBuddhistChronology.INSTANCE.date(LocalDate.now(clock)); + } + + /** + * Obtains a {@code ThaiBuddhistDate} representing a date in the Thai Buddhist calendar + * system from the proleptic-year, month-of-year and day-of-month fields. + *

      + * This returns a {@code ThaiBuddhistDate} with the specified fields. + * The day must be valid for the year and month, otherwise an exception will be thrown. + * + * @param prolepticYear the Thai Buddhist proleptic-year + * @param month the Thai Buddhist month-of-year, from 1 to 12 + * @param dayOfMonth the Thai Buddhist day-of-month, from 1 to 31 + * @return the date in Thai Buddhist calendar system, not null + * @throws DateTimeException if the value of any field is out of range, + * or if the day-of-month is invalid for the month-year + */ + public static ThaiBuddhistDate of(int prolepticYear, int month, int dayOfMonth) { + return new ThaiBuddhistDate(LocalDate.of(prolepticYear - YEARS_DIFFERENCE, month, dayOfMonth)); + } + + /** + * Obtains a {@code ThaiBuddhistDate} from a temporal object. + *

      + * This obtains a date in the Thai Buddhist calendar system based on the specified temporal. + * A {@code TemporalAccessor} represents an arbitrary set of date and time information, + * which this factory converts to an instance of {@code ThaiBuddhistDate}. + *

      + * The conversion typically uses the {@link ChronoField#EPOCH_DAY EPOCH_DAY} + * field, which is standardized across calendar systems. + *

      + * This method matches the signature of the functional interface {@link TemporalQuery} + * allowing it to be used as a query via method reference, {@code ThaiBuddhistDate::from}. + * + * @param temporal the temporal object to convert, not null + * @return the date in Thai Buddhist calendar system, not null + * @throws DateTimeException if unable to convert to a {@code ThaiBuddhistDate} + */ + public static ThaiBuddhistDate from(TemporalAccessor temporal) { + return ThaiBuddhistChronology.INSTANCE.date(temporal); + } + + //----------------------------------------------------------------------- /** * Creates an instance from an ISO date. * @@ -111,8 +206,8 @@ final class ThaiBuddhistDate //----------------------------------------------------------------------- @Override - public ThaiBuddhistChrono getChrono() { - return ThaiBuddhistChrono.INSTANCE; + public ThaiBuddhistChronology getChronology() { + return ThaiBuddhistChronology.INSTANCE; } @Override @@ -136,11 +231,11 @@ final class ThaiBuddhistDate return ValueRange.of(1, max); } } - return getChrono().range(f); + return getChronology().range(f); } throw new DateTimeException("Unsupported field: " + field.getName()); } - return field.doRange(this); + return field.rangeRefinedBy(this); } @Override @@ -158,7 +253,7 @@ final class ThaiBuddhistDate } return isoDate.getLong(field); } - return field.doGet(this); + return field.getFrom(this); } private int getProlepticYear() { @@ -194,6 +289,36 @@ final class ThaiBuddhistDate return (ThaiBuddhistDate) ChronoLocalDate.super.with(field, newValue); } + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + public ThaiBuddhistDate with(TemporalAdjuster adjuster) { + return (ThaiBuddhistDate)super.with(adjuster); + } + + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + public ThaiBuddhistDate plus(TemporalAmount amount) { + return (ThaiBuddhistDate)super.plus(amount); + } + + /** + * {@inheritDoc} + * @throws DateTimeException {@inheritDoc} + * @throws ArithmeticException {@inheritDoc} + */ + @Override + public ThaiBuddhistDate minus(TemporalAmount amount) { + return (ThaiBuddhistDate)super.minus(amount); + } + //----------------------------------------------------------------------- @Override ThaiBuddhistDate plusYears(long years) { @@ -205,15 +330,60 @@ final class ThaiBuddhistDate return with(isoDate.plusMonths(months)); } + @Override + ThaiBuddhistDate plusWeeks(long weeksToAdd) { + return (ThaiBuddhistDate)super.plusWeeks(weeksToAdd); + } + @Override ThaiBuddhistDate plusDays(long days) { return with(isoDate.plusDays(days)); } + @Override + public ThaiBuddhistDate plus(long amountToAdd, TemporalUnit unit) { + return (ThaiBuddhistDate)super.plus(amountToAdd, unit); + } + + @Override + public ThaiBuddhistDate minus(long amountToAdd, TemporalUnit unit) { + return (ThaiBuddhistDate)super.minus(amountToAdd, unit); + } + + @Override + ThaiBuddhistDate minusYears(long yearsToSubtract) { + return (ThaiBuddhistDate)super.minusYears(yearsToSubtract); + } + + @Override + ThaiBuddhistDate minusMonths(long monthsToSubtract) { + return (ThaiBuddhistDate)super.minusMonths(monthsToSubtract); + } + + @Override + ThaiBuddhistDate minusWeeks(long weeksToSubtract) { + return (ThaiBuddhistDate)super.minusWeeks(weeksToSubtract); + } + + @Override + ThaiBuddhistDate minusDays(long daysToSubtract) { + return (ThaiBuddhistDate)super.minusDays(daysToSubtract); + } + private ThaiBuddhistDate with(LocalDate newDate) { return (newDate.equals(isoDate) ? this : new ThaiBuddhistDate(newDate)); } + @Override // for javadoc and covariant return type + public final ChronoLocalDateTime atTime(LocalTime localTime) { + return (ChronoLocalDateTime)super.atTime(localTime); + } + + @Override + public Period periodUntil(ChronoLocalDate endDate) { + return isoDate.periodUntil(endDate); + } + @Override // override for performance public long toEpochDay() { return isoDate.toEpochDay(); @@ -234,7 +404,7 @@ final class ThaiBuddhistDate @Override // override for performance public int hashCode() { - return getChrono().getId().hashCode() ^ isoDate.hashCode(); + return getChronology().getId().hashCode() ^ isoDate.hashCode(); } //----------------------------------------------------------------------- @@ -243,17 +413,17 @@ final class ThaiBuddhistDate } void writeExternal(DataOutput out) throws IOException { - // MinguoChrono is implicit in the THAIBUDDHIST_DATE_TYPE + // ThaiBuddhistChronology is implicit in the THAIBUDDHIST_DATE_TYPE out.writeInt(this.get(YEAR)); out.writeByte(this.get(MONTH_OF_YEAR)); out.writeByte(this.get(DAY_OF_MONTH)); } - static ChronoLocalDate readExternal(DataInput in) throws IOException { + static ThaiBuddhistDate readExternal(DataInput in) throws IOException { int year = in.readInt(); int month = in.readByte(); int dayOfMonth = in.readByte(); - return ThaiBuddhistChrono.INSTANCE.date(year, month, dayOfMonth); + return ThaiBuddhistChronology.INSTANCE.date(year, month, dayOfMonth); } } diff --git a/jdk/src/share/classes/java/time/calendar/ThaiBuddhistEra.java b/jdk/src/share/classes/java/time/chrono/ThaiBuddhistEra.java similarity index 68% rename from jdk/src/share/classes/java/time/calendar/ThaiBuddhistEra.java rename to jdk/src/share/classes/java/time/chrono/ThaiBuddhistEra.java index 713d3e681c5..24c1bb38199 100644 --- a/jdk/src/share/classes/java/time/calendar/ThaiBuddhistEra.java +++ b/jdk/src/share/classes/java/time/chrono/ThaiBuddhistEra.java @@ -54,23 +54,13 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package java.time.calendar; +package java.time.chrono; -import static java.time.temporal.ChronoField.ERA; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.time.DateTimeException; -import java.time.format.DateTimeFormatterBuilder; -import java.time.format.TextStyle; -import java.time.temporal.ChronoField; -import java.time.temporal.ChronoLocalDate; -import java.time.temporal.Era; -import java.time.temporal.Temporal; -import java.time.temporal.TemporalField; -import java.time.temporal.ValueRange; -import java.util.Locale; /** * An era in the Thai Buddhist calendar system. @@ -85,7 +75,7 @@ import java.util.Locale; * * @since 1.8 */ -enum ThaiBuddhistEra implements Era { +enum ThaiBuddhistEra implements Era { /** * The singleton instance for the era before the current one, 'Before Buddhist Era', @@ -134,69 +124,20 @@ enum ThaiBuddhistEra implements Era { } @Override - public ThaiBuddhistChrono getChrono() { - return ThaiBuddhistChrono.INSTANCE; + public ThaiBuddhistChronology getChronology() { + return ThaiBuddhistChronology.INSTANCE; } // JDK8 default methods: //----------------------------------------------------------------------- @Override - public ChronoLocalDate date(int year, int month, int day) { - return getChrono().date(this, year, month, day); + public ThaiBuddhistDate date(int year, int month, int day) { + return (ThaiBuddhistDate)(getChronology().date(this, year, month, day)); } @Override - public ChronoLocalDate dateYearDay(int year, int dayOfYear) { - return getChrono().dateYearDay(this, year, dayOfYear); - } - - //----------------------------------------------------------------------- - @Override - public boolean isSupported(TemporalField field) { - if (field instanceof ChronoField) { - return field == ERA; - } - return field != null && field.doIsSupported(this); - } - - @Override - public ValueRange range(TemporalField field) { - if (field == ERA) { - return field.range(); - } else if (field instanceof ChronoField) { - throw new DateTimeException("Unsupported field: " + field.getName()); - } - return field.doRange(this); - } - - @Override - public int get(TemporalField field) { - if (field == ERA) { - return getValue(); - } - return range(field).checkValidIntValue(getLong(field), field); - } - - @Override - public long getLong(TemporalField field) { - if (field == ERA) { - return getValue(); - } else if (field instanceof ChronoField) { - throw new DateTimeException("Unsupported field: " + field.getName()); - } - return field.doGet(this); - } - - //------------------------------------------------------------------------- - @Override - public Temporal adjustInto(Temporal temporal) { - return temporal.with(ERA, getValue()); - } - - //----------------------------------------------------------------------- - @Override - public String getText(TextStyle style, Locale locale) { - return new DateTimeFormatterBuilder().appendText(ERA, style).toFormatter(locale).print(this); + public ThaiBuddhistDate dateYearDay(int year, int dayOfYear) { + return (ThaiBuddhistDate)(getChronology().dateYearDay(this, year, dayOfYear)); } //----------------------------------------------------------------------- diff --git a/jdk/src/share/classes/java/time/chrono/package-info.java b/jdk/src/share/classes/java/time/chrono/package-info.java new file mode 100644 index 00000000000..4f2a3f6e78c --- /dev/null +++ b/jdk/src/share/classes/java/time/chrono/package-info.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. 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. + */ + +/** + *

      + * Generic API for calendar systems other than the default ISO. + *

      + *

      + * 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 {@link java.time.chrono} package. + *

      + *

      + * A calendar system is defined by the {@link java.time.chrono.Chronology} interface, + * while a date in a calendar system is defined by the {@link java.time.chrono.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. + * See {@link java.time.chrono.ChronoLocalDate ChronoLocalDate} + * for a full discussion of the issues. + *

      + *

      + * 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. + *

      + *

      + * The supported calendar systems includes: + *

      + *
        + *
      • {@link java.time.chrono.HijrahChronology Hijrah calendar}
      • + *
      • {@link java.time.chrono.JapaneseChronology Japanese calendar}
      • + *
      • {@link java.time.chrono.MinguoChronology Minguo calendar}
      • + *
      • {@link java.time.chrono.ThaiBuddhistChronology Thai Buddhist calendar}
      • + *
      + * + *

      Example

      + *

      + * This example lists todays date for all of the available calendars. + *

      + *
      + *   // Enumerate the list of available calendars and print todays date for each.
      + *       Set<Chronology> chronos = Chronology.getAvailableChronologies();
      + *       for (Chronology chrono : chronos) {
      + *           ChronoLocalDate<?> date = chrono.dateNow();
      + *           System.out.printf("   %20s: %s%n", chrono.getId(), date.toString());
      + *       }
      + * 
      + * + *

      + * This example creates and uses a date in a named non-ISO calendar system. + *

      + *
      + *   // Print the Thai Buddhist date
      + *       ChronoLocalDate<?> now1 = Chronology.of("ThaiBuddhist").dateNow();
      + *       int day = now1.get(ChronoField.DAY_OF_MONTH);
      + *       int dow = now1.get(ChronoField.DAY_OF_WEEK);
      + *       int month = now1.get(ChronoField.MONTH_OF_YEAR);
      + *       int year = now1.get(ChronoField.YEAR);
      + *       System.out.printf("  Today is %s %s %d-%s-%d%n", now1.getChronology().getId(),
      + *                 dow, day, month, year);
      + *   // Print today's date and the last day of the year for the Thai Buddhist Calendar.
      + *       ChronoLocalDate<?> first = now1
      + *                 .with(ChronoField.DAY_OF_MONTH, 1)
      + *                 .with(ChronoField.MONTH_OF_YEAR, 1);
      + *       ChronoLocalDate<?> last = first
      + *                 .plus(1, ChronoUnit.YEARS)
      + *                 .minus(1, ChronoUnit.DAYS);
      + *       System.out.printf("  %s: 1st of year: %s; end of year: %s%n", last.getChronology().getId(),
      + *                 first, last);
      + *  
      + * + *

      + * This example creates and uses a date in a specific ThaiBuddhist calendar system. + *

      + *
      + *   // Print the Thai Buddhist date
      + *       ThaiBuddhistDate now1 = ThaiBuddhistDate.now();
      + *       int day = now1.get(ChronoField.DAY_OF_MONTH);
      + *       int dow = now1.get(ChronoField.DAY_OF_WEEK);
      + *       int month = now1.get(ChronoField.MONTH_OF_YEAR);
      + *       int year = now1.get(ChronoField.YEAR);
      + *       System.out.printf("  Today is %s %s %d-%s-%d%n", now1.getChronology().getId(),
      + *                 dow, day, month, year);
      + *
      + *   // Print today's date and the last day of the year for the Thai Buddhist Calendar.
      + *       ThaiBuddhistDate first = now1
      + *                 .with(ChronoField.DAY_OF_MONTH, 1)
      + *                 .with(ChronoField.MONTH_OF_YEAR, 1);
      + *       ThaiBuddhistDate last = first
      + *                 .plus(1, ChronoUnit.YEARS)
      + *                 .minus(1, ChronoUnit.DAYS);
      + *       System.out.printf("  %s: 1st of year: %s; end of year: %s%n", last.getChronology().getId(),
      + *                 first, last);
      + *  
      + * + *

      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.chrono; diff --git a/jdk/src/share/classes/java/time/format/DateTimeBuilder.java b/jdk/src/share/classes/java/time/format/DateTimeBuilder.java index 32c7084593a..43f85bb3de1 100644 --- a/jdk/src/share/classes/java/time/format/DateTimeBuilder.java +++ b/jdk/src/share/classes/java/time/format/DateTimeBuilder.java @@ -74,9 +74,9 @@ 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; @@ -86,34 +86,33 @@ 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 java.time.DateTimeException; import java.time.DayOfWeek; -import java.time.Instant; import java.time.LocalDate; import java.time.LocalTime; import java.time.ZoneId; -import java.time.ZoneOffset; -import java.time.temporal.Chrono; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.Chronology; +import java.time.chrono.Era; +import java.time.chrono.IsoChronology; +import java.time.chrono.JapaneseChronology; import java.time.temporal.ChronoField; +import java.time.temporal.ChronoUnit; import java.time.temporal.Queries; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalField; import java.time.temporal.TemporalQuery; -import java.util.ArrayList; import java.util.EnumMap; import java.util.HashMap; -import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.Objects; -import java.util.Set; /** * Builder that can holds date and time fields and related date and time objects. @@ -121,12 +120,11 @@ import java.util.Set; * This class still needs major revision before JDK1.8 ships. *

      * The builder is used to hold onto different elements of date and time. - * It is designed as two separate maps: + * It holds two kinds of object: *

        - *
      • from {@link java.time.temporal.TemporalField} to {@code long} value, where the value may be - * outside the valid range for the field - *
      • from {@code Class} to {@link java.time.temporal.TemporalAccessor}, holding larger scale objects - * like {@code LocalDateTime}. + *
      • a {@code Map} from {@link TemporalField} to {@code long} value, where the + * value may be outside the valid range for the field + *
      • a list of objects, such as {@code Chronology} or {@code ZoneId} *

      * *

      Specification for implementors

      @@ -135,7 +133,7 @@ import java.util.Set; * * @since 1.8 */ -public final class DateTimeBuilder +final class DateTimeBuilder implements TemporalAccessor, Cloneable { /** @@ -147,9 +145,21 @@ public final class DateTimeBuilder */ private final EnumMap standardFields = new EnumMap(ChronoField.class); /** - * The list of complete date-time objects. + * The chronology. */ - private final List objects = new ArrayList<>(2); + private Chronology chrono; + /** + * The zone. + */ + private ZoneId zone; + /** + * The date. + */ + private LocalDate date; + /** + * The time. + */ + private LocalTime time; //----------------------------------------------------------------------- /** @@ -158,74 +168,7 @@ public final class DateTimeBuilder public DateTimeBuilder() { } - /** - * Creates a new instance of the builder with a single field-value. - *

      - * This is equivalent to using {@link #addFieldValue(TemporalField, long)} on an empty builder. - * - * @param field the field to add, not null - * @param value the value to add, not null - */ - public DateTimeBuilder(TemporalField field, long value) { - addFieldValue(field, value); - } - - /** - * Creates a new instance of the builder. - * - * @param zone the zone, may be null - * @param chrono the chronology, may be null - */ - public DateTimeBuilder(ZoneId zone, Chrono chrono) { - if (zone != null) { - objects.add(zone); - } - if (chrono != null) { - objects.add(chrono); - } - } - //----------------------------------------------------------------------- - /** - * Gets the map of field-value pairs in the builder. - * - * @return a modifiable copy of the field-value map, not null - */ - public Map getFieldValueMap() { - Map map = new HashMap(standardFields); - if (otherFields != null) { - map.putAll(otherFields); - } - return map; - } - - /** - * Checks whether the specified field is present in the builder. - * - * @param field the field to find in the field-value map, not null - * @return true if the field is present - */ - public boolean containsFieldValue(TemporalField field) { - Objects.requireNonNull(field, "field"); - return standardFields.containsKey(field) || (otherFields != null && otherFields.containsKey(field)); - } - - /** - * Gets the value of the specified field from the builder. - * - * @param field the field to query in the field-value map, not null - * @return the value of the field, may be out of range - * @throws DateTimeException if the field is not present - */ - public long getFieldValue(TemporalField field) { - Objects.requireNonNull(field, "field"); - Long value = getFieldValue0(field); - if (value == null) { - throw new DateTimeException("Field not found: " + field); - } - return value; - } - private Long getFieldValue0(TemporalField field) { if (field instanceof ChronoField) { return standardFields.get(field); @@ -235,18 +178,6 @@ public final class DateTimeBuilder return null; } - /** - * Gets the value of the specified field from the builder ensuring it is valid. - * - * @param field the field to query in the field-value map, not null - * @return the value of the field, may be out of range - * @throws DateTimeException if the field is not present - */ - public long getValidFieldValue(TemporalField field) { - long value = getFieldValue(field); - return field.range().checkValidValue(value, field); - } - /** * Adds a field-value pair to the builder. *

      @@ -261,7 +192,7 @@ public final class DateTimeBuilder * @return {@code this}, for method chaining * @throws DateTimeException if the field is already present with a different value */ - public DateTimeBuilder addFieldValue(TemporalField field, long value) { + DateTimeBuilder addFieldValue(TemporalField field, long value) { Objects.requireNonNull(field, "field"); Long old = getFieldValue0(field); // check first for better error message if (old != null && old.longValue() != value) { @@ -282,125 +213,21 @@ public final class DateTimeBuilder return this; } - /** - * Removes a field-value pair from the builder. - *

      - * This removes a field, which must exist, from the builder. - * See {@link #removeFieldValues(TemporalField...)} for a version which does not throw an exception - * - * @param field the field to remove, not null - * @return the previous value of the field - * @throws DateTimeException if the field is not found - */ - public long removeFieldValue(TemporalField field) { - Objects.requireNonNull(field, "field"); - Long value = null; - if (field instanceof ChronoField) { - value = standardFields.remove(field); - } else if (otherFields != null) { - value = otherFields.remove(field); - } - if (value == null) { - throw new DateTimeException("Field not found: " + field); - } - return value; - } - //----------------------------------------------------------------------- - /** - * Removes a list of fields from the builder. - *

      - * This removes the specified fields from the builder. - * No exception is thrown if the fields are not present. - * - * @param fields the fields to remove, not null - */ - public void removeFieldValues(TemporalField... fields) { - for (TemporalField field : fields) { - if (field instanceof ChronoField) { - standardFields.remove(field); - } else if (otherFields != null) { - otherFields.remove(field); - } - } + void addObject(Chronology chrono) { + this.chrono = chrono; } - /** - * Queries a list of fields from the builder. - *

      - * This gets the value of the specified fields from the builder into - * an array where the positions match the order of the fields. - * If a field is not present, the array will contain null in that position. - * - * @param fields the fields to query, not null - * @return the array of field values, not null - */ - public Long[] queryFieldValues(TemporalField... fields) { - Long[] values = new Long[fields.length]; - int i = 0; - for (TemporalField field : fields) { - values[i++] = getFieldValue0(field); - } - return values; + void addObject(ZoneId zone) { + this.zone = zone; } - //----------------------------------------------------------------------- - /** - * Gets the list of date-time objects in the builder. - *

      - * This map is intended for use with {@link ZoneOffset} and {@link ZoneId}. - * The returned map is live and may be edited. - * - * @return the editable list of date-time objects, not null - */ - public List getCalendricalList() { - return objects; + void addObject(LocalDate date) { + this.date = date; } - /** - * Adds a date-time object to the builder. - *

      - * This adds a date-time object to the builder. - * If the object is a {@code DateTimeBuilder}, each field is added using {@link #addFieldValue}. - * If the object is not already present, then the object is added. - * If the object is already present and it is equal to that specified, no action occurs. - * If the object is already present and it is not equal to that specified, then an exception is thrown. - * - * @param object the object to add, not null - * @return {@code this}, for method chaining - * @throws DateTimeException if the field is already present with a different value - */ - public DateTimeBuilder addCalendrical(Object object) { - Objects.requireNonNull(object, "object"); - // special case - if (object instanceof DateTimeBuilder) { - DateTimeBuilder dtb = (DateTimeBuilder) object; - for (TemporalField field : dtb.getFieldValueMap().keySet()) { - addFieldValue(field, dtb.getFieldValue(field)); - } - return this; - } - if (object instanceof Instant) { - addFieldValue(INSTANT_SECONDS, ((Instant) object).getEpochSecond()); - addFieldValue(NANO_OF_SECOND, ((Instant) object).getNano()); - } else { - objects.add(object); - } -// TODO -// // preserve state of builder until validated -// Class cls = dateTime.extract(Class.class); -// if (cls == null) { -// throw new DateTimeException("Invalid dateTime, unable to extract Class"); -// } -// Object obj = objects.get(cls); -// if (obj != null) { -// if (obj.equals(dateTime) == false) { -// throw new DateTimeException("Conflict found: " + dateTime.getClass().getSimpleName() + " " + obj + " differs from " + dateTime + ": " + this); -// } -// } else { -// objects.put(cls, dateTime); -// } - return this; + void addObject(LocalTime time) { + this.time = time; } //----------------------------------------------------------------------- @@ -413,21 +240,7 @@ public final class DateTimeBuilder * * @return {@code this}, for method chaining */ - public DateTimeBuilder resolve() { - splitObjects(); - // handle unusual fields - if (otherFields != null) { - outer: - while (true) { - Set> entrySet = new HashSet<>(otherFields.entrySet()); - for (Entry entry : entrySet) { - if (entry.getKey().resolve(this, entry.getValue())) { - continue outer; - } - } - break; - } - } + DateTimeBuilder resolve() { // handle standard fields mergeDate(); mergeTime(); @@ -441,11 +254,39 @@ public final class DateTimeBuilder return; } - // normalize fields - if (standardFields.containsKey(EPOCH_MONTH)) { - long em = standardFields.remove(EPOCH_MONTH); - addFieldValue(MONTH_OF_YEAR, (em % 12) + 1); - addFieldValue(YEAR, (em / 12) + 1970); + Era era = null; + if (chrono == IsoChronology.INSTANCE) { + // normalize fields + if (standardFields.containsKey(EPOCH_MONTH)) { + long em = standardFields.remove(EPOCH_MONTH); + addFieldValue(MONTH_OF_YEAR, (em % 12) + 1); + addFieldValue(YEAR, (em / 12) + 1970); + } + } else { + // TODO: revisit EPOCH_MONTH calculation in non-ISO chronology + // Handle EPOCH_MONTH here for non-ISO Chronology + if (standardFields.containsKey(EPOCH_MONTH)) { + long em = standardFields.remove(EPOCH_MONTH); + ChronoLocalDate chronoDate = chrono.date(LocalDate.ofEpochDay(0L)); + chronoDate = chronoDate.plus(em, ChronoUnit.MONTHS); + LocalDate date = LocalDate.ofEpochDay(chronoDate.toEpochDay()); + checkDate(date); + return; + } + List eras = chrono.eras(); + if (!eras.isEmpty()) { + if (standardFields.containsKey(ERA)) { + long index = standardFields.remove(ERA); + era = chrono.eraOf((int) index); + } else { + era = eras.get(eras.size() - 1); // current Era + } + if (standardFields.containsKey(YEAR_OF_ERA)) { + Long y = standardFields.remove(YEAR_OF_ERA); + putFieldValue0(YEAR, y); + } + } + } // build date @@ -455,7 +296,19 @@ public final class DateTimeBuilder int y = Math.toIntExact(standardFields.remove(YEAR)); int moy = Math.toIntExact(standardFields.remove(MONTH_OF_YEAR)); int dom = Math.toIntExact(standardFields.remove(DAY_OF_MONTH)); - checkDate(LocalDate.of(y, moy, dom)); + LocalDate date; + if (chrono == IsoChronology.INSTANCE) { + date = LocalDate.of(y, moy, dom); + } else { + ChronoLocalDate chronoDate; + if (era == null) { + chronoDate = chrono.date(y, moy, dom); + } else { + chronoDate = era.date(y, moy, dom); + } + date = LocalDate.ofEpochDay(chronoDate.toEpochDay()); + } + checkDate(date); return; } if (standardFields.containsKey(ALIGNED_WEEK_OF_MONTH)) { @@ -464,7 +317,20 @@ public final class DateTimeBuilder int moy = Math.toIntExact(standardFields.remove(MONTH_OF_YEAR)); int aw = Math.toIntExact(standardFields.remove(ALIGNED_WEEK_OF_MONTH)); int ad = Math.toIntExact(standardFields.remove(ALIGNED_DAY_OF_WEEK_IN_MONTH)); - checkDate(LocalDate.of(y, moy, 1).plusDays((aw - 1) * 7 + (ad - 1))); + LocalDate date; + if (chrono == IsoChronology.INSTANCE) { + date = LocalDate.of(y, moy, 1).plusDays((aw - 1) * 7 + (ad - 1)); + } else { + ChronoLocalDate chronoDate; + if (era == null) { + chronoDate = chrono.date(y, moy, 1); + } else { + chronoDate = era.date(y, moy, 1); + } + chronoDate = chronoDate.plus((aw - 1) * 7 + (ad - 1), ChronoUnit.DAYS); + date = LocalDate.ofEpochDay(chronoDate.toEpochDay()); + } + checkDate(date); return; } if (standardFields.containsKey(DAY_OF_WEEK)) { @@ -472,7 +338,20 @@ public final class DateTimeBuilder int moy = Math.toIntExact(standardFields.remove(MONTH_OF_YEAR)); int aw = Math.toIntExact(standardFields.remove(ALIGNED_WEEK_OF_MONTH)); int dow = Math.toIntExact(standardFields.remove(DAY_OF_WEEK)); - checkDate(LocalDate.of(y, moy, 1).plusDays((aw - 1) * 7).with(nextOrSame(DayOfWeek.of(dow)))); + LocalDate date; + if (chrono == IsoChronology.INSTANCE) { + date = LocalDate.of(y, moy, 1).plusDays((aw - 1) * 7).with(nextOrSame(DayOfWeek.of(dow))); + } else { + ChronoLocalDate chronoDate; + if (era == null) { + chronoDate = chrono.date(y, moy, 1); + } else { + chronoDate = era.date(y, moy, 1); + } + chronoDate = chronoDate.plus((aw - 1) * 7, ChronoUnit.DAYS).with(nextOrSame(DayOfWeek.of(dow))); + date = LocalDate.ofEpochDay(chronoDate.toEpochDay()); + } + checkDate(date); return; } } @@ -480,7 +359,19 @@ public final class DateTimeBuilder if (standardFields.containsKey(DAY_OF_YEAR)) { int y = Math.toIntExact(standardFields.remove(YEAR)); int doy = Math.toIntExact(standardFields.remove(DAY_OF_YEAR)); - checkDate(LocalDate.ofYearDay(y, doy)); + LocalDate date; + if (chrono == IsoChronology.INSTANCE) { + date = LocalDate.ofYearDay(y, doy); + } else { + ChronoLocalDate chronoDate; + if (era == null) { + chronoDate = chrono.dateYearDay(y, doy); + } else { + chronoDate = era.dateYearDay(y, doy); + } + date = LocalDate.ofEpochDay(chronoDate.toEpochDay()); + } + checkDate(date); return; } if (standardFields.containsKey(ALIGNED_WEEK_OF_YEAR)) { @@ -488,14 +379,40 @@ public final class DateTimeBuilder int y = Math.toIntExact(standardFields.remove(YEAR)); int aw = Math.toIntExact(standardFields.remove(ALIGNED_WEEK_OF_YEAR)); int ad = Math.toIntExact(standardFields.remove(ALIGNED_DAY_OF_WEEK_IN_YEAR)); - checkDate(LocalDate.of(y, 1, 1).plusDays((aw - 1) * 7 + (ad - 1))); + LocalDate date; + if (chrono == IsoChronology.INSTANCE) { + date = LocalDate.of(y, 1, 1).plusDays((aw - 1) * 7 + (ad - 1)); + } else { + ChronoLocalDate chronoDate; + if (era == null) { + chronoDate = chrono.dateYearDay(y, 1); + } else { + chronoDate = era.dateYearDay(y, 1); + } + chronoDate = chronoDate.plus((aw - 1) * 7 + (ad - 1), ChronoUnit.DAYS); + date = LocalDate.ofEpochDay(chronoDate.toEpochDay()); + } + checkDate(date); return; } if (standardFields.containsKey(DAY_OF_WEEK)) { int y = Math.toIntExact(standardFields.remove(YEAR)); int aw = Math.toIntExact(standardFields.remove(ALIGNED_WEEK_OF_YEAR)); int dow = Math.toIntExact(standardFields.remove(DAY_OF_WEEK)); - checkDate(LocalDate.of(y, 1, 1).plusDays((aw - 1) * 7).with(nextOrSame(DayOfWeek.of(dow)))); + LocalDate date; + if (chrono == IsoChronology.INSTANCE) { + date = LocalDate.of(y, 1, 1).plusDays((aw - 1) * 7).with(nextOrSame(DayOfWeek.of(dow))); + } else { + ChronoLocalDate chronoDate; + if (era == null) { + chronoDate = chrono.dateYearDay(y, 1); + } else { + chronoDate = era.dateYearDay(y, 1); + } + chronoDate = chronoDate.plus((aw - 1) * 7, ChronoUnit.DAYS).with(nextOrSame(DayOfWeek.of(dow))); + date = LocalDate.ofEpochDay(chronoDate.toEpochDay()); + } + checkDate(date); return; } } @@ -503,9 +420,7 @@ public final class DateTimeBuilder } private void checkDate(LocalDate date) { - // TODO: this doesn't handle aligned weeks over into next month which would otherwise be valid - - addCalendrical(date); + addObject(date); for (ChronoField field : standardFields.keySet()) { long val1; try { @@ -594,96 +509,66 @@ public final class DateTimeBuilder int somVal = Math.toIntExact(som); if (nos != null) { int nosVal = Math.toIntExact(nos); - addCalendrical(LocalTime.of(hodVal, mohVal, somVal, nosVal)); + addObject(LocalTime.of(hodVal, mohVal, somVal, nosVal)); } else { - addCalendrical(LocalTime.of(hodVal, mohVal, somVal)); + addObject(LocalTime.of(hodVal, mohVal, somVal)); } } else { - addCalendrical(LocalTime.of(hodVal, mohVal)); + addObject(LocalTime.of(hodVal, mohVal)); } } else { - addCalendrical(LocalTime.of(hodVal, 0)); - } - } - } - - private void splitObjects() { - List objectsToAdd = new ArrayList<>(); - for (Object object : objects) { - if (object instanceof LocalDate || object instanceof LocalTime || - object instanceof ZoneId || object instanceof Chrono) { - continue; - } - if (object instanceof ZoneOffset || object instanceof Instant) { - objectsToAdd.add(object); - - } else if (object instanceof TemporalAccessor) { - // TODO -// TemporalAccessor dt = (TemporalAccessor) object; -// objectsToAdd.add(dt.extract(LocalDate.class)); -// objectsToAdd.add(dt.extract(LocalTime.class)); -// objectsToAdd.add(dt.extract(ZoneId.class)); -// objectsToAdd.add(dt.extract(Chrono.class)); - } - } - for (Object object : objectsToAdd) { - if (object != null) { - addCalendrical(object); + addObject(LocalTime.of(hodVal, 0)); } } } //----------------------------------------------------------------------- @Override - public R query(TemporalQuery query) { - if (query == Queries.zoneId()) { - return (R) extract(ZoneId.class); + public boolean isSupported(TemporalField field) { + if (field == null) { + return false; } - if (query == Queries.offset()) { - ZoneOffset offset = extract(ZoneOffset.class); - if (offset == null && standardFields.containsKey(OFFSET_SECONDS)) { - offset = ZoneOffset.ofTotalSeconds(Math.toIntExact(standardFields.get(OFFSET_SECONDS))); + return standardFields.containsKey(field) || + (otherFields != null && otherFields.containsKey(field)) || + (date != null && date.isSupported(field)) || + (time != null && time.isSupported(field)); + } + + @Override + public long getLong(TemporalField field) { + Objects.requireNonNull(field, "field"); + Long value = getFieldValue0(field); + if (value == null) { + if (date != null && date.isSupported(field)) { + return date.getLong(field); } - return (R) offset; + if (time != null && time.isSupported(field)) { + return time.getLong(field); + } + throw new DateTimeException("Field not found: " + field); } - if (query == Queries.chrono()) { - return extract(Chrono.class); - } - // incomplete, so no need to handle PRECISION - return TemporalAccessor.super.query(query); + return value; } @SuppressWarnings("unchecked") - public R extract(Class type) { - R result = null; - for (Object obj : objects) { - if (type.isInstance(obj)) { - if (result != null && result.equals(obj) == false) { - throw new DateTimeException("Conflict found: " + type.getSimpleName() + " differs " + result + " vs " + obj + ": " + this); - } - result = (R) obj; - } - } - return result; - } - - //----------------------------------------------------------------------- - /** - * Clones this builder, creating a new independent copy referring to the - * same map of fields and objects. - * - * @return the cloned builder, not null - */ @Override - public DateTimeBuilder clone() { - DateTimeBuilder dtb = new DateTimeBuilder(); - dtb.objects.addAll(this.objects); - dtb.standardFields.putAll(this.standardFields); - dtb.standardFields.putAll(this.standardFields); - if (this.otherFields != null) { - dtb.otherFields.putAll(this.otherFields); + public R query(TemporalQuery query) { + if (query == Queries.zoneId()) { + return (R) zone; + } else if (query == Queries.chronology()) { + return (R) chrono; + } else if (query == Queries.localDate()) { + return (R) date; + } else if (query == Queries.localTime()) { + return (R) time; + } else if (query == Queries.zone() || query == Queries.offset()) { + return query.queryFrom(this); + } else if (query == Queries.precision()) { + return null; // not a complete date/time } - return dtb; + // inline TemporalAccessor.super.query(query) as an optimization + // non-JDK classes are not permitted to make this optimization + return query.queryFrom(this); } //----------------------------------------------------------------------- @@ -691,29 +576,20 @@ public final class DateTimeBuilder public String toString() { StringBuilder buf = new StringBuilder(128); buf.append("DateTimeBuilder["); - Map fields = getFieldValueMap(); + Map fields = new HashMap<>(); + fields.putAll(standardFields); + if (otherFields != null) { + fields.putAll(otherFields); + } if (fields.size() > 0) { buf.append("fields=").append(fields); } - if (objects.size() > 0) { - if (fields.size() > 0) { - buf.append(", "); - } - buf.append("objects=").append(objects); - } + buf.append(", ").append(chrono); + buf.append(", ").append(zone); + buf.append(", ").append(date); + buf.append(", ").append(time); buf.append(']'); return buf.toString(); } - //----------------------------------------------------------------------- - @Override - public boolean isSupported(TemporalField field) { - return field != null && containsFieldValue(field); - } - - @Override - public long getLong(TemporalField field) { - return getFieldValue(field); - } - } diff --git a/jdk/src/share/classes/java/time/format/DateTimeFormatStyleProvider.java b/jdk/src/share/classes/java/time/format/DateTimeFormatStyleProvider.java index e50ce265629..eba19f88d6e 100644 --- a/jdk/src/share/classes/java/time/format/DateTimeFormatStyleProvider.java +++ b/jdk/src/share/classes/java/time/format/DateTimeFormatStyleProvider.java @@ -61,12 +61,13 @@ */ package java.time.format; -import java.text.DateFormat; import java.text.SimpleDateFormat; -import java.time.temporal.Chrono; +import java.time.chrono.Chronology; import java.util.Locale; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import sun.util.locale.provider.LocaleProviderAdapter; +import sun.util.locale.provider.LocaleResources; /** * A provider to obtain date-time formatters for a style. @@ -110,44 +111,36 @@ final class DateTimeFormatStyleProvider { * @throws IllegalArgumentException if both format styles are null or if the locale is not recognized */ public DateTimeFormatter getFormatter( - FormatStyle dateStyle, FormatStyle timeStyle, Chrono chrono, Locale locale) { + FormatStyle dateStyle, FormatStyle timeStyle, Chronology chrono, Locale locale) { if (dateStyle == null && timeStyle == null) { throw new IllegalArgumentException("Date and Time style must not both be null"); } String key = chrono.getId() + '|' + locale.toString() + '|' + dateStyle + timeStyle; Object cached = FORMATTER_CACHE.get(key); if (cached != null) { - if (cached.equals("")) { - throw new IllegalArgumentException("Unable to convert DateFormat to DateTimeFormatter"); - } return (DateTimeFormatter) cached; } - DateFormat dateFormat; - if (dateStyle != null) { - if (timeStyle != null) { - dateFormat = DateFormat.getDateTimeInstance(convertStyle(dateStyle), convertStyle(timeStyle), locale); - } else { - dateFormat = DateFormat.getDateInstance(convertStyle(dateStyle), locale); - } - } else { - dateFormat = DateFormat.getTimeInstance(convertStyle(timeStyle), locale); - } - if (dateFormat instanceof SimpleDateFormat) { - String pattern = ((SimpleDateFormat) dateFormat).toPattern(); - DateTimeFormatter formatter = new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter(locale); - FORMATTER_CACHE.putIfAbsent(key, formatter); - return formatter; - } - FORMATTER_CACHE.putIfAbsent(key, ""); - throw new IllegalArgumentException("Unable to convert DateFormat to DateTimeFormatter"); + + LocaleResources lr = LocaleProviderAdapter.getResourceBundleBased() + .getLocaleResources(locale); + String pattern = lr.getCldrDateTimePattern(convertStyle(timeStyle), convertStyle(dateStyle), + chrono.getCalendarType()); + DateTimeFormatter formatter = new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter(locale); + FORMATTER_CACHE.putIfAbsent(key, formatter); + return formatter; } /** - * Converts the enum style to the old format style. - * @param style the enum style, not null - * @return the int style + * Converts the enum style to the java.util.Calendar style. Standalone styles + * are not supported. + * + * @param style the enum style + * @return the int style, or -1 if style is null, indicating unrequired */ private int convertStyle(FormatStyle style) { + if (style == null) { + return -1; + } return style.ordinal(); // indices happen to align } diff --git a/jdk/src/share/classes/java/time/format/DateTimeFormatter.java b/jdk/src/share/classes/java/time/format/DateTimeFormatter.java index 1b9aa2c8e4d..58a1c9263a9 100644 --- a/jdk/src/share/classes/java/time/format/DateTimeFormatter.java +++ b/jdk/src/share/classes/java/time/format/DateTimeFormatter.java @@ -61,6 +61,16 @@ */ package 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.SECOND_OF_MINUTE; +import static java.time.temporal.ChronoField.YEAR; + import java.io.IOException; import java.text.FieldPosition; import java.text.Format; @@ -68,21 +78,32 @@ import java.text.ParseException; import java.text.ParsePosition; import java.time.DateTimeException; import java.time.ZoneId; +import java.time.ZoneOffset; import java.time.format.DateTimeFormatterBuilder.CompositePrinterParser; -import java.time.temporal.Chrono; +import java.time.chrono.Chronology; +import java.time.temporal.ChronoField; +import java.time.temporal.IsoFields; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalQuery; +import java.util.HashMap; import java.util.Locale; +import java.util.Map; import java.util.Objects; /** * Formatter for printing and parsing date-time objects. *

      - * This class provides the main application entry point for printing and parsing. - * Common instances of {@code DateTimeFormatter} are provided by {@link DateTimeFormatters}. - * For more complex formatters, a {@link DateTimeFormatterBuilder builder} is provided. + * This class provides the main application entry point for printing and parsing + * and provides common implementations of {@code DateTimeFormatter}: + *

        + *
      • Using pattern letters, such as {@code yyyy-MMM-dd} + *
      • Using localized styles, such as {@code long} or {@code medium} + *
      • Using predefined constants, such as {@code ISO_LOCAL_DATE} + *

      + * *

      - * In most cases, it is not necessary to use this class directly when formatting. + * In most cases, provided formatters will be sufficient. + * For more complex formatters, a {@link DateTimeFormatterBuilder builder} is provided. * The main date-time classes provide two methods - one for printing, * {@code toString(DateTimeFormatter formatter)}, and one for parsing, * {@code parse(CharSequence text, DateTimeFormatter formatter)}. @@ -91,7 +112,7 @@ import java.util.Objects; * String text = date.toString(formatter); * LocalDate date = LocalDate.parse(text, formatter); * - * Some aspects of printing and parsing are dependent on the locale. + * Some aspects of formatting and parsing are dependent on the locale. * The locale can be changed using the {@link #withLocale(Locale)} method * which returns a new formatter in the requested locale. *

      @@ -120,12 +141,781 @@ public final class DateTimeFormatter { /** * The chronology to use for formatting, null for no override. */ - private final Chrono chrono; + private final Chronology chrono; /** * The zone to use for formatting, null for no override. */ private final ZoneId zone; + //----------------------------------------------------------------------- + /** + * Creates a formatter using the specified pattern. + *

      + * This method will create a formatter based on a simple pattern of letters and symbols. + * For example, {@code d MMM yyyy} will format 2011-12-03 as '3 Dec 2011'. + *

      + * The returned formatter will use the default locale, but this can be changed + * using {@link DateTimeFormatter#withLocale(Locale)}. + *

      + * All letters 'A' to 'Z' and 'a' to 'z' are reserved as pattern letters. + * The following pattern letters are defined: + *

      +     *  Symbol  Meaning                     Presentation      Examples
      +     *  ------  -------                     ------------      -------
      +     *   G       era                         text              A; AD; Anno Domini
      +     *   y       year                        year              2004; 04
      +     *   D       day-of-year                 number            189
      +     *   M       month-of-year               number/text       7; 07; Jul; July; J
      +     *   d       day-of-month                number            10
      +     *
      +     *   Q       quarter-of-year             number/text       3; 03; Q3
      +     *   Y       week-based-year             year              1996; 96
      +     *   w       week-of-year                number            27
      +     *   W       week-of-month               number            27
      +     *   e       localized day-of-week       number            2; Tue; Tuesday; T
      +     *   E       day-of-week                 number/text       2; Tue; Tuesday; T
      +     *   F       week-of-month               number            3
      +     *
      +     *   a       am-pm-of-day                text              PM
      +     *   h       clock-hour-of-am-pm (1-12)  number            12
      +     *   K       hour-of-am-pm (0-11)        number            0
      +     *   k       clock-hour-of-am-pm (1-24)  number            0
      +     *
      +     *   H       hour-of-day (0-23)          number            0
      +     *   m       minute-of-hour              number            30
      +     *   s       second-of-minute            number            55
      +     *   S       fraction-of-second          fraction          978
      +     *   A       milli-of-day                number            1234
      +     *   n       nano-of-second              number            987654321
      +     *   N       nano-of-day                 number            1234000000
      +     *
      +     *   V       time-zone ID                zone-id           America/Los_Angeles; Z; -08:30
      +     *   z       time-zone name              zone-name         Pacific Standard Time; PST
      +     *   X       zone-offset 'Z' for zero    offset-X          Z; -08; -0830; -08:30; -083015; -08:30:15;
      +     *   x       zone-offset                 offset-x          +0000; -08; -0830; -08:30; -083015; -08:30:15;
      +     *   Z       zone-offset                 offset-Z          +0000; -0800; -08:00;
      +     *
      +     *   p       pad next                    pad modifier      1
      +     *
      +     *   '       escape for text             delimiter
      +     *   ''      single quote                literal           '
      +     *   [       optional section start
      +     *   ]       optional section end
      +     *   {}      reserved for future use
      +     * 
      + *

      + * The count of pattern letters determine the format. + *

      + * Text: The text style is determined based on the number of pattern letters used. + * Less than 4 pattern letters will use the {@link TextStyle#SHORT short form}. + * Exactly 4 pattern letters will use the {@link TextStyle#FULL full form}. + * Exactly 5 pattern letters will use the {@link TextStyle#NARROW narrow form}. + *

      + * Number: If the count of letters is one, then the value is output using the minimum number + * of digits and without padding as per {@link DateTimeFormatterBuilder#appendValue(java.time.temporal.TemporalField)}. + * Otherwise, the count of digits is used as the width of the output field as per + * {@link DateTimeFormatterBuilder#appendValue(java.time.temporal.TemporalField, int)}. + *

      + * Number/Text: If the count of pattern letters is 3 or greater, use the Text rules above. + * Otherwise use the Number rules above. + *

      + * Fraction: Outputs the nano-of-second field as a fraction-of-second. + * The nano-of-second value has nine digits, thus the count of pattern letters is from 1 to 9. + * If it is less than 9, then the nano-of-second value is truncated, with only the most + * significant digits being output. + * When parsing in strict mode, the number of parsed digits must match the count of pattern letters. + * When parsing in lenient mode, the number of parsed digits must be at least the count of pattern + * letters, up to 9 digits. + *

      + * Year: The count of letters determines the minimum field width below which padding is used. + * If the count of letters is two, then a {@link DateTimeFormatterBuilder#appendValueReduced reduced} + * two digit form is used. + * For printing, this outputs the rightmost two digits. For parsing, this will parse using the + * base value of 2000, resulting in a year within the range 2000 to 2099 inclusive. + * If the count of letters is less than four (but not two), then the sign is only output for negative + * years as per {@link SignStyle#NORMAL}. + * Otherwise, the sign is output if the pad width is exceeded, as per {@link SignStyle#EXCEEDS_PAD} + *

      + * ZoneId: This outputs the time-zone ID, such as 'Europe/Paris'. + * If the count of letters is two, then the time-zone ID is output. + * Any other count of letters throws {@code IllegalArgumentException}. + *

      + * Zone names: This outputs the display name of the time-zone ID. + * If the count of letters is one, two or three, then the short name is output. + * If the count of letters is four, then the full name is output. + * Five or more letters throws {@code IllegalArgumentException}. + *

      + * Offset X and x: This formats the offset based on the number of pattern letters. + * One letter outputs just the hour', such as '+01', unless the minute is non-zero + * in which case the minute is also output, such as '+0130'. + * Two letters outputs the hour and minute, without a colon, such as '+0130'. + * Three letters outputs the hour and minute, with a colon, such as '+01:30'. + * Four letters outputs the hour and minute and optional second, without a colon, such as '+013015'. + * Five letters outputs the hour and minute and optional second, with a colon, such as '+01:30:15'. + * Six or more letters throws {@code IllegalArgumentException}. + * Pattern letter 'X' (upper case) will output 'Z' when the offset to be output would be zero, + * whereas pattern letter 'x' (lower case) will output '+00', '+0000', or '+00:00'. + *

      + * Offset Z: This formats the offset based on the number of pattern letters. + * One, two or three letters outputs the hour and minute, without a colon, such as '+0130'. + * Four or more letters throws {@code IllegalArgumentException}. + * The output will be '+0000' when the offset is zero. + *

      + * Optional section: The optional section markers work exactly like calling + * {@link DateTimeFormatterBuilder#optionalStart()} and {@link DateTimeFormatterBuilder#optionalEnd()}. + *

      + * Pad modifier: Modifies the pattern that immediately follows to be padded with spaces. + * The pad width is determined by the number of pattern letters. + * This is the same as calling {@link DateTimeFormatterBuilder#padNext(int)}. + *

      + * For example, 'ppH' outputs the hour-of-day padded on the left with spaces to a width of 2. + *

      + * Any unrecognized letter is an error. + * Any non-letter character, other than '[', ']', '{', '}' and the single quote will be output directly. + * Despite this, it is recommended to use single quotes around all characters that you want to + * output directly to ensure that future changes do not break your application. + * + * @param pattern the pattern to use, not null + * @return the formatter based on the pattern, not null + * @throws IllegalArgumentException if the pattern is invalid + * @see DateTimeFormatterBuilder#appendPattern(String) + */ + public static DateTimeFormatter ofPattern(String pattern) { + return new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter(); + } + + /** + * Creates a formatter using the specified pattern. + *

      + * This method will create a formatter based on a simple pattern of letters and symbols. + * For example, {@code d MMM yyyy} will format 2011-12-03 as '3 Dec 2011'. + *

      + * See {@link #ofPattern(String)} for details of the pattern. + *

      + * The returned formatter will use the specified locale, but this can be changed + * using {@link DateTimeFormatter#withLocale(Locale)}. + * + * @param pattern the pattern to use, not null + * @param locale the locale to use, not null + * @return the formatter based on the pattern, not null + * @throws IllegalArgumentException if the pattern is invalid + * @see DateTimeFormatterBuilder#appendPattern(String) + */ + public static DateTimeFormatter ofPattern(String pattern, Locale locale) { + return new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter(locale); + } + + //----------------------------------------------------------------------- + /** + * Returns a locale specific date format. + *

      + * This returns a formatter that will format or parse a date. + * The exact format pattern used varies by locale. + *

      + * The locale is determined from the formatter. The formatter returned directly by + * this method will use the {@link Locale#getDefault(Locale.Category) default FORMAT locale}. + * The locale can be controlled using {@link DateTimeFormatter#withLocale(Locale) withLocale(Locale)} + * on the result of this method. + *

      + * Note that the localized pattern is looked up lazily. + * This {@code DateTimeFormatter} holds the style required and the locale, + * looking up the pattern required on demand. + * + * @param dateStyle the formatter style to obtain, not null + * @return the date formatter, not null + */ + public static DateTimeFormatter ofLocalizedDate(FormatStyle dateStyle) { + Objects.requireNonNull(dateStyle, "dateStyle"); + return new DateTimeFormatterBuilder().appendLocalized(dateStyle, null).toFormatter(); + } + + /** + * Returns a locale specific time format. + *

      + * This returns a formatter that will format or parse a time. + * The exact format pattern used varies by locale. + *

      + * The locale is determined from the formatter. The formatter returned directly by + * this method will use the {@link Locale#getDefault(Locale.Category) default FORMAT locale}. + * The locale can be controlled using {@link DateTimeFormatter#withLocale(Locale) withLocale(Locale)} + * on the result of this method. + *

      + * Note that the localized pattern is looked up lazily. + * This {@code DateTimeFormatter} holds the style required and the locale, + * looking up the pattern required on demand. + * + * @param timeStyle the formatter style to obtain, not null + * @return the time formatter, not null + */ + public static DateTimeFormatter ofLocalizedTime(FormatStyle timeStyle) { + Objects.requireNonNull(timeStyle, "timeStyle"); + return new DateTimeFormatterBuilder().appendLocalized(null, timeStyle).toFormatter(); + } + + /** + * Returns a locale specific date-time formatter, which is typically of short length. + *

      + * This returns a formatter that will format or parse a date-time. + * The exact format pattern used varies by locale. + *

      + * The locale is determined from the formatter. The formatter returned directly by + * this method will use the {@link Locale#getDefault(Locale.Category) default FORMAT locale}. + * The locale can be controlled using {@link DateTimeFormatter#withLocale(Locale) withLocale(Locale)} + * on the result of this method. + *

      + * Note that the localized pattern is looked up lazily. + * This {@code DateTimeFormatter} holds the style required and the locale, + * looking up the pattern required on demand. + * + * @param dateTimeStyle the formatter style to obtain, not null + * @return the date-time formatter, not null + */ + public static DateTimeFormatter ofLocalizedDateTime(FormatStyle dateTimeStyle) { + Objects.requireNonNull(dateTimeStyle, "dateTimeStyle"); + return new DateTimeFormatterBuilder().appendLocalized(dateTimeStyle, dateTimeStyle).toFormatter(); + } + + /** + * Returns a locale specific date and time format. + *

      + * This returns a formatter that will format or parse a date-time. + * The exact format pattern used varies by locale. + *

      + * The locale is determined from the formatter. The formatter returned directly by + * this method will use the {@link Locale#getDefault() default FORMAT locale}. + * The locale can be controlled using {@link DateTimeFormatter#withLocale(Locale) withLocale(Locale)} + * on the result of this method. + *

      + * Note that the localized pattern is looked up lazily. + * This {@code DateTimeFormatter} holds the style required and the locale, + * looking up the pattern required on demand. + * + * @param dateStyle the date formatter style to obtain, not null + * @param timeStyle the time formatter style to obtain, not null + * @return the date, time or date-time formatter, not null + */ + public static DateTimeFormatter ofLocalizedDateTime(FormatStyle dateStyle, FormatStyle timeStyle) { + Objects.requireNonNull(dateStyle, "dateStyle"); + Objects.requireNonNull(timeStyle, "timeStyle"); + return new DateTimeFormatterBuilder().appendLocalized(dateStyle, timeStyle).toFormatter(); + } + + //----------------------------------------------------------------------- + /** + * Returns the ISO date formatter that formats or parses a date without an offset, + * such as '2011-12-03'. + *

      + * This returns an immutable formatter capable of formatting and parsing + * the ISO-8601 extended local date format. + * The format consists of: + *

        + *
      • Four digits or more for the {@link ChronoField#YEAR year}. + * Years in the range 0000 to 9999 will be pre-padded by zero to ensure four digits. + * Years outside that range will have a prefixed positive or negative symbol. + *
      • A dash + *
      • Two digits for the {@link ChronoField#MONTH_OF_YEAR month-of-year}. + * This is pre-padded by zero to ensure two digits. + *
      • A dash + *
      • Two digits for the {@link ChronoField#DAY_OF_MONTH day-of-month}. + * This is pre-padded by zero to ensure two digits. + *

      + */ + public static final DateTimeFormatter ISO_LOCAL_DATE; + static { + ISO_LOCAL_DATE = new DateTimeFormatterBuilder() + .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD) + .appendLiteral('-') + .appendValue(MONTH_OF_YEAR, 2) + .appendLiteral('-') + .appendValue(DAY_OF_MONTH, 2) + .toFormatter(); + } + + //----------------------------------------------------------------------- + /** + * Returns the ISO date formatter that formats or parses a date with an offset, + * such as '2011-12-03+01:00'. + *

      + * This returns an immutable formatter capable of formatting and parsing + * the ISO-8601 extended offset date format. + * The format consists of: + *

        + *
      • The {@link #ISO_LOCAL_DATE} + *
      • The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then + * they will be handled even though this is not part of the ISO-8601 standard. + * Parsing is case insensitive. + *

      + */ + public static final DateTimeFormatter ISO_OFFSET_DATE; + static { + ISO_OFFSET_DATE = new DateTimeFormatterBuilder() + .parseCaseInsensitive() + .append(ISO_LOCAL_DATE) + .appendOffsetId() + .toFormatter(); + } + + //----------------------------------------------------------------------- + /** + * Returns the ISO date formatter that formats or parses a date with the + * offset if available, such as '2011-12-03' or '2011-12-03+01:00'. + *

      + * This returns an immutable formatter capable of formatting and parsing + * the ISO-8601 extended date format. + * The format consists of: + *

        + *
      • The {@link #ISO_LOCAL_DATE} + *
      • If the offset is not available then the format is complete. + *
      • The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then + * they will be handled even though this is not part of the ISO-8601 standard. + * Parsing is case insensitive. + *

      + *

      + * As this formatter has an optional element, it may be necessary to parse using + * {@link DateTimeFormatter#parseBest}. + */ + public static final DateTimeFormatter ISO_DATE; + static { + ISO_DATE = new DateTimeFormatterBuilder() + .parseCaseInsensitive() + .append(ISO_LOCAL_DATE) + .optionalStart() + .appendOffsetId() + .toFormatter(); + } + + //----------------------------------------------------------------------- + /** + * Returns the ISO time formatter that formats or parses a time without an offset, + * such as '10:15' or '10:15:30'. + *

      + * This returns an immutable formatter capable of formatting and parsing + * the ISO-8601 extended local time format. + * The format consists of: + *

        + *
      • Two digits for the {@link ChronoField#HOUR_OF_DAY hour-of-day}. + * This is pre-padded by zero to ensure two digits. + *
      • A colon + *
      • Two digits for the {@link ChronoField#MINUTE_OF_HOUR minute-of-hour}. + * This is pre-padded by zero to ensure two digits. + *
      • If the second-of-minute is not available then the format is complete. + *
      • A colon + *
      • Two digits for the {@link ChronoField#SECOND_OF_MINUTE second-of-minute}. + * This is pre-padded by zero to ensure two digits. + *
      • If the nano-of-second is zero or not available then the format is complete. + *
      • A decimal point + *
      • One to nine digits for the {@link ChronoField#NANO_OF_SECOND nano-of-second}. + * As many digits will be output as required. + *

      + */ + public static final DateTimeFormatter ISO_LOCAL_TIME; + static { + ISO_LOCAL_TIME = new DateTimeFormatterBuilder() + .appendValue(HOUR_OF_DAY, 2) + .appendLiteral(':') + .appendValue(MINUTE_OF_HOUR, 2) + .optionalStart() + .appendLiteral(':') + .appendValue(SECOND_OF_MINUTE, 2) + .optionalStart() + .appendFraction(NANO_OF_SECOND, 0, 9, true) + .toFormatter(); + } + + //----------------------------------------------------------------------- + /** + * Returns the ISO time formatter that formats or parses a time with an offset, + * such as '10:15+01:00' or '10:15:30+01:00'. + *

      + * This returns an immutable formatter capable of formatting and parsing + * the ISO-8601 extended offset time format. + * The format consists of: + *

        + *
      • The {@link #ISO_LOCAL_TIME} + *
      • The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then + * they will be handled even though this is not part of the ISO-8601 standard. + * Parsing is case insensitive. + *

      + */ + public static final DateTimeFormatter ISO_OFFSET_TIME; + static { + ISO_OFFSET_TIME = new DateTimeFormatterBuilder() + .parseCaseInsensitive() + .append(ISO_LOCAL_TIME) + .appendOffsetId() + .toFormatter(); + } + + //----------------------------------------------------------------------- + /** + * Returns the ISO time formatter that formats or parses a time, with the + * offset if available, such as '10:15', '10:15:30' or '10:15:30+01:00'. + *

      + * This returns an immutable formatter capable of formatting and parsing + * the ISO-8601 extended offset time format. + * The format consists of: + *

        + *
      • The {@link #ISO_LOCAL_TIME} + *
      • If the offset is not available then the format is complete. + *
      • The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then + * they will be handled even though this is not part of the ISO-8601 standard. + * Parsing is case insensitive. + *

      + *

      + * As this formatter has an optional element, it may be necessary to parse using + * {@link DateTimeFormatter#parseBest}. + */ + public static final DateTimeFormatter ISO_TIME; + static { + ISO_TIME = new DateTimeFormatterBuilder() + .parseCaseInsensitive() + .append(ISO_LOCAL_TIME) + .optionalStart() + .appendOffsetId() + .toFormatter(); + } + + //----------------------------------------------------------------------- + /** + * Returns the ISO date formatter that formats or parses a date-time + * without an offset, such as '2011-12-03T10:15:30'. + *

      + * This returns an immutable formatter capable of formatting and parsing + * the ISO-8601 extended offset date-time format. + * The format consists of: + *

        + *
      • The {@link #ISO_LOCAL_DATE} + *
      • The letter 'T'. Parsing is case insensitive. + *
      • The {@link #ISO_LOCAL_TIME} + *

      + */ + public static final DateTimeFormatter ISO_LOCAL_DATE_TIME; + static { + ISO_LOCAL_DATE_TIME = new DateTimeFormatterBuilder() + .parseCaseInsensitive() + .append(ISO_LOCAL_DATE) + .appendLiteral('T') + .append(ISO_LOCAL_TIME) + .toFormatter(); + } + + //----------------------------------------------------------------------- + /** + * Returns the ISO date formatter that formats or parses a date-time + * with an offset, such as '2011-12-03T10:15:30+01:00'. + *

      + * This returns an immutable formatter capable of formatting and parsing + * the ISO-8601 extended offset date-time format. + * The format consists of: + *

        + *
      • The {@link #ISO_LOCAL_DATE_TIME} + *
      • The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then + * they will be handled even though this is not part of the ISO-8601 standard. + * Parsing is case insensitive. + *

      + */ + public static final DateTimeFormatter ISO_OFFSET_DATE_TIME; + static { + ISO_OFFSET_DATE_TIME = new DateTimeFormatterBuilder() + .parseCaseInsensitive() + .append(ISO_LOCAL_DATE_TIME) + .appendOffsetId() + .toFormatter(); + } + + //----------------------------------------------------------------------- + /** + * Returns the ISO date formatter that formats or parses a date-time with + * offset and zone, such as '2011-12-03T10:15:30+01:00[Europe/Paris]'. + *

      + * This returns an immutable formatter capable of formatting and parsing + * a format that extends the ISO-8601 extended offset date-time format + * to add the time-zone. + * The format consists of: + *

        + *
      • The {@link #ISO_OFFSET_DATE_TIME} + *
      • If the zone ID is not available or is a {@code ZoneOffset} then the format is complete. + *
      • An open square bracket '['. + *
      • The {@link ZoneId#getId() zone ID}. This is not part of the ISO-8601 standard. + * Parsing is case sensitive. + *
      • A close square bracket ']'. + *

      + */ + public static final DateTimeFormatter ISO_ZONED_DATE_TIME; + static { + ISO_ZONED_DATE_TIME = new DateTimeFormatterBuilder() + .append(ISO_OFFSET_DATE_TIME) + .optionalStart() + .appendLiteral('[') + .parseCaseSensitive() + .appendZoneRegionId() + .appendLiteral(']') + .toFormatter(); + } + + //----------------------------------------------------------------------- + /** + * Returns the ISO date formatter that formats or parses a date-time + * with the offset and zone if available, such as '2011-12-03T10:15:30', + * '2011-12-03T10:15:30+01:00' or '2011-12-03T10:15:30+01:00[Europe/Paris]'. + *

      + * This returns an immutable formatter capable of formatting and parsing + * the ISO-8601 extended offset date-time format. + * The format consists of: + *

        + *
      • The {@link #ISO_LOCAL_DATE_TIME} + *
      • If the offset is not available to format or parse then the format is complete. + *
      • The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then + * they will be handled even though this is not part of the ISO-8601 standard. + *
      • If the zone ID is not available or is a {@code ZoneOffset} then the format is complete. + *
      • An open square bracket '['. + *
      • The {@link ZoneId#getId() zone ID}. This is not part of the ISO-8601 standard. + * Parsing is case sensitive. + *
      • A close square bracket ']'. + *

      + *

      + * As this formatter has an optional element, it may be necessary to parse using + * {@link DateTimeFormatter#parseBest}. + */ + public static final DateTimeFormatter ISO_DATE_TIME; + static { + ISO_DATE_TIME = new DateTimeFormatterBuilder() + .append(ISO_LOCAL_DATE_TIME) + .optionalStart() + .appendOffsetId() + .optionalStart() + .appendLiteral('[') + .parseCaseSensitive() + .appendZoneRegionId() + .appendLiteral(']') + .toFormatter(); + } + + //----------------------------------------------------------------------- + /** + * Returns the ISO date formatter that formats or parses the ordinal date + * without an offset, such as '2012-337'. + *

      + * This returns an immutable formatter capable of formatting and parsing + * the ISO-8601 extended ordinal date format. + * The format consists of: + *

        + *
      • Four digits or more for the {@link ChronoField#YEAR year}. + * Years in the range 0000 to 9999 will be pre-padded by zero to ensure four digits. + * Years outside that range will have a prefixed positive or negative symbol. + *
      • A dash + *
      • Three digits for the {@link ChronoField#DAY_OF_YEAR day-of-year}. + * This is pre-padded by zero to ensure three digits. + *
      • If the offset is not available to format or parse then the format is complete. + *
      • The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then + * they will be handled even though this is not part of the ISO-8601 standard. + * Parsing is case insensitive. + *

      + *

      + * As this formatter has an optional element, it may be necessary to parse using + * {@link DateTimeFormatter#parseBest}. + */ + public static final DateTimeFormatter ISO_ORDINAL_DATE; + static { + ISO_ORDINAL_DATE = new DateTimeFormatterBuilder() + .parseCaseInsensitive() + .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD) + .appendLiteral('-') + .appendValue(DAY_OF_YEAR, 3) + .optionalStart() + .appendOffsetId() + .toFormatter(); + } + + //----------------------------------------------------------------------- + /** + * Returns the ISO date formatter that formats or parses the week-based date + * without an offset, such as '2012-W48-6'. + *

      + * This returns an immutable formatter capable of formatting and parsing + * the ISO-8601 extended week-based date format. + * The format consists of: + *

        + *
      • Four digits or more for the {@link IsoFields#WEEK_BASED_YEAR week-based-year}. + * Years in the range 0000 to 9999 will be pre-padded by zero to ensure four digits. + * Years outside that range will have a prefixed positive or negative symbol. + *
      • A dash + *
      • The letter 'W'. Parsing is case insensitive. + *
      • Two digits for the {@link IsoFields#WEEK_OF_WEEK_BASED_YEAR week-of-week-based-year}. + * This is pre-padded by zero to ensure three digits. + *
      • A dash + *
      • One digit for the {@link ChronoField#DAY_OF_WEEK day-of-week}. + * The value run from Monday (1) to Sunday (7). + *
      • If the offset is not available to format or parse then the format is complete. + *
      • The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then + * they will be handled even though this is not part of the ISO-8601 standard. + * Parsing is case insensitive. + *

      + *

      + * As this formatter has an optional element, it may be necessary to parse using + * {@link DateTimeFormatter#parseBest}. + */ + public static final DateTimeFormatter ISO_WEEK_DATE; + static { + ISO_WEEK_DATE = new DateTimeFormatterBuilder() + .parseCaseInsensitive() + .appendValue(IsoFields.WEEK_BASED_YEAR, 4, 10, SignStyle.EXCEEDS_PAD) + .appendLiteral("-W") + .appendValue(IsoFields.WEEK_OF_WEEK_BASED_YEAR, 2) + .appendLiteral('-') + .appendValue(DAY_OF_WEEK, 1) + .optionalStart() + .appendOffsetId() + .toFormatter(); + } + + //----------------------------------------------------------------------- + /** + * Returns the ISO instant formatter that formats or parses an instant in UTC. + *

      + * This returns an immutable formatter capable of formatting and parsing + * the ISO-8601 instant format. + * The format consists of: + *

        + *
      • The {@link #ISO_OFFSET_DATE_TIME} where the instant is converted from + * {@link ChronoField#INSTANT_SECONDS} and {@link ChronoField#NANO_OF_SECOND} + * using the {@code UTC} offset. Parsing is case insensitive. + *

      + */ + public static final DateTimeFormatter ISO_INSTANT; + static { + ISO_INSTANT = new DateTimeFormatterBuilder() + .parseCaseInsensitive() + .appendInstant() + .toFormatter(); + } + + //----------------------------------------------------------------------- + /** + * Returns the ISO date formatter that formats or parses a date without an offset, + * such as '20111203'. + *

      + * This returns an immutable formatter capable of formatting and parsing + * the ISO-8601 basic local date format. + * The format consists of: + *

        + *
      • Four digits for the {@link ChronoField#YEAR year}. + * Only years in the range 0000 to 9999 are supported. + *
      • Two digits for the {@link ChronoField#MONTH_OF_YEAR month-of-year}. + * This is pre-padded by zero to ensure two digits. + *
      • Two digits for the {@link ChronoField#DAY_OF_MONTH day-of-month}. + * This is pre-padded by zero to ensure two digits. + *
      • If the offset is not available to format or parse then the format is complete. + *
      • The {@link ZoneOffset#getId() offset ID} without colons. If the offset has + * seconds then they will be handled even though this is not part of the ISO-8601 standard. + * Parsing is case insensitive. + *

      + *

      + * As this formatter has an optional element, it may be necessary to parse using + * {@link DateTimeFormatter#parseBest}. + */ + public static final DateTimeFormatter BASIC_ISO_DATE; + static { + BASIC_ISO_DATE = new DateTimeFormatterBuilder() + .parseCaseInsensitive() + .appendValue(YEAR, 4) + .appendValue(MONTH_OF_YEAR, 2) + .appendValue(DAY_OF_MONTH, 2) + .optionalStart() + .appendOffset("+HHMMss", "Z") + .toFormatter(); + } + + //----------------------------------------------------------------------- + /** + * The RFC-1123 date-time formatter, such as 'Tue, 3 Jun 2008 11:05:30 GMT'. + *

      + * This returns an immutable formatter capable of formatting and parsing + * most of the RFC-1123 format. + * RFC-1123 updates RFC-822 changing the year from two digits to four. + * This implementation requires a four digit year. + * This implementation also does not handle North American or military zone + * names, only 'GMT' and offset amounts. + *

      + * The format consists of: + *

        + *
      • If the day-of-week is not available to format or parse then jump to day-of-month. + *
      • Three letter {@link ChronoField#DAY_OF_WEEK day-of-week} in English. + *
      • A comma + *
      • A space + *
      • One or two digits for the {@link ChronoField#DAY_OF_MONTH day-of-month}. + *
      • A space + *
      • Three letter {@link ChronoField#MONTH_OF_YEAR month-of-year} in English. + *
      • A space + *
      • Four digits for the {@link ChronoField#YEAR year}. + * Only years in the range 0000 to 9999 are supported. + *
      • A space + *
      • Two digits for the {@link ChronoField#HOUR_OF_DAY hour-of-day}. + * This is pre-padded by zero to ensure two digits. + *
      • A colon + *
      • Two digits for the {@link ChronoField#MINUTE_OF_HOUR minute-of-hour}. + * This is pre-padded by zero to ensure two digits. + *
      • If the second-of-minute is not available then jump to the next space. + *
      • A colon + *
      • Two digits for the {@link ChronoField#SECOND_OF_MINUTE second-of-minute}. + * This is pre-padded by zero to ensure two digits. + *
      • A space + *
      • The {@link ZoneOffset#getId() offset ID} without colons or seconds. + * An offset of zero uses "GMT". North American zone names and military zone names are not handled. + *

      + *

      + * Parsing is case insensitive. + */ + public static final DateTimeFormatter RFC_1123_DATE_TIME; + static { + // manually code maps to ensure correct data always used + // (locale data can be changed by application code) + Map dow = new HashMap<>(); + dow.put(1L, "Mon"); + dow.put(2L, "Tue"); + dow.put(3L, "Wed"); + dow.put(4L, "Thu"); + dow.put(5L, "Fri"); + dow.put(6L, "Sat"); + dow.put(7L, "Sun"); + Map moy = new HashMap<>(); + moy.put(1L, "Jan"); + moy.put(2L, "Feb"); + moy.put(3L, "Mar"); + moy.put(4L, "Apr"); + moy.put(5L, "May"); + moy.put(6L, "Jun"); + moy.put(7L, "Jul"); + moy.put(8L, "Aug"); + moy.put(9L, "Sep"); + moy.put(10L, "Oct"); + moy.put(11L, "Nov"); + moy.put(12L, "Dec"); + RFC_1123_DATE_TIME = new DateTimeFormatterBuilder() + .parseCaseInsensitive() + .parseLenient() + .optionalStart() + .appendText(DAY_OF_WEEK, dow) + .appendLiteral(", ") + .optionalEnd() + .appendValue(DAY_OF_MONTH, 1, 2, SignStyle.NOT_NEGATIVE) + .appendLiteral(' ') + .appendText(MONTH_OF_YEAR, moy) + .appendLiteral(' ') + .appendValue(YEAR, 4) // 2 digit year not handled + .appendLiteral(' ') + .appendValue(HOUR_OF_DAY, 2) + .appendLiteral(':') + .appendValue(MINUTE_OF_HOUR, 2) + .optionalStart() + .appendLiteral(':') + .appendValue(SECOND_OF_MINUTE, 2) + .optionalEnd() + .appendLiteral(' ') + .appendOffset("+HHMM", "GMT") // should handle UT/Z/EST/EDT/CST/CDT/MST/MDT/PST/MDT + .toFormatter(); + } + /** * Constructor. * @@ -136,7 +926,7 @@ public final class DateTimeFormatter { * @param zone the zone to use, null for no override */ DateTimeFormatter(CompositePrinterParser printerParser, Locale locale, - DateTimeFormatSymbols symbols, Chrono chrono, ZoneId zone) { + DateTimeFormatSymbols symbols, Chronology chrono, ZoneId zone) { this.printerParser = Objects.requireNonNull(printerParser, "printerParser"); this.locale = Objects.requireNonNull(locale, "locale"); this.symbols = Objects.requireNonNull(symbols, "symbols"); @@ -206,11 +996,11 @@ public final class DateTimeFormatter { *

      * This returns the override chronology, used to convert dates. * By default, a formatter has no override chronology, returning null. - * See {@link #withChrono(Chrono)} for more details on overriding. + * See {@link #withChronology(Chronology)} for more details on overriding. * * @return the chronology of this formatter, null if no override */ - public Chrono getChrono() { + public Chronology getChronology() { return chrono; } @@ -221,9 +1011,9 @@ public final class DateTimeFormatter { * with the override chronology set. * By default, a formatter has no override chronology, returning null. *

      - * If an override is added, then any date that is printed or parsed will be affected. + * If an override is added, then any date that is formatted or parsed will be affected. *

      - * When printing, if the {@code Temporal} object contains a date then it will + * When formatting, if the {@code Temporal} object contains a date then it will * be converted to a date in the override chronology. * Any time or zone will be retained unless overridden. * The converted result will behave in a manner equivalent to an implementation @@ -238,7 +1028,7 @@ public final class DateTimeFormatter { * @param chrono the new chronology, not null * @return a formatter based on this formatter with the requested override chronology, not null */ - public DateTimeFormatter withChrono(Chrono chrono) { + public DateTimeFormatter withChronology(Chronology chrono) { if (Objects.equals(this.chrono, chrono)) { return this; } @@ -266,9 +1056,9 @@ public final class DateTimeFormatter { * with the override zone set. * By default, a formatter has no override zone, returning null. *

      - * If an override is added, then any instant that is printed or parsed will be affected. + * If an override is added, then any instant that is formatted or parsed will be affected. *

      - * When printing, if the {@code Temporal} object contains an instant then it will + * When formatting, if the {@code Temporal} object contains an instant then it will * be converted to a zoned date-time using the override zone. * If the input has a chronology then it will be retained unless overridden. * If the input does not have a chronology, such as {@code Instant}, then @@ -294,53 +1084,120 @@ public final class DateTimeFormatter { //----------------------------------------------------------------------- /** - * Prints a date-time object using this formatter. + * Formats a date-time object using this formatter. *

      - * This prints the date-time to a String using the rules of the formatter. + * This formats the date-time to a String using the rules of the formatter. * - * @param temporal the temporal object to print, not null - * @return the printed string, not null - * @throws DateTimeException if an error occurs during printing + * @param temporal the temporal object to format, not null + * @return the formatted string, not null + * @throws DateTimeException if an error occurs during formatting */ - public String print(TemporalAccessor temporal) { + public String format(TemporalAccessor temporal) { StringBuilder buf = new StringBuilder(32); - printTo(temporal, buf); + formatTo(temporal, buf); return buf.toString(); } //----------------------------------------------------------------------- /** - * Prints a date-time object to an {@code Appendable} using this formatter. + * Formats a date-time object to an {@code Appendable} using this formatter. *

      - * This prints the date-time to the specified destination. + * This outputs the formatted date-time to the specified destination. * {@link Appendable} is a general purpose interface that is implemented by all * key character output classes including {@code StringBuffer}, {@code StringBuilder}, * {@code PrintStream} and {@code Writer}. *

      * Although {@code Appendable} methods throw an {@code IOException}, this method does not. * Instead, any {@code IOException} is wrapped in a runtime exception. - * See {@link DateTimePrintException#rethrowIOException()} for a means - * to extract the {@code IOException}. * - * @param temporal the temporal object to print, not null - * @param appendable the appendable to print to, not null - * @throws DateTimeException if an error occurs during printing + * @param temporal the temporal object to format, not null + * @param appendable the appendable to format to, not null + * @throws DateTimeException if an error occurs during formatting */ - public void printTo(TemporalAccessor temporal, Appendable appendable) { + public void formatTo(TemporalAccessor temporal, Appendable appendable) { Objects.requireNonNull(temporal, "temporal"); Objects.requireNonNull(appendable, "appendable"); try { DateTimePrintContext context = new DateTimePrintContext(temporal, this); if (appendable instanceof StringBuilder) { - printerParser.print(context, (StringBuilder) appendable); + printerParser.format(context, (StringBuilder) appendable); } else { // buffer output to avoid writing to appendable in case of error StringBuilder buf = new StringBuilder(32); - printerParser.print(context, buf); + printerParser.format(context, buf); appendable.append(buf); } } catch (IOException ex) { - throw new DateTimePrintException(ex.getMessage(), ex); + throw new DateTimeException(ex.getMessage(), ex); + } + } + + //----------------------------------------------------------------------- + /** + * Fully parses the text producing a temporal object. + *

      + * This parses the entire text producing a temporal object. + * It is typically more useful to use {@link #parse(CharSequence, TemporalQuery)}. + * The result of this method is {@code TemporalAccessor} which has been resolved, + * applying basic validation checks to help ensure a valid date-time. + *

      + * If the parse completes without reading the entire length of the text, + * or a problem occurs during parsing or merging, then an exception is thrown. + * + * @param text the text to parse, not null + * @return the parsed temporal object, not null + * @throws DateTimeParseException if unable to parse the requested result + */ + public TemporalAccessor parse(CharSequence text) { + Objects.requireNonNull(text, "text"); + try { + return parseToBuilder(text, null).resolve(); + } catch (DateTimeParseException ex) { + throw ex; + } catch (RuntimeException ex) { + throw createError(text, ex); + } + } + + /** + * Parses the text using this formatter, providing control over the text position. + *

      + * This parses the text without requiring the parse to start from the beginning + * of the string or finish at the end. + * The result of this method is {@code TemporalAccessor} which has been resolved, + * applying basic validation checks to help ensure a valid date-time. + *

      + * The text will be parsed from the specified start {@code ParsePosition}. + * The entire length of the text does not have to be parsed, the {@code ParsePosition} + * will be updated with the index at the end of parsing. + *

      + * The operation of this method is slightly different to similar methods using + * {@code ParsePosition} on {@code java.text.Format}. That class will return + * errors using the error index on the {@code ParsePosition}. By contrast, this + * method will throw a {@link DateTimeParseException} if an error occurs, with + * the exception containing the error index. + * This change in behavior is necessary due to the increased complexity of + * parsing and resolving dates/times in this API. + *

      + * If the formatter parses the same field more than once with different values, + * the result will be an error. + * + * @param text the text to parse, not null + * @param position the position to parse from, updated with length parsed + * and the index of any error, not null + * @return the parsed temporal object, not null + * @throws DateTimeParseException if unable to parse the requested result + * @throws IndexOutOfBoundsException if the position is invalid + */ + public TemporalAccessor parse(CharSequence text, ParsePosition position) { + Objects.requireNonNull(text, "text"); + Objects.requireNonNull(position, "position"); + try { + return parseToBuilder(text, position).resolve(); + } catch (DateTimeParseException | IndexOutOfBoundsException ex) { + throw ex; + } catch (RuntimeException ex) { + throw createError(text, ex); } } @@ -362,19 +1219,18 @@ public final class DateTimeFormatter { * @param text the text to parse, not null * @param query the query defining the type to parse to, not null * @return the parsed date-time, not null - * @throws DateTimeParseException if the parse fails + * @throws DateTimeParseException if unable to parse the requested result */ public T parse(CharSequence text, TemporalQuery query) { Objects.requireNonNull(text, "text"); Objects.requireNonNull(query, "query"); - String str = text.toString(); // parsing whole String, so this makes sense try { - DateTimeBuilder builder = parseToBuilder(str).resolve(); + DateTimeBuilder builder = parseToBuilder(text, null).resolve(); return builder.query(query); } catch (DateTimeParseException ex) { throw ex; } catch (RuntimeException ex) { - throw createError(str, ex); + throw createError(text, ex); } } @@ -382,8 +1238,8 @@ public final class DateTimeFormatter { * Fully parses the text producing an object of one of the specified types. *

      * This parse method is convenient for use when the parser can handle optional elements. - * For example, a pattern of 'yyyy-MM[-dd[Z]]' can be fully parsed to an {@code OffsetDate}, - * or partially parsed to a {@code LocalDate} or a {@code YearMonth}. + * For example, a pattern of 'yyyy-MM-dd HH.mm[Z]]' can be fully parsed to a {@code ZonedDateTime}, + * or partially parsed to a {@code LocalDateTime}. * The queries must be specified in order, starting from the best matching full-parse option * and ending with the worst matching minimal parse option. * The query is typically a method reference to a {@code from(TemporalAccessor)} method. @@ -392,8 +1248,8 @@ public final class DateTimeFormatter { * Normally, applications will use {@code instanceof} to check the result. * For example: *

      -     *  TemporalAccessor dt = parser.parseBest(str, OffsetDate::from, LocalDate::from);
      -     *  if (dt instanceof OffsetDate) {
      +     *  TemporalAccessor dt = parser.parseBest(str, ZonedDateTime::from, LocalDateTime::from);
      +     *  if (dt instanceof ZonedDateTime) {
            *   ...
            *  } else {
            *   ...
      @@ -407,8 +1263,7 @@ public final class DateTimeFormatter {
            *  must implement {@code TemporalAccessor}, not null
            * @return the parsed date-time, not null
            * @throws IllegalArgumentException if less than 2 types are specified
      -     * @throws DateTimeException if none of the queries can be parsed from the input
      -     * @throws DateTimeParseException if the parse fails
      +     * @throws DateTimeParseException if unable to parse the requested result
            */
           public TemporalAccessor parseBest(CharSequence text, TemporalQuery... queries) {
               Objects.requireNonNull(text, "text");
      @@ -416,9 +1271,8 @@ public final class DateTimeFormatter {
               if (queries.length < 2) {
                   throw new IllegalArgumentException("At least two queries must be specified");
               }
      -        String str = text.toString();  // parsing whole String, so this makes sense
               try {
      -            DateTimeBuilder builder = parseToBuilder(str).resolve();
      +            DateTimeBuilder builder = parseToBuilder(text, null).resolve();
                   for (TemporalQuery query : queries) {
                       try {
                           return (TemporalAccessor) builder.query(query);
      @@ -430,16 +1284,18 @@ public final class DateTimeFormatter {
               } catch (DateTimeParseException ex) {
                   throw ex;
               } catch (RuntimeException ex) {
      -            throw createError(str, ex);
      +            throw createError(text, ex);
               }
           }
       
      -    private DateTimeParseException createError(String str, RuntimeException ex) {
      -        String abbr = str;
      -        if (abbr.length() > 64) {
      -            abbr = abbr.substring(0, 64) + "...";
      +    private DateTimeParseException createError(CharSequence text, RuntimeException ex) {
      +        String abbr = "";
      +        if (text.length() > 64) {
      +            abbr = text.subSequence(0, 64).toString() + "...";
      +        } else {
      +            abbr = text.toString();
               }
      -        return new DateTimeParseException("Text '" + abbr + "' could not be parsed: " + ex.getMessage(), str, 0, ex);
      +        return new DateTimeParseException("Text '" + abbr + "' could not be parsed: " + ex.getMessage(), text, 0, ex);
           }
       
           //-----------------------------------------------------------------------
      @@ -451,60 +1307,87 @@ public final class DateTimeFormatter {
            * some other {@code DateTimeException} if another date/time problem occurs.
            *
            * @param text  the text to parse, not null
      +     * @param position  the position to parse from, updated with length parsed
      +     *  and the index of any error, null if parsing whole string
            * @return the engine representing the result of the parse, not null
            * @throws DateTimeParseException if the parse fails
            */
      -    public DateTimeBuilder parseToBuilder(CharSequence text) {
      -        Objects.requireNonNull(text, "text");
      -        String str = text.toString();  // parsing whole String, so this makes sense
      -        ParsePosition pos = new ParsePosition(0);
      -        DateTimeBuilder result = parseToBuilder(str, pos);
      -        if (result == null || pos.getErrorIndex() >= 0 || pos.getIndex() < str.length()) {
      -            String abbr = str;
      -            if (abbr.length() > 64) {
      -                abbr = abbr.substring(0, 64) + "...";
      +    private DateTimeBuilder parseToBuilder(final CharSequence text, final ParsePosition position) {
      +        ParsePosition pos = (position != null ? position : new ParsePosition(0));
      +        DateTimeParseContext result = parseUnresolved0(text, pos);
      +        if (result == null || pos.getErrorIndex() >= 0 || (position == null && pos.getIndex() < text.length())) {
      +            String abbr = "";
      +            if (text.length() > 64) {
      +                abbr = text.subSequence(0, 64).toString() + "...";
      +            } else {
      +                abbr = text.toString();
                   }
                   if (pos.getErrorIndex() >= 0) {
                       throw new DateTimeParseException("Text '" + abbr + "' could not be parsed at index " +
      -                        pos.getErrorIndex(), str, pos.getErrorIndex());
      +                        pos.getErrorIndex(), text, pos.getErrorIndex());
                   } else {
                       throw new DateTimeParseException("Text '" + abbr + "' could not be parsed, unparsed text found at index " +
      -                        pos.getIndex(), str, pos.getIndex());
      +                        pos.getIndex(), text, pos.getIndex());
                   }
               }
      -        return result;
      +        return result.resolveFields().toBuilder();
           }
       
           /**
      -     * Parses the text to a builder.
      +     * Parses the text using this formatter, without resolving the result, intended
      +     * for advanced use cases.
            * 

      - * This parses to a {@code DateTimeBuilder} but does not require the input to be fully parsed. + * Parsing is implemented as a two-phase operation. + * First, the text is parsed using the layout defined by the formatter, producing + * a {@code Map} of field to value, a {@code ZoneId} and a {@code Chronology}. + * Second, the parsed data is resolved, by validating, combining and + * simplifying the various fields into more useful ones. + * This method performs the parsing stage but not the resolving stage. *

      - * This method does not throw {@link DateTimeParseException}. - * Instead, errors are returned within the state of the specified parse position. + * The result of this method is {@code TemporalAccessor} which represents the + * data as seen in the input. Values are not validated, thus parsing a date string + * of '2012-00-65' would result in a temporal with three fields - year of '2012', + * month of '0' and day-of-month of '65'. + *

      + * The text will be parsed from the specified start {@code ParsePosition}. + * The entire length of the text does not have to be parsed, the {@code ParsePosition} + * will be updated with the index at the end of parsing. + *

      + * Errors are returned using the error index field of the {@code ParsePosition} + * instead of {@code DateTimeParseException}. + * The returned error index will be set to an index indicative of the error. * Callers must check for errors before using the context. *

      - * This method may throw some other {@code DateTimeException} if a date/time problem occurs. + * If the formatter parses the same field more than once with different values, + * the result will be an error. + *

      + * This method is intended for advanced use cases that need access to the + * internal state during parsing. Typical application code should use + * {@link #parse(CharSequence, TemporalQuery)} or the parse method on the target type. * * @param text the text to parse, not null * @param position the position to parse from, updated with length parsed * and the index of any error, not null - * @return the parsed text, null only if the parse results in an error + * @return the parsed text, null if the parse results in an error * @throws DateTimeException if some problem occurs during parsing * @throws IndexOutOfBoundsException if the position is invalid */ - public DateTimeBuilder parseToBuilder(CharSequence text, ParsePosition position) { + public TemporalAccessor parseUnresolved(CharSequence text, ParsePosition position) { + return parseUnresolved0(text, position); + } + + private DateTimeParseContext parseUnresolved0(CharSequence text, ParsePosition position) { Objects.requireNonNull(text, "text"); Objects.requireNonNull(position, "position"); DateTimeParseContext context = new DateTimeParseContext(this); int pos = position.getIndex(); pos = printerParser.parse(context, text, pos); if (pos < 0) { - position.setErrorIndex(~pos); + position.setErrorIndex(~pos); // index not updated from input return null; } - position.setIndex(pos); - return context.toBuilder(); + position.setIndex(pos); // errorIndex not updated from input + return context; } //----------------------------------------------------------------------- @@ -521,8 +1404,8 @@ public final class DateTimeFormatter { /** * Returns this formatter as a {@code java.text.Format} instance. *

      - * The returned {@link Format} instance will print any {@link java.time.temporal.TemporalAccessor} - * and parses to a resolved {@link DateTimeBuilder}. + * The returned {@link Format} instance will format any {@link TemporalAccessor} + * and parses to a resolved {@link TemporalAccessor}. *

      * Exceptions will follow the definitions of {@code Format}, see those methods * for details about {@code IllegalArgumentException} during formatting and @@ -539,7 +1422,7 @@ public final class DateTimeFormatter { * Returns this formatter as a {@code java.text.Format} instance that will * parse using the specified query. *

      - * The returned {@link Format} instance will print any {@link java.time.temporal.TemporalAccessor} + * The returned {@link Format} instance will format any {@link TemporalAccessor} * and parses to the type specified. * The type must be one that is supported by {@link #parse}. *

      @@ -602,7 +1485,7 @@ public final class DateTimeFormatter { pos.setBeginIndex(0); pos.setEndIndex(0); try { - formatter.printTo((TemporalAccessor) obj, toAppendTo); + formatter.formatTo((TemporalAccessor) obj, toAppendTo); } catch (RuntimeException ex) { throw new IllegalArgumentException(ex.getMessage(), ex); } @@ -612,10 +1495,10 @@ public final class DateTimeFormatter { public Object parseObject(String text) throws ParseException { Objects.requireNonNull(text, "text"); try { - if (parseType != null) { - return formatter.parse(text, parseType); + if (parseType == null) { + return formatter.parseToBuilder(text, null).resolve(); } - return formatter.parseToBuilder(text); + return formatter.parse(text, parseType); } catch (DateTimeParseException ex) { throw new ParseException(ex.getMessage(), ex.getErrorIndex()); } catch (RuntimeException ex) { @@ -625,26 +1508,27 @@ public final class DateTimeFormatter { @Override public Object parseObject(String text, ParsePosition pos) { Objects.requireNonNull(text, "text"); - DateTimeBuilder builder; + DateTimeParseContext unresolved; try { - builder = formatter.parseToBuilder(text, pos); + unresolved = formatter.parseUnresolved0(text, pos); } catch (IndexOutOfBoundsException ex) { if (pos.getErrorIndex() < 0) { pos.setErrorIndex(0); } return null; } - if (builder == null) { + if (unresolved == null) { if (pos.getErrorIndex() < 0) { pos.setErrorIndex(0); } return null; } - if (parseType == null) { - return builder; - } try { - return builder.resolve().query(parseType); + DateTimeBuilder builder = unresolved.resolveFields().toBuilder().resolve(); + if (parseType == null) { + return builder; + } + return builder.query(parseType); } catch (RuntimeException ex) { pos.setErrorIndex(0); return null; diff --git a/jdk/src/share/classes/java/time/format/DateTimeFormatterBuilder.java b/jdk/src/share/classes/java/time/format/DateTimeFormatterBuilder.java index 9ad63a6e6fc..f2ed2317865 100644 --- a/jdk/src/share/classes/java/time/format/DateTimeFormatterBuilder.java +++ b/jdk/src/share/classes/java/time/format/DateTimeFormatterBuilder.java @@ -81,11 +81,12 @@ import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZoneOffset; +import java.time.chrono.Chronology; +import java.time.chrono.IsoChronology; +import java.time.chrono.JapaneseChronology; import java.time.format.DateTimeTextProvider.LocaleStore; -import java.time.temporal.Chrono; import java.time.temporal.ChronoField; -import java.time.temporal.ISOChrono; -import java.time.temporal.ISOFields; +import java.time.temporal.IsoFields; import java.time.temporal.Queries; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalField; @@ -99,6 +100,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; @@ -289,10 +291,10 @@ public final class DateTimeFormatterBuilder { * Appends the value of a date-time field to the formatter using a normal * output style. *

      - * The value of the field will be output during a print. + * The value of the field will be output during a format. * If the value cannot be obtained then an exception will be thrown. *

      - * The value will be printed as per the normal print of an integer value. + * The value will be printed as per the normal format of an integer value. * Only negative numbers will be signed. No padding will be added. *

      * The parser for a variable width value such as this normally behaves greedily, @@ -313,12 +315,12 @@ public final class DateTimeFormatterBuilder { * Appends the value of a date-time field to the formatter using a fixed * width, zero-padded approach. *

      - * The value of the field will be output during a print. + * The value of the field will be output during a format. * If the value cannot be obtained then an exception will be thrown. *

      * The value will be zero-padded on the left. If the size of the value * means that it cannot be printed within the width then an exception is thrown. - * If the value of the field is negative then an exception is thrown during printing. + * If the value of the field is negative then an exception is thrown during formatting. *

      * This method supports a special technique of parsing known as 'adjacent value parsing'. * This technique solves the problem where a variable length value is followed by one or more @@ -368,9 +370,9 @@ public final class DateTimeFormatterBuilder { /** * Appends the value of a date-time field to the formatter providing full - * control over printing. + * control over formatting. *

      - * The value of the field will be output during a print. + * The value of the field will be output during a format. * If the value cannot be obtained then an exception will be thrown. *

      * This method provides full control of the numeric formatting, including @@ -386,7 +388,7 @@ public final class DateTimeFormatterBuilder { *

      * If this method is invoked with equal minimum and maximum widths and a sign style of * {@code NOT_NEGATIVE} then it delegates to {@code appendValue(TemporalField,int)}. - * In this scenario, the printing and parsing behavior described there occur. + * In this scenario, the formatting and parsing behavior described there occur. * * @param field the field to append, not null * @param minWidth the minimum field width of the printed field, from 1 to 19 @@ -425,11 +427,11 @@ public final class DateTimeFormatterBuilder { /** * Appends the reduced value of a date-time field to the formatter. *

      - * This is typically used for printing and parsing a two digit year. + * This is typically used for formatting and parsing a two digit year. * The {@code width} is the printed and parsed width. * The {@code baseValue} is used during parsing to determine the valid range. *

      - * For printing, the width is used to determine the number of characters to print. + * For formatting, the width is used to determine the number of characters to format. * The rightmost characters are output to match the width, left padding with zero. *

      * For parsing, exactly the number of characters specified by the width are parsed. @@ -525,12 +527,12 @@ public final class DateTimeFormatterBuilder { * Appends the text of a date-time field to the formatter using the full * text style. *

      - * The text of the field will be output during a print. + * The text of the field will be output during a format. * The value must be within the valid range of the field. * If the value cannot be obtained then an exception will be thrown. * If the field has no textual representation, then the numeric value will be used. *

      - * The value will be printed as per the normal print of an integer value. + * The value will be printed as per the normal format of an integer value. * Only negative numbers will be signed. No padding will be added. * * @param field the field to append, not null @@ -543,12 +545,12 @@ public final class DateTimeFormatterBuilder { /** * Appends the text of a date-time field to the formatter. *

      - * The text of the field will be output during a print. + * The text of the field will be output during a format. * The value must be within the valid range of the field. * If the value cannot be obtained then an exception will be thrown. * If the field has no textual representation, then the numeric value will be used. *

      - * The value will be printed as per the normal print of an integer value. + * The value will be printed as per the normal format of an integer value. * Only negative numbers will be signed. No padding will be added. * * @param field the field to append, not null @@ -568,10 +570,10 @@ public final class DateTimeFormatterBuilder { *

      * The standard text outputting methods use the localized text in the JDK. * This method allows that text to be specified directly. - * The supplied map is not validated by the builder to ensure that printing or + * The supplied map is not validated by the builder to ensure that formatting or * parsing is possible, thus an invalid map may throw an error during later use. *

      - * Supplying the map of text provides considerable flexibility in printing and parsing. + * Supplying the map of text provides considerable flexibility in formatting and parsing. * For example, a legacy application might require or supply the months of the * year as "JNY", "FBY", "MCH" etc. These do not match the standard set of text * for localized month names. Using this method, a map can be created which @@ -588,7 +590,7 @@ public final class DateTimeFormatterBuilder { * Other uses might be to output the value with a suffix, such as "1st", "2nd", "3rd", * or as Roman numerals "I", "II", "III", "IV". *

      - * During printing, the value is obtained and checked that it is in the valid range. + * During formatting, the value is obtained and checked that it is in the valid range. * If text is not available for the value then it is output as a number. * During parsing, the parser will match against the map of text and numeric values. * @@ -624,7 +626,7 @@ public final class DateTimeFormatterBuilder { * They are converted to a date-time with a zone-offset of UTC and printed * using the standard ISO-8601 format. *

      - * An alternative to this method is to print/parse the instant as a single + * An alternative to this method is to format/parse the instant as a single * epoch-seconds value. That is achieved using {@code appendValue(INSTANT_SECONDS)}. * * @return this, for chaining, not null @@ -637,22 +639,22 @@ public final class DateTimeFormatterBuilder { /** * Appends the zone offset, such as '+01:00', to the formatter. *

      - * This appends an instruction to print/parse the offset ID to the builder. + * This appends an instruction to format/parse the offset ID to the builder. * This is equivalent to calling {@code appendOffset("HH:MM:ss", "Z")}. * * @return this, for chaining, not null */ public DateTimeFormatterBuilder appendOffsetId() { - appendInternal(OffsetIdPrinterParser.INSTANCE_ID); + appendInternal(OffsetIdPrinterParser.INSTANCE_ID_Z); return this; } /** * Appends the zone offset, such as '+01:00', to the formatter. *

      - * This appends an instruction to print/parse the offset ID to the builder. + * This appends an instruction to format/parse the offset ID to the builder. *

      - * During printing, the offset is obtained using a mechanism equivalent + * During formatting, the offset is obtained using a mechanism equivalent * to querying the temporal with {@link Queries#offset()}. * It will be printed using the format defined below. * If the offset cannot be obtained then an exception is thrown unless the @@ -665,15 +667,18 @@ public final class DateTimeFormatterBuilder { * The format of the offset is controlled by a pattern which must be one * of the following: *

        - *
      • {@code +HH} - hour only, ignoring any minute - *
      • {@code +HHMM} - hour and minute, no colon - *
      • {@code +HH:MM} - hour and minute, with colon - *
      • {@code +HHMMss} - hour and minute, with second if non-zero and no colon - *
      • {@code +HH:MM:ss} - hour and minute, with second if non-zero and colon + *
      • {@code +HH} - hour only, ignoring minute and second + *
      • {@code +HHmm} - hour, with minute if non-zero, ignoring second, no colon + *
      • {@code +HH:mm} - hour, with minute if non-zero, ignoring second, with colon + *
      • {@code +HHMM} - hour and minute, ignoring second, no colon + *
      • {@code +HH:MM} - hour and minute, ignoring second, with colon + *
      • {@code +HHMMss} - hour and minute, with second if non-zero, no colon + *
      • {@code +HH:MM:ss} - hour and minute, with second if non-zero, with colon *
      • {@code +HHMMSS} - hour, minute and second, no colon *
      • {@code +HH:MM:SS} - hour, minute and second, with colon *

      - * The "no offset" text controls what text is printed when the offset is zero. + * The "no offset" text controls what text is printed when the total amount of + * the offset fields to be output is zero. * Example values would be 'Z', '+00:00', 'UTC' or 'GMT'. * Three formats are accepted for parsing UTC - the "no offset" text, and the * plus and minus versions of zero defined by the pattern. @@ -683,7 +688,7 @@ public final class DateTimeFormatterBuilder { * @return this, for chaining, not null */ public DateTimeFormatterBuilder appendOffset(String pattern, String noOffsetText) { - appendInternal(new OffsetIdPrinterParser(noOffsetText, pattern)); + appendInternal(new OffsetIdPrinterParser(pattern, noOffsetText)); return this; } @@ -691,20 +696,48 @@ public final class DateTimeFormatterBuilder { /** * Appends the time-zone ID, such as 'Europe/Paris' or '+02:00', to the formatter. *

      - * This appends an instruction to print/parse the zone ID to the builder. + * This appends an instruction to format/parse the zone ID to the builder. * The zone ID is obtained in a strict manner suitable for {@code ZonedDateTime}. * By contrast, {@code OffsetDateTime} does not have a zone ID suitable * for use with this method, see {@link #appendZoneOrOffsetId()}. *

      - * During printing, the zone is obtained using a mechanism equivalent + * During formatting, the zone is obtained using a mechanism equivalent * to querying the temporal with {@link Queries#zoneId()}. * It will be printed using the result of {@link ZoneId#getId()}. * If the zone cannot be obtained then an exception is thrown unless the * section of the formatter is optional. *

      - * During parsing, the zone is parsed and must match a known zone or offset. - * If the zone cannot be parsed then an exception is thrown unless the - * section of the formatter is optional. + * During parsing, the text must match a known zone or offset. + * There are two types of zone ID, offset-based, such as '+01:30' and + * region-based, such as 'Europe/London'. These are parsed differently. + * If the parse starts with '+', '-', 'UT', 'UTC' or 'GMT', then the parser + * expects an offset-based zone and will not match region-based zones. + * The offset ID, such as '+02:30', may be at the start of the parse, + * or prefixed by 'UT', 'UTC' or 'GMT'. The offset ID parsing is + * equivalent to using {@link #appendOffset(String, String)} using the + * arguments 'HH:MM:ss' and the no offset string '0'. + * If the parse starts with 'UT', 'UTC' or 'GMT', and the parser cannot + * match a following offset ID, then {@link ZoneOffset#UTC} is selected. + * In all other cases, the list of known region-based zones is used to + * find the longest available match. If no match is found, and the parse + * starts with 'Z', then {@code ZoneOffset.UTC} is selected. + * The parser uses the {@linkplain #parseCaseInsensitive() case sensitive} setting. + *

      + * For example, the following will parse: + *

      +     *   "Europe/London"           -> ZoneId.of("Europe/London")
      +     *   "Z"                       -> ZoneOffset.UTC
      +     *   "UT"                      -> ZoneOffset.UTC
      +     *   "UTC"                     -> ZoneOffset.UTC
      +     *   "GMT"                     -> ZoneOffset.UTC
      +     *   "UT0"                     -> ZoneOffset.UTC
      +     *   "UTC0"                    -> ZoneOffset.UTC
      +     *   "GMT0"                    -> ZoneOffset.UTC
      +     *   "+01:30"                  -> ZoneOffset.of("+01:30")
      +     *   "UT+01:30"                -> ZoneOffset.of("+01:30")
      +     *   "UTC+01:30"               -> ZoneOffset.of("+01:30")
      +     *   "GMT+01:30"               -> ZoneOffset.of("+01:30")
      +     * 
      * * @return this, for chaining, not null * @see #appendZoneRegionId() @@ -718,21 +751,52 @@ public final class DateTimeFormatterBuilder { * Appends the time-zone region ID, such as 'Europe/Paris', to the formatter, * rejecting the zone ID if it is a {@code ZoneOffset}. *

      - * This appends an instruction to print/parse the zone ID to the builder + * This appends an instruction to format/parse the zone ID to the builder * only if it is a region-based ID. *

      - * During printing, the zone is obtained using a mechanism equivalent + * During formatting, the zone is obtained using a mechanism equivalent * to querying the temporal with {@link Queries#zoneId()}. * If the zone is a {@code ZoneOffset} or it cannot be obtained then * an exception is thrown unless the section of the formatter is optional. * If the zone is not an offset, then the zone will be printed using * the zone ID from {@link ZoneId#getId()}. *

      - * During parsing, the zone is parsed and must match a known zone or offset. - * If the zone cannot be parsed then an exception is thrown unless the - * section of the formatter is optional. - * Note that parsing accepts offsets, whereas printing will never produce - * one, thus parsing is equivalent to {@code appendZoneId}. + * During parsing, the text must match a known zone or offset. + * There are two types of zone ID, offset-based, such as '+01:30' and + * region-based, such as 'Europe/London'. These are parsed differently. + * If the parse starts with '+', '-', 'UT', 'UTC' or 'GMT', then the parser + * expects an offset-based zone and will not match region-based zones. + * The offset ID, such as '+02:30', may be at the start of the parse, + * or prefixed by 'UT', 'UTC' or 'GMT'. The offset ID parsing is + * equivalent to using {@link #appendOffset(String, String)} using the + * arguments 'HH:MM:ss' and the no offset string '0'. + * If the parse starts with 'UT', 'UTC' or 'GMT', and the parser cannot + * match a following offset ID, then {@link ZoneOffset#UTC} is selected. + * In all other cases, the list of known region-based zones is used to + * find the longest available match. If no match is found, and the parse + * starts with 'Z', then {@code ZoneOffset.UTC} is selected. + * The parser uses the {@linkplain #parseCaseInsensitive() case sensitive} setting. + *

      + * For example, the following will parse: + *

      +     *   "Europe/London"           -> ZoneId.of("Europe/London")
      +     *   "Z"                       -> ZoneOffset.UTC
      +     *   "UT"                      -> ZoneOffset.UTC
      +     *   "UTC"                     -> ZoneOffset.UTC
      +     *   "GMT"                     -> ZoneOffset.UTC
      +     *   "UT0"                     -> ZoneOffset.UTC
      +     *   "UTC0"                    -> ZoneOffset.UTC
      +     *   "GMT0"                    -> ZoneOffset.UTC
      +     *   "+01:30"                  -> ZoneOffset.of("+01:30")
      +     *   "UT+01:30"                -> ZoneOffset.of("+01:30")
      +     *   "UTC+01:30"               -> ZoneOffset.of("+01:30")
      +     *   "GMT+01:30"               -> ZoneOffset.of("+01:30")
      +     * 
      + *

      + * Note that this method is is identical to {@code appendZoneId()} except + * in the mechanism used to obtain the zone. + * Note also that parsing accepts offsets, whereas formatting will never + * produce one. * * @return this, for chaining, not null * @see #appendZoneId() @@ -746,24 +810,52 @@ public final class DateTimeFormatterBuilder { * Appends the time-zone ID, such as 'Europe/Paris' or '+02:00', to * the formatter, using the best available zone ID. *

      - * This appends an instruction to print/parse the best available + * This appends an instruction to format/parse the best available * zone or offset ID to the builder. * The zone ID is obtained in a lenient manner that first attempts to * find a true zone ID, such as that on {@code ZonedDateTime}, and * then attempts to find an offset, such as that on {@code OffsetDateTime}. *

      - * During printing, the zone is obtained using a mechanism equivalent + * During formatting, the zone is obtained using a mechanism equivalent * to querying the temporal with {@link Queries#zone()}. * It will be printed using the result of {@link ZoneId#getId()}. * If the zone cannot be obtained then an exception is thrown unless the * section of the formatter is optional. *

      - * During parsing, the zone is parsed and must match a known zone or offset. - * If the zone cannot be parsed then an exception is thrown unless the - * section of the formatter is optional. + * During parsing, the text must match a known zone or offset. + * There are two types of zone ID, offset-based, such as '+01:30' and + * region-based, such as 'Europe/London'. These are parsed differently. + * If the parse starts with '+', '-', 'UT', 'UTC' or 'GMT', then the parser + * expects an offset-based zone and will not match region-based zones. + * The offset ID, such as '+02:30', may be at the start of the parse, + * or prefixed by 'UT', 'UTC' or 'GMT'. The offset ID parsing is + * equivalent to using {@link #appendOffset(String, String)} using the + * arguments 'HH:MM:ss' and the no offset string '0'. + * If the parse starts with 'UT', 'UTC' or 'GMT', and the parser cannot + * match a following offset ID, then {@link ZoneOffset#UTC} is selected. + * In all other cases, the list of known region-based zones is used to + * find the longest available match. If no match is found, and the parse + * starts with 'Z', then {@code ZoneOffset.UTC} is selected. + * The parser uses the {@linkplain #parseCaseInsensitive() case sensitive} setting. *

      - * This method is is identical to {@code appendZoneId()} except in the - * mechanism used to obtain the zone. + * For example, the following will parse: + *

      +     *   "Europe/London"           -> ZoneId.of("Europe/London")
      +     *   "Z"                       -> ZoneOffset.UTC
      +     *   "UT"                      -> ZoneOffset.UTC
      +     *   "UTC"                     -> ZoneOffset.UTC
      +     *   "GMT"                     -> ZoneOffset.UTC
      +     *   "UT0"                     -> ZoneOffset.UTC
      +     *   "UTC0"                    -> ZoneOffset.UTC
      +     *   "GMT0"                    -> ZoneOffset.UTC
      +     *   "+01:30"                  -> ZoneOffset.of("+01:30")
      +     *   "UT+01:30"                -> ZoneOffset.of("+01:30")
      +     *   "UTC+01:30"               -> ZoneOffset.of("+01:30")
      +     *   "GMT+01:30"               -> ZoneOffset.of("+01:30")
      +     * 
      + *

      + * Note that this method is is identical to {@code appendZoneId()} except + * in the mechanism used to obtain the zone. * * @return this, for chaining, not null * @see #appendZoneId() @@ -776,9 +868,10 @@ public final class DateTimeFormatterBuilder { /** * Appends the time-zone name, such as 'British Summer Time', to the formatter. *

      - * This appends an instruction to print the textual name of the zone to the builder. + * This appends an instruction to format/parse the textual name of the zone to + * the builder. *

      - * During printing, the zone is obtained using a mechanism equivalent + * During formatting, the zone is obtained using a mechanism equivalent * to querying the temporal with {@link Queries#zoneId()}. * If the zone is a {@code ZoneOffset} it will be printed using the * result of {@link ZoneOffset#getId()}. @@ -791,31 +884,87 @@ public final class DateTimeFormatterBuilder { * If the zone cannot be obtained then an exception is thrown unless the * section of the formatter is optional. *

      - * Parsing is not currently supported. + * During parsing, either the textual zone name, the zone ID or the offset + * is accepted. Many textual zone names are not unique, such as CST can be + * for both "Central Standard Time" and "China Standard Time". In this + * situation, the zone id will be determined by the region information from + * formatter's {@link DateTimeFormatter#getLocale() locale} and the standard + * zone id for that area, for example, America/New_York for the America Eastern + * zone. The {@link #appendZoneText(TextStyle, Set)} may be used + * to specify a set of preferred {@link ZoneId} in this situation. * * @param textStyle the text style to use, not null * @return this, for chaining, not null */ public DateTimeFormatterBuilder appendZoneText(TextStyle textStyle) { - // TODO: parsing of zone text? -// * During parsing, either the textual zone name, the zone ID or the offset -// * is accepted. -// * If the zone cannot be parsed then an exception is thrown unless the -// * section of the formatter is optional. - appendInternal(new ZoneTextPrinterParser(textStyle)); + appendInternal(new ZoneTextPrinterParser(textStyle, null)); + return this; + } + + /** + * Appends the time-zone name, such as 'British Summer Time', to the formatter. + *

      + * This appends an instruction to format/parse the textual name of the zone to + * the builder. + *

      + * During formatting, the zone is obtained using a mechanism equivalent + * to querying the temporal with {@link Queries#zoneId()}. + * If the zone is a {@code ZoneOffset} it will be printed using the + * result of {@link ZoneOffset#getId()}. + * If the zone is not an offset, the textual name will be looked up + * for the locale set in the {@link DateTimeFormatter}. + * If the temporal object being printed represents an instant, then the text + * will be the summer or winter time text as appropriate. + * If the lookup for text does not find any suitable reuslt, then the + * {@link ZoneId#getId() ID} will be printed instead. + * If the zone cannot be obtained then an exception is thrown unless the + * section of the formatter is optional. + *

      + * During parsing, either the textual zone name, the zone ID or the offset + * is accepted. Many textual zone names are not unique, such as CST can be + * for both "Central Standard Time" and "China Standard Time". In this + * situation, the zone id will be determined by the region information from + * formatter's {@link DateTimeFormatter#getLocale() locale} and the standard + * zone id for that area, for example, America/New_York for the America Eastern + * zone. This method also allows a set of preferred {@link ZoneId} to be + * specified for parsing. The matched preferred zone id will be used if the + * textural zone name being parsed is not unique. + * + * If the zone cannot be parsed then an exception is thrown unless the + * section of the formatter is optional. + * + * @param textStyle the text style to use, not null + * @param preferredZones the set of preferred zone ids, not null + * @return this, for chaining, not null + */ + public DateTimeFormatterBuilder appendZoneText(TextStyle textStyle, + Set preferredZones) { + Objects.requireNonNull(preferredZones, "preferredZones"); + appendInternal(new ZoneTextPrinterParser(textStyle, preferredZones)); return this; } //----------------------------------------------------------------------- /** - * Appends the chronology ID to the formatter. + * Appends the chronology ID, such as 'ISO' or 'ThaiBuddhist', to the formatter. *

      - * The chronology ID will be output during a print. - * If the chronology cannot be obtained then an exception will be thrown. + * This appends an instruction to format/parse the chronology ID to the builder. + *

      + * During formatting, the chronology is obtained using a mechanism equivalent + * to querying the temporal with {@link Queries#chronology()}. + * It will be printed using the result of {@link Chronology#getId()}. + * If the chronology cannot be obtained then an exception is thrown unless the + * section of the formatter is optional. + *

      + * During parsing, the chronology is parsed and must match one of the chronologies + * in {@link Chronology#getAvailableChronologies()}. + * If the chronology cannot be parsed then an exception is thrown unless the + * section of the formatter is optional. + * The parser uses the {@linkplain #parseCaseInsensitive() case sensitive} setting. * * @return this, for chaining, not null */ - public DateTimeFormatterBuilder appendChronoId() { + public DateTimeFormatterBuilder appendChronologyId() { appendInternal(new ChronoPrinterParser(null)); return this; } @@ -823,14 +972,14 @@ public final class DateTimeFormatterBuilder { /** * Appends the chronology name to the formatter. *

      - * The calendar system name will be output during a print. + * The calendar system name will be output during a format. * If the chronology cannot be obtained then an exception will be thrown. * The calendar system name is obtained from the formatting symbols. * * @param textStyle the text style to use, not null * @return this, for chaining, not null */ - public DateTimeFormatterBuilder appendChronoText(TextStyle textStyle) { + public DateTimeFormatterBuilder appendChronologyText(TextStyle textStyle) { Objects.requireNonNull(textStyle, "textStyle"); appendInternal(new ChronoPrinterParser(textStyle)); return this; @@ -840,39 +989,36 @@ public final class DateTimeFormatterBuilder { /** * Appends a localized date-time pattern to the formatter. *

      - * The pattern is resolved lazily using the locale being used during the print/parse - * (stored in {@link DateTimeFormatter}. + * This appends a localized section to the builder, suitable for outputting + * a date, time or date-time combination. The format of the localized + * section is lazily looked up based on four items: + *

        + *
      • the {@code dateStyle} specified to this method + *
      • the {@code timeStyle} specified to this method + *
      • the {@code Locale} of the {@code DateTimeFormatter} + *
      • the {@code Chronology}, selecting the best available + *

      + * During formatting, the chronology is obtained from the temporal object + * being formatted, which may have been overridden by + * {@link DateTimeFormatter#withChronology(Chronology)}. *

      - * The pattern can vary by chronology, although typically it doesn't. - * This method uses the standard ISO chronology patterns. + * During parsing, if a chronology has already been parsed, then it is used. + * Otherwise the default from {@code DateTimeFormatter.withChronology(Chronology)} + * is used, with {@code IsoChronology} as the fallback. + *

      + * Note that this method provides similar functionality to methods on + * {@code DateFormat} such as {@link DateFormat#getDateTimeInstance(int, int)}. * * @param dateStyle the date style to use, null means no date required * @param timeStyle the time style to use, null means no time required * @return this, for chaining, not null + * @throws IllegalArgumentException if both the date and time styles are null */ public DateTimeFormatterBuilder appendLocalized(FormatStyle dateStyle, FormatStyle timeStyle) { - return appendLocalized(dateStyle, timeStyle, ISOChrono.INSTANCE); - } - - /** - * Appends a localized date-time pattern to the formatter. - *

      - * The pattern is resolved lazily using the locale being used during the print/parse, - * stored in {@link DateTimeFormatter}. - *

      - * The pattern can vary by chronology, although typically it doesn't. - * This method allows the chronology to be specified. - * - * @param dateStyle the date style to use, null means no date required - * @param timeStyle the time style to use, null means no time required - * @param chrono the chronology to use, not null - * @return this, for chaining, not null - */ - public DateTimeFormatterBuilder appendLocalized(FormatStyle dateStyle, FormatStyle timeStyle, Chrono chrono) { - Objects.requireNonNull(chrono, "chrono"); - if (dateStyle != null || timeStyle != null) { - appendInternal(new LocalizedPrinterParser(dateStyle, timeStyle, chrono)); + if (dateStyle == null && timeStyle == null) { + throw new IllegalArgumentException("Either the date or time style must be non-null"); } + appendInternal(new LocalizedPrinterParser(dateStyle, timeStyle)); return this; } @@ -880,7 +1026,7 @@ public final class DateTimeFormatterBuilder { /** * Appends a character literal to the formatter. *

      - * This character will be output during a print. + * This character will be output during a format. * * @param literal the literal to append, not null * @return this, for chaining, not null @@ -893,7 +1039,7 @@ public final class DateTimeFormatterBuilder { /** * Appends a string literal to the formatter. *

      - * This string will be output during a print. + * This string will be output during a format. *

      * If the literal is empty, nothing is added to the formatter. * @@ -929,13 +1075,13 @@ public final class DateTimeFormatterBuilder { } /** - * Appends a formatter to the builder which will optionally print/parse. + * Appends a formatter to the builder which will optionally format/parse. *

      * This method has the same effect as appending each of the constituent * parts directly to this builder surrounded by an {@link #optionalStart()} and * {@link #optionalEnd()}. *

      - * The formatter will print if data is available for all the fields contained within it. + * The formatter will format if data is available for all the fields contained within it. * The formatter will parse if the string matches, otherwise no error is returned. * * @param formatter the formatter to add, not null @@ -958,7 +1104,7 @@ public final class DateTimeFormatterBuilder { *

            *  Symbol  Meaning                     Presentation      Examples
            *  ------  -------                     ------------      -------
      -     *   G       era                         number/text       1; 01; AD; Anno Domini
      +     *   G       era                         text              A; AD; Anno Domini
            *   y       year                        year              2004; 04
            *   D       day-of-year                 number            189
            *   M       month-of-year               number/text       7; 07; Jul; July; J
      @@ -985,10 +1131,11 @@ public final class DateTimeFormatterBuilder {
            *   n       nano-of-second              number            987654321
            *   N       nano-of-day                 number            1234000000
            *
      -     *   I       time-zone ID                zoneId            America/Los_Angeles
      -     *   z       time-zone name              text              Pacific Standard Time; PST
      -     *   Z       zone-offset                 offset-Z          +0000; -0800; -08:00;
      +     *   V       time-zone ID                zone-id           America/Los_Angeles; Z; -08:30
      +     *   z       time-zone name              zone-name         Pacific Standard Time; PST
            *   X       zone-offset 'Z' for zero    offset-X          Z; -08; -0830; -08:30; -083015; -08:30:15;
      +     *   x       zone-offset                 offset-x          +0000; -08; -0830; -08:30; -083015; -08:30:15;
      +     *   Z       zone-offset                 offset-Z          +0000; -0800; -08:00;
            *
            *   p       pad next                    pad modifier      1
            *
      @@ -1023,26 +1170,66 @@ public final class DateTimeFormatterBuilder {
            * 

      * Year: The count of letters determines the minimum field width below which padding is used. * If the count of letters is two, then a {@link #appendValueReduced reduced} two digit form is used. - * For printing, this outputs the rightmost two digits. For parsing, this will parse using the + * For formatting, this outputs the rightmost two digits. For parsing, this will parse using the * base value of 2000, resulting in a year within the range 2000 to 2099 inclusive. * If the count of letters is less than four (but not two), then the sign is only output for negative * years as per {@link SignStyle#NORMAL}. * Otherwise, the sign is output if the pad width is exceeded, as per {@link SignStyle#EXCEEDS_PAD} *

      - * ZoneId: 'I' outputs the zone ID, such as 'Europe/Paris'. + * ZoneId: This outputs the time-zone ID, such as 'Europe/Paris'. + * If the count of letters is two, then the time-zone ID is output. + * Any other count of letters throws {@code IllegalArgumentException}. + *

      +     *  Pattern     Equivalent builder methods
      +     *   VV          appendZoneId()
      +     * 
      *

      - * Offset X: This formats the offset using 'Z' when the offset is zero. - * One letter outputs just the hour', such as '+01' + * Zone names: This outputs the display name of the time-zone ID. + * If the count of letters is one, two or three, then the short name is output. + * If the count of letters is four, then the full name is output. + * Five or more letters throws {@code IllegalArgumentException}. + *

      +     *  Pattern     Equivalent builder methods
      +     *   z           appendZoneText(TextStyle.SHORT)
      +     *   zz          appendZoneText(TextStyle.SHORT)
      +     *   zzz         appendZoneText(TextStyle.SHORT)
      +     *   zzzz        appendZoneText(TextStyle.FULL)
      +     * 
      + *

      + * Offset X and x: This formats the offset based on the number of pattern letters. + * One letter outputs just the hour', such as '+01', unless the minute is non-zero + * in which case the minute is also output, such as '+0130'. * Two letters outputs the hour and minute, without a colon, such as '+0130'. * Three letters outputs the hour and minute, with a colon, such as '+01:30'. * Four letters outputs the hour and minute and optional second, without a colon, such as '+013015'. * Five letters outputs the hour and minute and optional second, with a colon, such as '+01:30:15'. + * Six or more letters throws {@code IllegalArgumentException}. + * Pattern letter 'X' (upper case) will output 'Z' when the offset to be output would be zero, + * whereas pattern letter 'x' (lower case) will output '+00', '+0000', or '+00:00'. + *

      +     *  Pattern     Equivalent builder methods
      +     *   X           appendOffset("+HHmm","Z")
      +     *   XX          appendOffset("+HHMM","Z")
      +     *   XXX         appendOffset("+HH:MM","Z")
      +     *   XXXX        appendOffset("+HHMMss","Z")
      +     *   XXXXX       appendOffset("+HH:MM:ss","Z")
      +     *   x           appendOffset("+HHmm","+00")
      +     *   xx          appendOffset("+HHMM","+0000")
      +     *   xxx         appendOffset("+HH:MM","+00:00")
      +     *   xxxx        appendOffset("+HHMMss","+0000")
      +     *   xxxxx       appendOffset("+HH:MM:ss","+00:00")
      +     * 
      *

      - * Offset Z: This formats the offset using '+0000' or '+00:00' when the offset is zero. - * One or two letters outputs the hour and minute, without a colon, such as '+0130'. - * Three letters outputs the hour and minute, with a colon, such as '+01:30'. - *

      - * Zone names: Time zone names ('z') cannot be parsed. + * Offset Z: This formats the offset based on the number of pattern letters. + * One, two or three letters outputs the hour and minute, without a colon, such as '+0130'. + * Four or more letters throws {@code IllegalArgumentException}. + * The output will be '+0000' when the offset is zero. + *

      +     *  Pattern     Equivalent builder methods
      +     *   Z           appendOffset("+HHMM","+0000")
      +     *   ZZ          appendOffset("+HHMM","+0000")
      +     *   ZZZ         appendOffset("+HHMM","+0000")
      +     * 
      *

      * Optional section: The optional section markers work exactly like calling {@link #optionalStart()} * and {@link #optionalEnd()}. @@ -1058,14 +1245,15 @@ public final class DateTimeFormatterBuilder { * Despite this, it is recommended to use single quotes around all characters that you want to * output directly to ensure that future changes do not break your application. *

      - * The pattern string is similar, but not identical, to {@link java.text.SimpleDateFormat SimpleDateFormat}. + * Note that the pattern string is similar, but not identical, to + * {@link java.text.SimpleDateFormat SimpleDateFormat}. + * The pattern string is also similar, but not identical, to that defined by the + * Unicode Common Locale Data Repository (CLDR/LDML). * Pattern letters 'E' and 'u' are merged, which changes the meaning of "E" and "EE" to be numeric. - * Pattern letters 'Z' and 'X' are extended. + * Pattern letters 'X' is aligned with Unicode CLDR/LDML, which affects pattern 'X'. * Pattern letter 'y' and 'Y' parse years of two digits and more than 4 digits differently. * Pattern letters 'n', 'A', 'N', 'I' and 'p' are added. * Number types will reject large numbers. - * The pattern string is also similar, but not identical, to that defined by the - * Unicode Common Locale Data Repository (CLDR). * * @param pattern the pattern to add, not null * @return this, for chaining, not null @@ -1107,27 +1295,34 @@ public final class DateTimeFormatterBuilder { if (field != null) { parseField(cur, count, field); } else if (cur == 'z') { - if (count < 4) { - appendZoneText(TextStyle.SHORT); - } else { + if (count > 4) { + throw new IllegalArgumentException("Too many pattern letters: " + cur); + } else if (count == 4) { appendZoneText(TextStyle.FULL); + } else { + appendZoneText(TextStyle.SHORT); + } + } else if (cur == 'V') { + if (count != 2) { + throw new IllegalArgumentException("Pattern letter count must be 2: " + cur); } - } else if (cur == 'I') { appendZoneId(); } else if (cur == 'Z') { if (count > 3) { throw new IllegalArgumentException("Too many pattern letters: " + cur); } - if (count < 3) { - appendOffset("+HHMM", "+0000"); - } else { - appendOffset("+HH:MM", "+00:00"); - } + appendOffset("+HHMM", "+0000"); } else if (cur == 'X') { if (count > 5) { throw new IllegalArgumentException("Too many pattern letters: " + cur); } - appendOffset(OffsetIdPrinterParser.PATTERNS[count - 1], "Z"); + appendOffset(OffsetIdPrinterParser.PATTERNS[count + (count == 1 ? 0 : 1)], "Z"); + } else if (cur == 'x') { + if (count > 5) { + throw new IllegalArgumentException("Too many pattern letters: " + cur); + } + String zero = (count == 1 ? "+00" : (count % 2 == 0 ? "+0000" : "+00:00")); + appendOffset(OffsetIdPrinterParser.PATTERNS[count + (count == 1 ? 0 : 1)], zero); } else if (cur == 'w' || cur == 'e') { // Fields defined by Locale if (count > 1) { @@ -1196,7 +1391,6 @@ public final class DateTimeFormatterBuilder { appendValue(field, count, 19, SignStyle.EXCEEDS_PAD); } break; - case 'G': case 'M': case 'Q': case 'E': @@ -1220,6 +1414,7 @@ public final class DateTimeFormatterBuilder { throw new IllegalArgumentException("Too many pattern letters: " + cur); } break; + case 'G': case 'a': switch (count) { case 1: @@ -1253,44 +1448,44 @@ public final class DateTimeFormatterBuilder { /** Map of letters to fields. */ private static final Map FIELD_MAP = new HashMap<>(); static { - FIELD_MAP.put('G', ChronoField.ERA); // Java, CLDR (different to both for 1/2 chars) - FIELD_MAP.put('y', ChronoField.YEAR); // CLDR - // FIELD_MAP.put('y', ChronoField.YEAR_OF_ERA); // Java, CLDR // TODO redefine from above - // FIELD_MAP.put('u', ChronoField.YEAR); // CLDR // TODO - // FIELD_MAP.put('Y', ISODateTimeField.WEEK_BASED_YEAR); // Java7, CLDR (needs localized week number) // TODO - FIELD_MAP.put('Q', ISOFields.QUARTER_OF_YEAR); // CLDR (removed quarter from 310) - FIELD_MAP.put('M', ChronoField.MONTH_OF_YEAR); // Java, CLDR - // FIELD_MAP.put('w', WeekFields.weekOfYear()); // Java, CLDR (needs localized week number) - // FIELD_MAP.put('W', WeekFields.weekOfMonth()); // Java, CLDR (needs localized week number) - FIELD_MAP.put('D', ChronoField.DAY_OF_YEAR); // Java, CLDR - FIELD_MAP.put('d', ChronoField.DAY_OF_MONTH); // Java, CLDR - FIELD_MAP.put('F', ChronoField.ALIGNED_WEEK_OF_MONTH); // Java, CLDR - FIELD_MAP.put('E', ChronoField.DAY_OF_WEEK); // Java, CLDR (different to both for 1/2 chars) - // FIELD_MAP.put('e', WeekFields.dayOfWeek()); // CLDR (needs localized week number) - FIELD_MAP.put('a', ChronoField.AMPM_OF_DAY); // Java, CLDR - FIELD_MAP.put('H', ChronoField.HOUR_OF_DAY); // Java, CLDR - FIELD_MAP.put('k', ChronoField.CLOCK_HOUR_OF_DAY); // Java, CLDR - FIELD_MAP.put('K', ChronoField.HOUR_OF_AMPM); // Java, CLDR - FIELD_MAP.put('h', ChronoField.CLOCK_HOUR_OF_AMPM); // Java, CLDR - FIELD_MAP.put('m', ChronoField.MINUTE_OF_HOUR); // Java, CLDR - FIELD_MAP.put('s', ChronoField.SECOND_OF_MINUTE); // Java, CLDR - FIELD_MAP.put('S', ChronoField.NANO_OF_SECOND); // CLDR (Java uses milli-of-second number) - FIELD_MAP.put('A', ChronoField.MILLI_OF_DAY); // CLDR - FIELD_MAP.put('n', ChronoField.NANO_OF_SECOND); // 310 - FIELD_MAP.put('N', ChronoField.NANO_OF_DAY); // 310 - // reserved - z,Z,X,I,p - // Java - X - compatible, but extended to 4 and 5 letters - // Java - u - clashes with CLDR, go with CLDR (year-proleptic) here - // CLDR - U - cycle year name, not supported by 310 yet - // CLDR - l - deprecated - // CLDR - j - not relevant - // CLDR - g - modified-julian-day - // CLDR - z - time-zone names // TODO properly - // CLDR - Z - different approach here // TODO bring 310 in line with CLDR - // CLDR - v,V - extended time-zone names - // CLDR - q/c/L - standalone quarter/day-of-week/month - // 310 - I - time-zone id - // 310 - p - prefix for padding + FIELD_MAP.put('G', ChronoField.ERA); // Java, LDML (different to both for 1/2 chars) + FIELD_MAP.put('y', ChronoField.YEAR); // LDML + // FIELD_MAP.put('y', ChronoField.YEAR_OF_ERA); // Java, LDML // TODO redefine from above + // FIELD_MAP.put('u', ChronoField.YEAR); // LDML // TODO + // FIELD_MAP.put('Y', IsoFields.WEEK_BASED_YEAR); // Java7, LDML (needs localized week number) // TODO + FIELD_MAP.put('Q', IsoFields.QUARTER_OF_YEAR); // LDML (removed quarter from 310) + FIELD_MAP.put('M', ChronoField.MONTH_OF_YEAR); // Java, LDML + // FIELD_MAP.put('w', WeekFields.weekOfYear()); // Java, LDML (needs localized week number) + // FIELD_MAP.put('W', WeekFields.weekOfMonth()); // Java, LDML (needs localized week number) + FIELD_MAP.put('D', ChronoField.DAY_OF_YEAR); // Java, LDML + FIELD_MAP.put('d', ChronoField.DAY_OF_MONTH); // Java, LDML + FIELD_MAP.put('F', ChronoField.ALIGNED_WEEK_OF_MONTH); // Java, LDML + FIELD_MAP.put('E', ChronoField.DAY_OF_WEEK); // Java, LDML (different to both for 1/2 chars) + // FIELD_MAP.put('e', WeekFields.dayOfWeek()); // LDML (needs localized week number) + FIELD_MAP.put('a', ChronoField.AMPM_OF_DAY); // Java, LDML + FIELD_MAP.put('H', ChronoField.HOUR_OF_DAY); // Java, LDML + FIELD_MAP.put('k', ChronoField.CLOCK_HOUR_OF_DAY); // Java, LDML + FIELD_MAP.put('K', ChronoField.HOUR_OF_AMPM); // Java, LDML + FIELD_MAP.put('h', ChronoField.CLOCK_HOUR_OF_AMPM); // Java, LDML + FIELD_MAP.put('m', ChronoField.MINUTE_OF_HOUR); // Java, LDML + FIELD_MAP.put('s', ChronoField.SECOND_OF_MINUTE); // Java, LDML + FIELD_MAP.put('S', ChronoField.NANO_OF_SECOND); // LDML (Java uses milli-of-second number) + FIELD_MAP.put('A', ChronoField.MILLI_OF_DAY); // LDML + FIELD_MAP.put('n', ChronoField.NANO_OF_SECOND); // 310 (proposed for LDML) + FIELD_MAP.put('N', ChronoField.NANO_OF_DAY); // 310 (proposed for LDML) + // 310 - z - time-zone names, matches LDML and SimpleDateFormat 1 to 4 + // 310 - Z - matches SimpleDateFormat and LDML + // 310 - V - time-zone id, matches proposed LDML + // 310 - p - prefix for padding + // 310 - X - matches proposed LDML, almost matches JavaSDF for 1, exact match 2&3, extended 4&5 + // 310 - x - matches proposed LDML + // Java - u - clashes with LDML, go with LDML (year-proleptic) here + // LDML - U - cycle year name, not supported by 310 yet + // LDML - l - deprecated + // LDML - j - not relevant + // LDML - g - modified-julian-day + // LDML - v,V - extended time-zone names + // LDML - q/c/L - standalone quarter/day-of-week/month } //----------------------------------------------------------------------- @@ -1299,8 +1494,15 @@ public final class DateTimeFormatterBuilder { *

      * This padding will pad to a fixed width using spaces. *

      - * An exception will be thrown during printing if the pad width - * is exceeded. + * During formatting, the decorated element will be output and then padded + * to the specified width. An exception will be thrown during formatting if + * the pad width is exceeded. + *

      + * During parsing, the padding and decorated element are parsed. + * If parsing is lenient, then the pad width is treated as a maximum. + * If parsing is case insensitive, then the pad character is matched ignoring case. + * The padding is parsed greedily. Thus, if the decorated element starts with + * the pad character, it will not be parsed. * * @param padWidth the pad width, 1 or greater * @return this, for chaining, not null @@ -1316,8 +1518,15 @@ public final class DateTimeFormatterBuilder { * This padding is intended for padding other than zero-padding. * Zero-padding should be achieved using the appendValue methods. *

      - * An exception will be thrown during printing if the pad width - * is exceeded. + * During formatting, the decorated element will be output and then padded + * to the specified width. An exception will be thrown during formatting if + * the pad width is exceeded. + *

      + * During parsing, the padding and decorated element are parsed. + * If parsing is lenient, then the pad width is treated as a maximum. + * If parsing is case insensitive, then the pad character is matched ignoring case. + * The padding is parsed greedily. Thus, if the decorated element starts with + * the pad character, it will not be parsed. * * @param padWidth the pad width, 1 or greater * @param padChar the pad character @@ -1338,19 +1547,19 @@ public final class DateTimeFormatterBuilder { /** * Mark the start of an optional section. *

      - * The output of printing can include optional sections, which may be nested. + * The output of formatting can include optional sections, which may be nested. * An optional section is started by calling this method and ended by calling * {@link #optionalEnd()} or by ending the build process. *

      * All elements in the optional section are treated as optional. - * During printing, the section is only output if data is available in the + * During formatting, the section is only output if data is available in the * {@code TemporalAccessor} for all the elements in the section. * During parsing, the whole section may be missing from the parsed string. *

      * For example, consider a builder setup as * {@code builder.appendValue(HOUR_OF_DAY,2).optionalStart().appendValue(MINUTE_OF_HOUR,2)}. * The optional section ends automatically at the end of the builder. - * During printing, the minute will only be output if its value can be obtained from the date-time. + * During formatting, the minute will only be output if its value can be obtained from the date-time. * During parsing, the input will be successfully parsed whether the minute is present or not. * * @return this, for chaining, not null @@ -1364,7 +1573,7 @@ public final class DateTimeFormatterBuilder { /** * Ends an optional section. *

      - * The output of printing can include optional sections, which may be nested. + * The output of formatting can include optional sections, which may be nested. * An optional section is started by calling {@link #optionalStart()} and ended * using this method (or at the end of the builder). *

      @@ -1374,13 +1583,13 @@ public final class DateTimeFormatterBuilder { * on the formatter other than ending the (empty) optional section. *

      * All elements in the optional section are treated as optional. - * During printing, the section is only output if data is available in the + * During formatting, the section is only output if data is available in the * {@code TemporalAccessor} for all the elements in the section. * During parsing, the whole section may be missing from the parsed string. *

      * For example, consider a builder setup as * {@code builder.appendValue(HOUR_OF_DAY,2).optionalStart().appendValue(MINUTE_OF_HOUR,2).optionalEnd()}. - * During printing, the minute will only be output if its value can be obtained from the date-time. + * During formatting, the minute will only be output if its value can be obtained from the date-time. * During parsing, the input will be successfully parsed whether the minute is present or not. * * @return this, for chaining, not null @@ -1466,18 +1675,17 @@ public final class DateTimeFormatterBuilder { //----------------------------------------------------------------------- /** - * Strategy for printing/parsing date-time information. + * Strategy for formatting/parsing date-time information. *

      - * The printer may print any part, or the whole, of the input date-time object. - * Typically, a complete print is constructed from a number of smaller + * The printer may format any part, or the whole, of the input date-time object. + * Typically, a complete format is constructed from a number of smaller * units, each outputting a single field. *

      * The parser may parse any piece of text from the input, storing the result * in the context. Typically, each individual parser will just parse one * field, such as the day-of-month, storing the value in the context. - * Once the parse is complete, the caller will then convert the context - * to a {@link DateTimeBuilder} to merge the parsed values to create the - * desired object, such as a {@code LocalDate}. + * Once the parse is complete, the caller will then resolve the parsed values + * to create the desired object, such as a {@code LocalDate}. *

      * The parse position will be updated during the parse. Parsing will start at * the specified index and the return value specifies the new parse position @@ -1489,7 +1697,7 @@ public final class DateTimeFormatterBuilder { * All implementations that can be instantiated must be final, immutable and thread-safe. *

      * The context is not a thread-safe object and a new instance will be created - * for each print that occurs. The context must not be stored in an instance + * for each format that occurs. The context must not be stored in an instance * variable or shared with any other threads. */ interface DateTimePrinterParser { @@ -1497,17 +1705,17 @@ public final class DateTimeFormatterBuilder { /** * Prints the date-time object to the buffer. *

      - * The context holds information to use during the print. + * The context holds information to use during the format. * It also contains the date-time information to be printed. *

      * The buffer must not be mutated beyond the content controlled by the implementation. * - * @param context the context to print using, not null + * @param context the context to format using, not null * @param buf the buffer to append to, not null * @return false if unable to query the value from the date-time, true otherwise * @throws DateTimeException if the date-time cannot be printed successfully */ - boolean print(DateTimePrintContext context, StringBuilder buf); + boolean format(DateTimePrintContext context, StringBuilder buf); /** * Parses text into date-time information. @@ -1557,14 +1765,14 @@ public final class DateTimeFormatterBuilder { } @Override - public boolean print(DateTimePrintContext context, StringBuilder buf) { + public boolean format(DateTimePrintContext context, StringBuilder buf) { int length = buf.length(); if (optional) { context.startOptional(); } try { for (DateTimePrinterParser pp : printerParsers) { - if (pp.print(context, buf) == false) { + if (pp.format(context, buf) == false) { buf.setLength(length); // reset buffer return true; } @@ -1640,14 +1848,14 @@ public final class DateTimeFormatterBuilder { } @Override - public boolean print(DateTimePrintContext context, StringBuilder buf) { + public boolean format(DateTimePrintContext context, StringBuilder buf) { int preLen = buf.length(); - if (printerParser.print(context, buf) == false) { + if (printerParser.format(context, buf) == false) { return false; } int len = buf.length() - preLen; if (len > padWidth) { - throw new DateTimePrintException( + throw new DateTimeException( "Cannot print as output of " + len + " characters exceeds pad width of " + padWidth); } for (int i = 0; i < padWidth - len; i++) { @@ -1658,37 +1866,32 @@ public final class DateTimeFormatterBuilder { @Override public int parse(DateTimeParseContext context, CharSequence text, int position) { + // cache context before changed by decorated parser + final boolean strict = context.isStrict(); + // parse if (position > text.length()) { throw new IndexOutOfBoundsException(); } + if (position == text.length()) { + return ~position; // no more characters in the string + } int endPos = position + padWidth; if (endPos > text.length()) { - return ~position; // not enough characters in the string to meet the parse width + if (strict) { + return ~position; // not enough characters in the string to meet the parse width + } + endPos = text.length(); } int pos = position; - while (pos < endPos && text.charAt(pos) == padChar) { + while (pos < endPos && context.charEquals(text.charAt(pos), padChar)) { pos++; } text = text.subSequence(0, endPos); - int firstError = 0; - while (pos >= position) { - int resultPos = printerParser.parse(context, text, pos); - if (resultPos < 0) { - // parse of decorated field had an error - if (firstError == 0) { - firstError = resultPos; - } - // loop around in case the decorated parser can handle the padChar at the start - pos--; - continue; - } - if (resultPos != endPos) { - return ~position; // parse of decorated field didn't parse to the end - } - return resultPos; + int resultPos = printerParser.parse(context, text, pos); + if (resultPos != endPos && strict) { + return ~(position + pos); // parse of decorated field didn't parse to the end } - // loop runs at least once, so firstError must be set by the time we get here - return firstError; // return error from first parse of decorated field + return resultPos; } @Override @@ -1708,7 +1911,7 @@ public final class DateTimeFormatterBuilder { LENIENT; @Override - public boolean print(DateTimePrintContext context, StringBuilder buf) { + public boolean format(DateTimePrintContext context, StringBuilder buf) { return true; // nothing to do here } @@ -1749,7 +1952,7 @@ public final class DateTimeFormatterBuilder { } @Override - public boolean print(DateTimePrintContext context, StringBuilder buf) { + public boolean format(DateTimePrintContext context, StringBuilder buf) { buf.append(literal); return true; } @@ -1792,7 +1995,7 @@ public final class DateTimeFormatterBuilder { } @Override - public boolean print(DateTimePrintContext context, StringBuilder buf) { + public boolean format(DateTimePrintContext context, StringBuilder buf) { buf.append(literal); return true; } @@ -1847,7 +2050,7 @@ public final class DateTimeFormatterBuilder { /** * Constructor. * - * @param field the field to print, not null + * @param field the field to format, not null * @param minWidth the minimum field width, from 1 to 19 * @param maxWidth the maximum field width, from minWidth to 19 * @param signStyle the positive/negative sign style, not null @@ -1864,7 +2067,7 @@ public final class DateTimeFormatterBuilder { /** * Constructor. * - * @param field the field to print, not null + * @param field the field to format, not null * @param minWidth the minimum field width, from 1 to 19 * @param maxWidth the maximum field width, from minWidth to 19 * @param signStyle the positive/negative sign style, not null @@ -1900,8 +2103,14 @@ public final class DateTimeFormatterBuilder { } @Override - public boolean print(DateTimePrintContext context, StringBuilder buf) { - Long valueLong = context.getValue(field); + public boolean format(DateTimePrintContext context, StringBuilder buf) { + Chronology chrono = context.getTemporal().query(Queries.chronology()); + Long valueLong; + if (chrono == JapaneseChronology.INSTANCE && field == ChronoField.YEAR) { + valueLong = context.getValue(ChronoField.YEAR_OF_ERA); + } else { + valueLong = context.getValue(field); + } if (valueLong == null) { return false; } @@ -1909,7 +2118,7 @@ public final class DateTimeFormatterBuilder { DateTimeFormatSymbols symbols = context.getSymbols(); String str = (value == Long.MIN_VALUE ? "9223372036854775808" : Long.toString(Math.abs(value))); if (str.length() > maxWidth) { - throw new DateTimePrintException("Field " + field.getName() + + throw new DateTimeException("Field " + field.getName() + " cannot be printed as the value " + value + " exceeds the maximum print width of " + maxWidth); } @@ -1934,7 +2143,7 @@ public final class DateTimeFormatterBuilder { buf.append(symbols.getNegativeSign()); break; case NOT_NEGATIVE: - throw new DateTimePrintException("Field " + field.getName() + + throw new DateTimeException("Field " + field.getName() + " cannot be printed as the value " + value + " cannot be negative according to the SignStyle"); } @@ -2057,11 +2266,9 @@ public final class DateTimeFormatterBuilder { totalBig = totalBig.divide(BigInteger.TEN); pos--; } - setValue(context, totalBig.longValue()); - } else { - setValue(context, total); + return setValue(context, totalBig.longValue(), position, pos); } - return pos; + return setValue(context, total, position, pos); } /** @@ -2069,9 +2276,19 @@ public final class DateTimeFormatterBuilder { * * @param context the context to store into, not null * @param value the value + * @param errorPos the position of the field being parsed + * @param successPos the position after the field being parsed + * @return the new position */ - void setValue(DateTimeParseContext context, long value) { - context.setParsedField(field, value); + int setValue(DateTimeParseContext context, long value, int errorPos, int successPos) { + TemporalField f = field; + if (field == ChronoField.YEAR) { + Chronology chrono = context.getEffectiveChronology(); + if (chrono == JapaneseChronology.INSTANCE) { + f = ChronoField.YEAR_OF_ERA; + } + } + return context.setParsedField(f, value, errorPos, successPos); } @Override @@ -2097,7 +2314,7 @@ public final class DateTimeFormatterBuilder { /** * Constructor. * - * @param field the field to print, validated not null + * @param field the field to format, validated not null * @param width the field width, from 1 to 18 * @param baseValue the base value */ @@ -2122,7 +2339,7 @@ public final class DateTimeFormatterBuilder { } @Override - void setValue(DateTimeParseContext context, long value) { + int setValue(DateTimeParseContext context, long value, int errorPos, int successPos) { int lastPart = baseValue % range; if (baseValue > 0) { value = baseValue - lastPart + value; @@ -2132,7 +2349,7 @@ public final class DateTimeFormatterBuilder { if (value < baseValue) { value += range; } - context.setParsedField(field, value); + return context.setParsedField(field, value, errorPos, successPos); } @Override @@ -2191,7 +2408,7 @@ public final class DateTimeFormatterBuilder { } @Override - public boolean print(DateTimePrintContext context, StringBuilder buf) { + public boolean format(DateTimePrintContext context, StringBuilder buf) { Long value = context.getValue(field); if (value == null) { return false; @@ -2257,8 +2474,7 @@ public final class DateTimeFormatterBuilder { } BigDecimal fraction = new BigDecimal(total).movePointLeft(pos - position); long value = convertFromFraction(fraction); - context.setParsedField(field, value); - return pos; + return context.setParsedField(field, value, position, pos); } /** @@ -2348,23 +2564,20 @@ public final class DateTimeFormatterBuilder { } @Override - public boolean print(DateTimePrintContext context, StringBuilder buf) { + public boolean format(DateTimePrintContext context, StringBuilder buf) { Long value = context.getValue(field); if (value == null) { return false; } - String text = null; - if (field == ChronoField.ERA) { - Chrono chrono = context.getTemporal().query(Queries.chrono()); - if (chrono == null) { - chrono = ISOChrono.INSTANCE; - } - text = provider.getEraText(chrono, value, textStyle, context.getLocale()); - } else { + String text; + Chronology chrono = context.getTemporal().query(Queries.chronology()); + if (chrono == null || chrono == IsoChronology.INSTANCE) { text = provider.getText(field, value, textStyle, context.getLocale()); + } else { + text = provider.getText(chrono, field, value, textStyle, context.getLocale()); } if (text == null) { - return numberPrinterParser().print(context, buf); + return numberPrinterParser().format(context, buf); } buf.append(text); return true; @@ -2377,14 +2590,19 @@ public final class DateTimeFormatterBuilder { throw new IndexOutOfBoundsException(); } TextStyle style = (context.isStrict() ? textStyle : null); - Iterator> it = provider.getTextIterator(field, style, context.getLocale()); + Chronology chrono = context.getEffectiveChronology(); + Iterator> it; + if (chrono == null || chrono == IsoChronology.INSTANCE) { + it = provider.getTextIterator(field, style, context.getLocale()); + } else { + it = provider.getTextIterator(chrono, field, style, context.getLocale()); + } if (it != null) { while (it.hasNext()) { Entry entry = it.next(); String itText = entry.getKey(); if (context.subSequenceEquals(itText, 0, parseText, position, itText.length())) { - context.setParsedField(field, entry.getValue()); - return position + itText.length(); + return context.setParsedField(field, entry.getValue(), position, position + itText.length()); } } if (context.isStrict()) { @@ -2426,15 +2644,15 @@ public final class DateTimeFormatterBuilder { private static final long SECONDS_0000_TO_1970 = ((146097L * 5L) - (30L * 365L + 7L)) * 86400L; private static final CompositePrinterParser PARSER = new DateTimeFormatterBuilder() .parseCaseInsensitive() - .append(DateTimeFormatters.isoLocalDate()).appendLiteral('T') - .append(DateTimeFormatters.isoLocalTime()).appendLiteral('Z') + .append(DateTimeFormatter.ISO_LOCAL_DATE).appendLiteral('T') + .append(DateTimeFormatter.ISO_LOCAL_TIME).appendLiteral('Z') .toFormatter().toPrinterParser(false); InstantPrinterParser() { } @Override - public boolean print(DateTimePrintContext context, StringBuilder buf) { + public boolean format(DateTimePrintContext context, StringBuilder buf) { // use INSTANT_SECONDS, thus this code is not bound by Instant.MAX Long inSecs = context.getValue(INSTANT_SECONDS); Long inNanos = context.getValue(NANO_OF_SECOND); @@ -2502,9 +2720,9 @@ public final class DateTimeFormatterBuilder { } catch (RuntimeException ex) { return ~position; } - context.setParsedField(INSTANT_SECONDS, instantSecs); - context.setParsedField(NANO_OF_SECOND, nano); - return text.length(); + int successPos = text.length(); + successPos = context.setParsedField(INSTANT_SECONDS, instantSecs, position, successPos); + return context.setParsedField(NANO_OF_SECOND, nano, position, successPos); } @Override @@ -2519,9 +2737,10 @@ public final class DateTimeFormatterBuilder { */ static final class OffsetIdPrinterParser implements DateTimePrinterParser { static final String[] PATTERNS = new String[] { - "+HH", "+HHMM", "+HH:MM", "+HHMMss", "+HH:MM:ss", "+HHMMSS", "+HH:MM:SS", + "+HH", "+HHmm", "+HH:mm", "+HHMM", "+HH:MM", "+HHMMss", "+HH:MM:ss", "+HHMMSS", "+HH:MM:SS", }; // order used in pattern builder - static final OffsetIdPrinterParser INSTANCE_ID = new OffsetIdPrinterParser("Z", "+HH:MM:ss"); + static final OffsetIdPrinterParser INSTANCE_ID_Z = new OffsetIdPrinterParser("+HH:MM:ss", "Z"); + static final OffsetIdPrinterParser INSTANCE_ID_ZERO = new OffsetIdPrinterParser("+HH:MM:ss", "0"); private final String noOffsetText; private final int type; @@ -2529,14 +2748,14 @@ public final class DateTimeFormatterBuilder { /** * Constructor. * - * @param noOffsetText the text to use for UTC, not null * @param pattern the pattern + * @param noOffsetText the text to use for UTC, not null */ - OffsetIdPrinterParser(String noOffsetText, String pattern) { - Objects.requireNonNull(noOffsetText, "noOffsetText"); + OffsetIdPrinterParser(String pattern, String noOffsetText) { Objects.requireNonNull(pattern, "pattern"); - this.noOffsetText = noOffsetText; + Objects.requireNonNull(noOffsetText, "noOffsetText"); this.type = checkPattern(pattern); + this.noOffsetText = noOffsetText; } private int checkPattern(String pattern) { @@ -2549,7 +2768,7 @@ public final class DateTimeFormatterBuilder { } @Override - public boolean print(DateTimePrintContext context, StringBuilder buf) { + public boolean format(DateTimePrintContext context, StringBuilder buf) { Long offsetSecs = context.getValue(OFFSET_SECONDS); if (offsetSecs == null) { return false; @@ -2561,16 +2780,24 @@ public final class DateTimeFormatterBuilder { int absHours = Math.abs((totalSecs / 3600) % 100); // anything larger than 99 silently dropped int absMinutes = Math.abs((totalSecs / 60) % 60); int absSeconds = Math.abs(totalSecs % 60); + int bufPos = buf.length(); + int output = absHours; buf.append(totalSecs < 0 ? "-" : "+") .append((char) (absHours / 10 + '0')).append((char) (absHours % 10 + '0')); - if (type >= 1) { + if (type >= 3 || (type >= 1 && absMinutes > 0)) { buf.append((type % 2) == 0 ? ":" : "") .append((char) (absMinutes / 10 + '0')).append((char) (absMinutes % 10 + '0')); - if (type >= 5 || (type >= 3 && absSeconds > 0)) { + output += absMinutes; + if (type >= 7 || (type >= 5 && absSeconds > 0)) { buf.append((type % 2) == 0 ? ":" : "") .append((char) (absSeconds / 10 + '0')).append((char) (absSeconds % 10 + '0')); + output += absSeconds; } } + if (output == 0) { + buf.setLength(bufPos); + buf.append(noOffsetText); + } } return true; } @@ -2581,16 +2808,14 @@ public final class DateTimeFormatterBuilder { int noOffsetLen = noOffsetText.length(); if (noOffsetLen == 0) { if (position == length) { - context.setParsedField(OFFSET_SECONDS, 0); - return position; + return context.setParsedField(OFFSET_SECONDS, 0, position, position); } } else { if (position == length) { return ~position; } if (context.subSequenceEquals(text, position, noOffsetText, 0, noOffsetLen)) { - context.setParsedField(OFFSET_SECONDS, 0); - return position + noOffsetLen; + return context.setParsedField(OFFSET_SECONDS, 0, position, position + noOffsetLen); } } @@ -2601,22 +2826,19 @@ public final class DateTimeFormatterBuilder { int negative = (sign == '-' ? -1 : 1); int[] array = new int[4]; array[0] = position + 1; - if (parseNumber(array, 1, text, true) || - parseNumber(array, 2, text, type > 0) || - parseNumber(array, 3, text, false)) { - return ~position; + if ((parseNumber(array, 1, text, true) || + parseNumber(array, 2, text, type >=3) || + parseNumber(array, 3, text, false)) == false) { + // success + long offsetSecs = negative * (array[1] * 3600L + array[2] * 60L + array[3]); + return context.setParsedField(OFFSET_SECONDS, offsetSecs, position, array[0]); } - long offsetSecs = negative * (array[1] * 3600L + array[2] * 60L + array[3]); - context.setParsedField(OFFSET_SECONDS, offsetSecs); - return array[0]; - } else { - // handle special case of empty no offset text - if (noOffsetLen == 0) { - context.setParsedField(OFFSET_SECONDS, 0); - return position + noOffsetLen; - } - return ~position; } + // handle special case of empty no offset text + if (noOffsetLen == 0) { + return context.setParsedField(OFFSET_SECONDS, 0, position, position + noOffsetLen); + } + return ~position; } /** @@ -2659,7 +2881,7 @@ public final class DateTimeFormatterBuilder { @Override public String toString() { String converted = noOffsetText.replace("'", "''"); - return "Offset('" + converted + "'," + PATTERNS[type] + ")"; + return "Offset(" + PATTERNS[type] + ",'" + converted + "')"; } } @@ -2667,29 +2889,38 @@ public final class DateTimeFormatterBuilder { /** * Prints or parses a zone ID. */ - static final class ZoneTextPrinterParser implements DateTimePrinterParser { + static final class ZoneTextPrinterParser extends ZoneIdPrinterParser { /** The text style to output. */ private final TextStyle textStyle; - ZoneTextPrinterParser(TextStyle textStyle) { + /** The preferred zoneid map */ + private Set preferredZones; + + ZoneTextPrinterParser(TextStyle textStyle, Set preferredZones) { + super(Queries.zone(), "ZoneText(" + textStyle + ")"); this.textStyle = Objects.requireNonNull(textStyle, "textStyle"); + if (preferredZones != null && preferredZones.size() != 0) { + this.preferredZones = new HashSet<>(); + for (ZoneId id : preferredZones) { + this.preferredZones.add(id.getId()); + } + } } private static final int STD = 0; private static final int DST = 1; private static final int GENERIC = 2; - private static final Map>> cache = new ConcurrentHashMap<>(); - private static String getDisplayName(String id, int type, TextStyle style, Locale locale) { - if (style == TextStyle.NARROW) { + private String getDisplayName(String id, int type, Locale locale) { + if (textStyle == TextStyle.NARROW) { return null; } String[] names; SoftReference> ref = cache.get(id); - Map perLocale; + Map perLocale = null; if (ref == null || (perLocale = ref.get()) == null || (names = perLocale.get(locale)) == null) { names = TimeZoneNameUtility.retrieveDisplayNames(id, locale); @@ -2707,55 +2938,99 @@ public final class DateTimeFormatterBuilder { if (names[6] == null) { names[6] = names[0]; } - perLocale = new ConcurrentHashMap<>(); + if (perLocale == null) { + perLocale = new ConcurrentHashMap<>(); + } perLocale.put(locale, names); - ref = new SoftReference<>(perLocale); - cache.put(id, ref); + cache.put(id, new SoftReference<>(perLocale)); } switch (type) { case STD: - return names[style.ordinal() + 1]; + return names[textStyle.ordinal() + 1]; case DST: - return names[style.ordinal() + 3]; + return names[textStyle.ordinal() + 3]; } - return names[style.ordinal() + 5]; + return names[textStyle.ordinal() + 5]; } @Override - public boolean print(DateTimePrintContext context, StringBuilder buf) { + public boolean format(DateTimePrintContext context, StringBuilder buf) { ZoneId zone = context.getValue(Queries.zoneId()); if (zone == null) { return false; } - if (zone instanceof ZoneOffset) { - buf.append(zone.getId()); - } else { + String zname = zone.getId(); + if (!(zone instanceof ZoneOffset)) { TemporalAccessor dt = context.getTemporal(); - Instant instant = null; - if (dt.isSupported(ChronoField.INSTANT_SECONDS)) { - instant = Instant.from(dt); - } - String name = getDisplayName(zone.getId(), - instant == null ? GENERIC - : (zone.getRules().isDaylightSavings(instant) ? DST : STD), - textStyle, context.getLocale()); + String name = getDisplayName(zname, + dt.isSupported(ChronoField.INSTANT_SECONDS) + ? (zone.getRules().isDaylightSavings(Instant.from(dt)) ? DST : STD) + : GENERIC, + context.getLocale()); if (name != null) { - buf.append(name); - } else { - buf.append(zone.getId()); + zname = name; } } + buf.append(zname); return true; } - @Override - public int parse(DateTimeParseContext context, CharSequence text, int position) { - throw new UnsupportedOperationException(); - } + // cache per instance for now + private final Map>> + cachedTree = new HashMap<>(); + private final Map>> + cachedTreeCI = new HashMap<>(); @Override - public String toString() { - return "ZoneText(" + textStyle + ")"; + protected PrefixTree getTree(DateTimeParseContext context) { + if (textStyle == TextStyle.NARROW) { + return super.getTree(context); + } + Locale locale = context.getLocale(); + boolean isCaseSensitive = context.isCaseSensitive(); + Set regionIds = ZoneRulesProvider.getAvailableZoneIds(); + int regionIdsSize = regionIds.size(); + + Map>> cached = + isCaseSensitive ? cachedTree : cachedTreeCI; + + Entry> entry = null; + PrefixTree tree = null; + String[][] zoneStrings = null; + if ((entry = cached.get(locale)) == null || + (entry.getKey() != regionIdsSize || + (tree = entry.getValue().get()) == null)) { + tree = PrefixTree.newTree(context); + zoneStrings = TimeZoneNameUtility.getZoneStrings(locale); + for (String[] names : zoneStrings) { + String zid = names[0]; + if (!regionIds.contains(zid)) { + continue; + } + tree.add(zid, zid); // don't convert zid -> metazone + zid = ZoneName.toZid(zid, locale); + int i = textStyle == TextStyle.FULL ? 1 : 2; + for (; i < names.length; i += 2) { + tree.add(names[i], zid); + } + } + // if we have a set of preferred zones, need a copy and + // add the preferred zones again to overwrite + if (preferredZones != null) { + for (String[] names : zoneStrings) { + String zid = names[0]; + if (!preferredZones.contains(zid) || !regionIds.contains(zid)) { + continue; + } + int i = textStyle == TextStyle.FULL ? 1 : 2; + for (; i < names.length; i += 2) { + tree.add(names[i], zid); + } + } + } + cached.put(locale, new SimpleImmutableEntry<>(regionIdsSize, new SoftReference<>(tree))); + } + return tree; } } @@ -2763,7 +3038,7 @@ public final class DateTimeFormatterBuilder { /** * Prints or parses a zone ID. */ - static final class ZoneIdPrinterParser implements DateTimePrinterParser { + static class ZoneIdPrinterParser implements DateTimePrinterParser { private final TemporalQuery query; private final String description; @@ -2772,9 +3047,8 @@ public final class DateTimeFormatterBuilder { this.description = description; } - //----------------------------------------------------------------------- @Override - public boolean print(DateTimePrintContext context, StringBuilder buf) { + public boolean format(DateTimePrintContext context, StringBuilder buf) { ZoneId zone = context.getValue(query); if (zone == null) { return false; @@ -2783,13 +3057,34 @@ public final class DateTimeFormatterBuilder { return true; } - //----------------------------------------------------------------------- /** * The cached tree to speed up parsing. */ private static volatile Entry cachedPrefixTree; private static volatile Entry cachedPrefixTreeCI; + protected PrefixTree getTree(DateTimeParseContext context) { + // prepare parse tree + Set regionIds = ZoneRulesProvider.getAvailableZoneIds(); + final int regionIdsSize = regionIds.size(); + Entry cached = context.isCaseSensitive() + ? cachedPrefixTree : cachedPrefixTreeCI; + if (cached == null || cached.getKey() != regionIdsSize) { + synchronized (this) { + cached = context.isCaseSensitive() ? cachedPrefixTree : cachedPrefixTreeCI; + if (cached == null || cached.getKey() != regionIdsSize) { + cached = new SimpleImmutableEntry<>(regionIdsSize, PrefixTree.newTree(regionIds, context)); + if (context.isCaseSensitive()) { + cachedPrefixTree = cached; + } else { + cachedPrefixTreeCI = cached; + } + } + } + } + return cached.getValue(); + } + /** * This implementation looks for the longest matching string. * For example, parsing Etc/GMT-2 will return Etc/GMC-2 rather than just @@ -2801,58 +3096,57 @@ public final class DateTimeFormatterBuilder { if (position > length) { throw new IndexOutOfBoundsException(); } + if (position == length) { + return ~position; + } // handle fixed time-zone IDs - if ((text.length() - position) >= 1) { - char nextChar = text.charAt(position); - if (nextChar == '+' || nextChar == '-') { - DateTimeParseContext newContext = context.copy(); - int endPos = OffsetIdPrinterParser.INSTANCE_ID.parse(newContext, text, position); - if (endPos < 0) { - return endPos; + char nextChar = text.charAt(position); + if (nextChar == '+' || nextChar == '-') { + return parseOffsetBased(context, text, position, OffsetIdPrinterParser.INSTANCE_ID_Z); + } else if (length >= position + 2) { + char nextNextChar = text.charAt(position + 1); + if (context.charEquals(nextChar, 'U') && context.charEquals(nextNextChar, 'T')) { + if (length >= position + 3 && context.charEquals(text.charAt(position + 2), 'C')) { + return parseOffsetBased(context, text, position + 3, OffsetIdPrinterParser.INSTANCE_ID_ZERO); } - int offset = (int) (long) newContext.getParsed(OFFSET_SECONDS); - ZoneId zone = ZoneOffset.ofTotalSeconds(offset); - context.setParsed(zone); - return endPos; + return parseOffsetBased(context, text, position + 2, OffsetIdPrinterParser.INSTANCE_ID_ZERO); + } else if (context.charEquals(nextChar, 'G') && length >= position + 3 && + context.charEquals(nextNextChar, 'M') && context.charEquals(text.charAt(position + 2), 'T')) { + return parseOffsetBased(context, text, position + 3, OffsetIdPrinterParser.INSTANCE_ID_ZERO); } } - // prepare parse tree - Set regionIds = ZoneRulesProvider.getAvailableZoneIds(); - final int regionIdsSize = regionIds.size(); - Entry cached = context.isCaseSensitive() - ? cachedPrefixTree : cachedPrefixTreeCI; - if (cached == null || cached.getKey() != regionIdsSize) { - synchronized (this) { - cached = context.isCaseSensitive() ? cachedPrefixTree : cachedPrefixTreeCI; - if (cached == null || cached.getKey() != regionIdsSize) { - cached = new SimpleImmutableEntry<>(regionIdsSize, - PrefixTree.newTree(regionIds, context.isCaseSensitive() - ? PrefixTree.STRICT : PrefixTree.CASE_INSENSITIVE)); - if (context.isCaseSensitive()) { - cachedPrefixTree = cached; - } else { - cachedPrefixTreeCI = cached; - } - } - } - } - PrefixTree tree = cached.getValue(); - // parse - String parsedZoneId = tree.match(text, position, length); - if (parsedZoneId == null || regionIds.contains(parsedZoneId) == false) { - if (text.charAt(position) == 'Z') { + PrefixTree tree = getTree(context); + ParsePosition ppos = new ParsePosition(position); + String parsedZoneId = tree.match(text, ppos); + if (parsedZoneId == null) { + if (context.charEquals(nextChar, 'Z')) { context.setParsed(ZoneOffset.UTC); return position + 1; } return ~position; } context.setParsed(ZoneId.of(parsedZoneId)); - return position + parsedZoneId.length(); + return ppos.getIndex(); } + private int parseOffsetBased(DateTimeParseContext context, CharSequence text, int position, OffsetIdPrinterParser parser) { + DateTimeParseContext newContext = context.copy(); + int endPos = parser.parse(newContext, text, position); + if (endPos < 0) { + if (parser == OffsetIdPrinterParser.INSTANCE_ID_Z) { + return ~position; + } + context.setParsed(ZoneOffset.UTC); + return position; + } + int offset = (int) newContext.getParsed(OFFSET_SECONDS).longValue(); + ZoneId zone = ZoneOffset.ofTotalSeconds(offset); + context.setParsed(zone); + return endPos; + } @Override public String toString() { @@ -2872,10 +3166,6 @@ public final class DateTimeFormatterBuilder { protected PrefixTree child; protected PrefixTree sibling; - static final int STRICT = 1; - static final int CASE_INSENSITIVE = 2; - static final int LENIENT = 3; - private PrefixTree(String k, String v, PrefixTree child) { this.key = k; this.value = v; @@ -2888,46 +3178,51 @@ public final class DateTimeFormatterBuilder { } /** - * Creates a new prefix parsing tree. + * Creates a new prefix parsing tree based on parse context. * - * @param type the type of the prefix tree. One of the three supported - * types, STRICT, CASE_INSENSITIVE and LENIENT + * @param context the parse context * @return the tree, not null */ - public static PrefixTree newTree(int type) { - PrefixTree tree; - switch(type) { - case STRICT: - tree = new PrefixTree("", null, null); - break; - case CASE_INSENSITIVE: - tree = new CI("", null, null); - break; - case LENIENT: - tree = new LENIENT("", null, null); - break; - default: - throw new IllegalArgumentException("Unknown type"); + public static PrefixTree newTree(DateTimeParseContext context) { + //if (!context.isStrict()) { + // return new LENIENT("", null, null); + //} + if (context.isCaseSensitive()) { + return new PrefixTree("", null, null); } - return tree; + return new CI("", null, null); } /** * Creates a new prefix parsing tree. * * @param keys a set of strings to build the prefix parsing tree, not null - * @param type the type of the prefix tree. One of the three supported - * types, STRICT, CASE_INSENSITIVE and LENIENT + * @param context the parse context * @return the tree, not null */ - public static PrefixTree newTree(Set keys, int type) { - PrefixTree tree = newTree(type); + public static PrefixTree newTree(Set keys, DateTimeParseContext context) { + PrefixTree tree = newTree(context); for (String k : keys) { tree.add0(k, k); } return tree; } + /** + * Clone a copy of this tree + */ + public PrefixTree copyTree() { + PrefixTree copy = new PrefixTree(key, value, null); + if (child != null) { + copy.child = child.copyTree(); + } + if (sibling != null) { + copy.sibling = sibling.copyTree(); + } + return copy; + } + + /** * Adds a pair of {key, value} into the prefix tree. * @@ -2958,10 +3253,10 @@ public final class DateTimeFormatterBuilder { child = c; return true; } - // have an existing already, keep it. - if (value != null) { - return false; - } + // have an existing already, overwrite it + // if (value != null) { + // return false; + //} value = v; return true; } @@ -3097,9 +3392,7 @@ public final class DateTimeFormatterBuilder { @Override protected boolean isEqual(char c1, char c2) { - return c1 == c2 || - Character.toUpperCase(c1) == Character.toUpperCase(c2) || - Character.toLowerCase(c1) == Character.toLowerCase(c2); + return DateTimeParseContext.charEqualsIgnoreCase(c1, c2); } @Override @@ -3213,8 +3506,8 @@ public final class DateTimeFormatterBuilder { } @Override - public boolean print(DateTimePrintContext context, StringBuilder buf) { - Chrono chrono = context.getValue(Queries.chrono()); + public boolean format(DateTimePrintContext context, StringBuilder buf) { + Chronology chrono = context.getValue(Queries.chronology()); if (chrono == null) { return false; } @@ -3228,7 +3521,26 @@ public final class DateTimeFormatterBuilder { @Override public int parse(DateTimeParseContext context, CharSequence text, int position) { - return ~position; // TODO, including case insensitive + // simple looping parser to find the chronology + if (position < 0 || position > text.length()) { + throw new IndexOutOfBoundsException(); + } + Set chronos = Chronology.getAvailableChronologies(); + Chronology bestMatch = null; + int matchLen = -1; + for (Chronology chrono : chronos) { + String id = chrono.getId(); + int idLen = id.length(); + if (idLen > matchLen && context.subSequenceEquals(text, position, id, 0, idLen)) { + bestMatch = chrono; + matchLen = idLen; + } + } + if (bestMatch == null) { + return ~position; + } + context.setParsed(bestMatch); + return position + matchLen; } } @@ -3239,40 +3551,40 @@ public final class DateTimeFormatterBuilder { static final class LocalizedPrinterParser implements DateTimePrinterParser { private final FormatStyle dateStyle; private final FormatStyle timeStyle; - private final Chrono chrono; /** * Constructor. * * @param dateStyle the date style to use, may be null * @param timeStyle the time style to use, may be null - * @param chrono the chronology to use, not null */ - LocalizedPrinterParser(FormatStyle dateStyle, FormatStyle timeStyle, Chrono chrono) { + LocalizedPrinterParser(FormatStyle dateStyle, FormatStyle timeStyle) { // validated by caller this.dateStyle = dateStyle; this.timeStyle = timeStyle; - this.chrono = chrono; } @Override - public boolean print(DateTimePrintContext context, StringBuilder buf) { - return formatter(context.getLocale()).toPrinterParser(false).print(context, buf); + public boolean format(DateTimePrintContext context, StringBuilder buf) { + Chronology chrono = Chronology.from(context.getTemporal()); + return formatter(context.getLocale(), chrono).toPrinterParser(false).format(context, buf); } @Override public int parse(DateTimeParseContext context, CharSequence text, int position) { - return formatter(context.getLocale()).toPrinterParser(false).parse(context, text, position); + Chronology chrono = context.getEffectiveChronology(); + return formatter(context.getLocale(), chrono).toPrinterParser(false).parse(context, text, position); } /** * Gets the formatter to use. * * @param locale the locale to use, not null + * @param chrono the chronology to use, not null * @return the formatter, not null * @throws IllegalArgumentException if the formatter cannot be found */ - private DateTimeFormatter formatter(Locale locale) { + private DateTimeFormatter formatter(Locale locale, Chronology chrono) { return DateTimeFormatStyleProvider.getInstance() .getFormatter(dateStyle, timeStyle, chrono, locale); } @@ -3280,7 +3592,7 @@ public final class DateTimeFormatterBuilder { @Override public String toString() { return "Localized(" + (dateStyle != null ? dateStyle : "") + "," + - (timeStyle != null ? timeStyle : "") + "," + chrono.getId() + ")"; + (timeStyle != null ? timeStyle : "") + ")"; } } @@ -3309,8 +3621,8 @@ public final class DateTimeFormatterBuilder { } @Override - public boolean print(DateTimePrintContext context, StringBuilder buf) { - return printerParser(context.getLocale()).print(context, buf); + public boolean format(DateTimePrintContext context, StringBuilder buf) { + return printerParser(context.getLocale()).format(context, buf); } @Override diff --git a/jdk/src/share/classes/java/time/format/DateTimeFormatters.java b/jdk/src/share/classes/java/time/format/DateTimeFormatters.java deleted file mode 100644 index d1d6efd43a0..00000000000 --- a/jdk/src/share/classes/java/time/format/DateTimeFormatters.java +++ /dev/null @@ -1,972 +0,0 @@ -/* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * 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 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.SECOND_OF_MINUTE; -import static java.time.temporal.ChronoField.YEAR; - -import java.time.ZoneId; -import java.time.ZoneOffset; -import java.time.temporal.ChronoField; -import java.time.temporal.ISOFields; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; - -/** - * Provides common implementations of {@code DateTimeFormatter}. - *

      - * This utility class provides three different ways to obtain a formatter. - *

        - *
      • Using pattern letters, such as {@code yyyy-MMM-dd} - *
      • Using localized styles, such as {@code long} or {@code medium} - *
      • Using predefined constants, such as {@code isoLocalDate()} - *

      - * - *

      Specification for implementors

      - * This is a thread-safe utility class. - * All returned formatters are immutable and thread-safe. - * - * @since 1.8 - */ -public final class DateTimeFormatters { - - /** - * Private constructor since this is a utility class. - */ - private DateTimeFormatters() { - } - - //----------------------------------------------------------------------- - /** - * Creates a formatter using the specified pattern. - *

      - * This method will create a formatter based on a simple pattern of letters and symbols. - * For example, {@code d MMM yyyy} will format 2011-12-03 as '3 Dec 2011'. - *

      - * The returned formatter will use the default locale, but this can be changed - * using {@link DateTimeFormatter#withLocale(Locale)}. - *

      - * All letters 'A' to 'Z' and 'a' to 'z' are reserved as pattern letters. - * The following pattern letters are defined: - *

      -     *  Symbol  Meaning                     Presentation      Examples
      -     *  ------  -------                     ------------      -------
      -     *   G       era                         number/text       1; 01; AD; Anno Domini
      -     *   y       year                        year              2004; 04
      -     *   D       day-of-year                 number            189
      -     *   M       month-of-year               number/text       7; 07; Jul; July; J
      -     *   d       day-of-month                number            10
      -     *
      -     *   Q       quarter-of-year             number/text       3; 03; Q3
      -     *   Y       week-based-year             year              1996; 96
      -     *   w       week-of-year                number            27
      -     *   W       week-of-month               number            27
      -     *   e       localized day-of-week       number            2; Tue; Tuesday; T
      -     *   E       day-of-week                 number/text       2; Tue; Tuesday; T
      -     *   F       week-of-month               number            3
      -     *
      -     *   a       am-pm-of-day                text              PM
      -     *   h       clock-hour-of-am-pm (1-12)  number            12
      -     *   K       hour-of-am-pm (0-11)        number            0
      -     *   k       clock-hour-of-am-pm (1-24)  number            0
      -     *
      -     *   H       hour-of-day (0-23)          number            0
      -     *   m       minute-of-hour              number            30
      -     *   s       second-of-minute            number            55
      -     *   S       fraction-of-second          fraction          978
      -     *   A       milli-of-day                number            1234
      -     *   n       nano-of-second              number            987654321
      -     *   N       nano-of-day                 number            1234000000
      -     *
      -     *   I       time-zone ID                zoneId            America/Los_Angeles
      -     *   z       time-zone name              text              Pacific Standard Time; PST
      -     *   Z       zone-offset                 offset-Z          +0000; -0800; -08:00;
      -     *   X       zone-offset 'Z' for zero    offset-X          Z; -08; -0830; -08:30; -083015; -08:30:15;
      -     *
      -     *   p       pad next                    pad modifier      1
      -     *
      -     *   '       escape for text             delimiter
      -     *   ''      single quote                literal           '
      -     *   [       optional section start
      -     *   ]       optional section end
      -     *   {}      reserved for future use
      -     * 
      - *

      - * The count of pattern letters determine the format. - *

      - * Text: The text style is determined based on the number of pattern letters used. - * Less than 4 pattern letters will use the {@link TextStyle#SHORT short form}. - * Exactly 4 pattern letters will use the {@link TextStyle#FULL full form}. - * Exactly 5 pattern letters will use the {@link TextStyle#NARROW narrow form}. - *

      - * Number: If the count of letters is one, then the value is printed using the minimum number - * of digits and without padding as per {@link DateTimeFormatterBuilder#appendValue(java.time.temporal.TemporalField)}. - * Otherwise, the count of digits is used as the width of the output field as per - * {@link DateTimeFormatterBuilder#appendValue(java.time.temporal.TemporalField, int)}. - *

      - * Number/Text: If the count of pattern letters is 3 or greater, use the Text rules above. - * Otherwise use the Number rules above. - *

      - * Fraction: Outputs the nano-of-second field as a fraction-of-second. - * The nano-of-second value has nine digits, thus the count of pattern letters is from 1 to 9. - * If it is less than 9, then the nano-of-second value is truncated, with only the most - * significant digits being output. - * When parsing in strict mode, the number of parsed digits must match the count of pattern letters. - * When parsing in lenient mode, the number of parsed digits must be at least the count of pattern - * letters, up to 9 digits. - *

      - * Year: The count of letters determines the minimum field width below which padding is used. - * If the count of letters is two, then a {@link DateTimeFormatterBuilder#appendValueReduced reduced} - * two digit form is used. - * For printing, this outputs the rightmost two digits. For parsing, this will parse using the - * base value of 2000, resulting in a year within the range 2000 to 2099 inclusive. - * If the count of letters is less than four (but not two), then the sign is only output for negative - * years as per {@link SignStyle#NORMAL}. - * Otherwise, the sign is output if the pad width is exceeded, as per {@link SignStyle#EXCEEDS_PAD} - *

      - * ZoneId: 'I' outputs the zone ID, such as 'Europe/Paris'. - *

      - * Offset X: This formats the offset using 'Z' when the offset is zero. - * One letter outputs just the hour', such as '+01' - * Two letters outputs the hour and minute, without a colon, such as '+0130'. - * Three letters outputs the hour and minute, with a colon, such as '+01:30'. - * Four letters outputs the hour and minute and optional second, without a colon, such as '+013015'. - * Five letters outputs the hour and minute and optional second, with a colon, such as '+01:30:15'. - *

      - * Offset Z: This formats the offset using '+0000' or '+00:00' when the offset is zero. - * One or two letters outputs the hour and minute, without a colon, such as '+0130'. - * Three letters outputs the hour and minute, with a colon, such as '+01:30'. - *

      - * Zone names: Time zone names ('z') cannot be parsed. - *

      - * Optional section: The optional section markers work exactly like calling - * {@link DateTimeFormatterBuilder#optionalStart()} and {@link DateTimeFormatterBuilder#optionalEnd()}. - *

      - * Pad modifier: Modifies the pattern that immediately follows to be padded with spaces. - * The pad width is determined by the number of pattern letters. - * This is the same as calling {@link DateTimeFormatterBuilder#padNext(int)}. - *

      - * For example, 'ppH' outputs the hour-of-day padded on the left with spaces to a width of 2. - *

      - * Any unrecognized letter is an error. - * Any non-letter character, other than '[', ']', '{', '}' and the single quote will be output directly. - * Despite this, it is recommended to use single quotes around all characters that you want to - * output directly to ensure that future changes do not break your application. - *

      - * The pattern string is similar, but not identical, to {@link java.text.SimpleDateFormat SimpleDateFormat}. - * Pattern letters 'E' and 'u' are merged, which changes the meaning of "E" and "EE" to be numeric. - * Pattern letters 'Z' and 'X' are extended. - * Pattern letter 'y' and 'Y' parse years of two digits and more than 4 digits differently. - * Pattern letters 'n', 'A', 'N', 'I' and 'p' are added. - * Number types will reject large numbers. - * The pattern string is also similar, but not identical, to that defined by the - * Unicode Common Locale Data Repository (CLDR). - * - * @param pattern the pattern to use, not null - * @return the formatter based on the pattern, not null - * @throws IllegalArgumentException if the pattern is invalid - * @see DateTimeFormatterBuilder#appendPattern(String) - */ - public static DateTimeFormatter pattern(String pattern) { - return new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter(); - } - - /** - * Creates a formatter using the specified pattern. - *

      - * This method will create a formatter based on a simple pattern of letters and symbols. - * For example, {@code d MMM yyyy} will format 2011-12-03 as '3 Dec 2011'. - *

      - * See {@link #pattern(String)} for details of the pattern. - *

      - * The returned formatter will use the specified locale, but this can be changed - * using {@link DateTimeFormatter#withLocale(Locale)}. - * - * @param pattern the pattern to use, not null - * @param locale the locale to use, not null - * @return the formatter based on the pattern, not null - * @throws IllegalArgumentException if the pattern is invalid - * @see DateTimeFormatterBuilder#appendPattern(String) - */ - public static DateTimeFormatter pattern(String pattern, Locale locale) { - return new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter(locale); - } - - //----------------------------------------------------------------------- - /** - * Returns a locale specific date format. - *

      - * This returns a formatter that will print/parse a date. - * The exact format pattern used varies by locale. - *

      - * The locale is determined from the formatter. The formatter returned directly by - * this method will use the {@link Locale#getDefault(Locale.Category) default FORMAT locale}. - * The locale can be controlled using {@link DateTimeFormatter#withLocale(Locale) withLocale(Locale)} - * on the result of this method. - *

      - * Note that the localized pattern is looked up lazily. - * This {@code DateTimeFormatter} holds the style required and the locale, - * looking up the pattern required on demand. - * - * @param dateStyle the formatter style to obtain, not null - * @return the date formatter, not null - */ - public static DateTimeFormatter localizedDate(FormatStyle dateStyle) { - Objects.requireNonNull(dateStyle, "dateStyle"); - return new DateTimeFormatterBuilder().appendLocalized(dateStyle, null).toFormatter(); - } - - /** - * Returns a locale specific time format. - *

      - * This returns a formatter that will print/parse a time. - * The exact format pattern used varies by locale. - *

      - * The locale is determined from the formatter. The formatter returned directly by - * this method will use the {@link Locale#getDefault(Locale.Category) default FORMAT locale}. - * The locale can be controlled using {@link DateTimeFormatter#withLocale(Locale) withLocale(Locale)} - * on the result of this method. - *

      - * Note that the localized pattern is looked up lazily. - * This {@code DateTimeFormatter} holds the style required and the locale, - * looking up the pattern required on demand. - * - * @param timeStyle the formatter style to obtain, not null - * @return the time formatter, not null - */ - public static DateTimeFormatter localizedTime(FormatStyle timeStyle) { - Objects.requireNonNull(timeStyle, "timeStyle"); - return new DateTimeFormatterBuilder().appendLocalized(null, timeStyle).toFormatter(); - } - - /** - * Returns a locale specific date-time format, which is typically of short length. - *

      - * This returns a formatter that will print/parse a date-time. - * The exact format pattern used varies by locale. - *

      - * The locale is determined from the formatter. The formatter returned directly by - * this method will use the {@link Locale#getDefault(Locale.Category) default FORMAT locale}. - * The locale can be controlled using {@link DateTimeFormatter#withLocale(Locale) withLocale(Locale)} - * on the result of this method. - *

      - * Note that the localized pattern is looked up lazily. - * This {@code DateTimeFormatter} holds the style required and the locale, - * looking up the pattern required on demand. - * - * @param dateTimeStyle the formatter style to obtain, not null - * @return the date-time formatter, not null - */ - public static DateTimeFormatter localizedDateTime(FormatStyle dateTimeStyle) { - Objects.requireNonNull(dateTimeStyle, "dateTimeStyle"); - return new DateTimeFormatterBuilder().appendLocalized(dateTimeStyle, dateTimeStyle).toFormatter(); - } - - /** - * Returns a locale specific date and time format. - *

      - * This returns a formatter that will print/parse a date-time. - * The exact format pattern used varies by locale. - *

      - * The locale is determined from the formatter. The formatter returned directly by - * this method will use the {@link Locale#getDefault() default FORMAT locale}. - * The locale can be controlled using {@link DateTimeFormatter#withLocale(Locale) withLocale(Locale)} - * on the result of this method. - *

      - * Note that the localized pattern is looked up lazily. - * This {@code DateTimeFormatter} holds the style required and the locale, - * looking up the pattern required on demand. - * - * @param dateStyle the date formatter style to obtain, not null - * @param timeStyle the time formatter style to obtain, not null - * @return the date, time or date-time formatter, not null - */ - public static DateTimeFormatter localizedDateTime(FormatStyle dateStyle, FormatStyle timeStyle) { - Objects.requireNonNull(dateStyle, "dateStyle"); - Objects.requireNonNull(timeStyle, "timeStyle"); - return new DateTimeFormatterBuilder().appendLocalized(dateStyle, timeStyle).toFormatter(); - } - - //----------------------------------------------------------------------- - /** - * Returns the ISO date formatter that prints/parses a date without an offset, - * such as '2011-12-03'. - *

      - * This returns an immutable formatter capable of printing and parsing - * the ISO-8601 extended local date format. - * The format consists of: - *

        - *
      • Four digits or more for the {@link ChronoField#YEAR year}. - * Years in the range 0000 to 9999 will be pre-padded by zero to ensure four digits. - * Years outside that range will have a prefixed positive or negative symbol. - *
      • A dash - *
      • Two digits for the {@link ChronoField#MONTH_OF_YEAR month-of-year}. - * This is pre-padded by zero to ensure two digits. - *
      • A dash - *
      • Two digits for the {@link ChronoField#DAY_OF_MONTH day-of-month}. - * This is pre-padded by zero to ensure two digits. - *

      - * - * @return the ISO local date formatter, not null - */ - public static DateTimeFormatter isoLocalDate() { - return ISO_LOCAL_DATE; - } - - /** Singleton date formatter. */ - private static final DateTimeFormatter ISO_LOCAL_DATE; - static { - ISO_LOCAL_DATE = new DateTimeFormatterBuilder() - .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD) - .appendLiteral('-') - .appendValue(MONTH_OF_YEAR, 2) - .appendLiteral('-') - .appendValue(DAY_OF_MONTH, 2) - .toFormatter(); - } - - //----------------------------------------------------------------------- - /** - * Returns the ISO date formatter that prints/parses a date with an offset, - * such as '2011-12-03+01:00'. - *

      - * This returns an immutable formatter capable of printing and parsing - * the ISO-8601 extended offset date format. - * The format consists of: - *

        - *
      • The {@link #isoLocalDate()} - *
      • The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then - * they will be handled even though this is not part of the ISO-8601 standard. - * Parsing is case insensitive. - *

      - * - * @return the ISO offset date formatter, not null - */ - public static DateTimeFormatter isoOffsetDate() { - return ISO_OFFSET_DATE; - } - - /** Singleton date formatter. */ - private static final DateTimeFormatter ISO_OFFSET_DATE; - static { - ISO_OFFSET_DATE = new DateTimeFormatterBuilder() - .parseCaseInsensitive() - .append(ISO_LOCAL_DATE) - .appendOffsetId() - .toFormatter(); - } - - //----------------------------------------------------------------------- - /** - * Returns the ISO date formatter that prints/parses a date with the - * offset if available, such as '2011-12-03' or '2011-12-03+01:00'. - *

      - * This returns an immutable formatter capable of printing and parsing - * the ISO-8601 extended date format. - * The format consists of: - *

        - *
      • The {@link #isoLocalDate()} - *
      • If the offset is not available to print/parse then the format is complete. - *
      • The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then - * they will be handled even though this is not part of the ISO-8601 standard. - * Parsing is case insensitive. - *

      - * As this formatter has an optional element, it may be necessary to parse using - * {@link DateTimeFormatter#parseBest}. - * - * @return the ISO date formatter, not null - */ - public static DateTimeFormatter isoDate() { - return ISO_DATE; - } - - /** Singleton date formatter. */ - private static final DateTimeFormatter ISO_DATE; - static { - ISO_DATE = new DateTimeFormatterBuilder() - .parseCaseInsensitive() - .append(ISO_LOCAL_DATE) - .optionalStart() - .appendOffsetId() - .toFormatter(); - } - - //----------------------------------------------------------------------- - /** - * Returns the ISO time formatter that prints/parses a time without an offset, - * such as '10:15' or '10:15:30'. - *

      - * This returns an immutable formatter capable of printing and parsing - * the ISO-8601 extended local time format. - * The format consists of: - *

        - *
      • Two digits for the {@link ChronoField#HOUR_OF_DAY hour-of-day}. - * This is pre-padded by zero to ensure two digits. - *
      • A colon - *
      • Two digits for the {@link ChronoField#MINUTE_OF_HOUR minute-of-hour}. - * This is pre-padded by zero to ensure two digits. - *
      • If the second-of-minute is not available to print/parse then the format is complete. - *
      • A colon - *
      • Two digits for the {@link ChronoField#SECOND_OF_MINUTE second-of-minute}. - * This is pre-padded by zero to ensure two digits. - *
      • If the nano-of-second is zero or not available to print/parse then the format is complete. - *
      • A decimal point - *
      • One to nine digits for the {@link ChronoField#NANO_OF_SECOND nano-of-second}. - * As many digits will be printed as required. - *

      - * - * @return the ISO local time formatter, not null - */ - public static DateTimeFormatter isoLocalTime() { - return ISO_LOCAL_TIME; - } - - /** Singleton date formatter. */ - private static final DateTimeFormatter ISO_LOCAL_TIME; - static { - ISO_LOCAL_TIME = new DateTimeFormatterBuilder() - .appendValue(HOUR_OF_DAY, 2) - .appendLiteral(':') - .appendValue(MINUTE_OF_HOUR, 2) - .optionalStart() - .appendLiteral(':') - .appendValue(SECOND_OF_MINUTE, 2) - .optionalStart() - .appendFraction(NANO_OF_SECOND, 0, 9, true) - .toFormatter(); - } - - //----------------------------------------------------------------------- - /** - * Returns the ISO time formatter that prints/parses a time with an offset, - * such as '10:15+01:00' or '10:15:30+01:00'. - *

      - * This returns an immutable formatter capable of printing and parsing - * the ISO-8601 extended offset time format. - * The format consists of: - *

        - *
      • The {@link #isoLocalTime()} - *
      • The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then - * they will be handled even though this is not part of the ISO-8601 standard. - * Parsing is case insensitive. - *

      - * - * @return the ISO offset time formatter, not null - */ - public static DateTimeFormatter isoOffsetTime() { - return ISO_OFFSET_TIME; - } - - /** Singleton date formatter. */ - private static final DateTimeFormatter ISO_OFFSET_TIME; - static { - ISO_OFFSET_TIME = new DateTimeFormatterBuilder() - .parseCaseInsensitive() - .append(ISO_LOCAL_TIME) - .appendOffsetId() - .toFormatter(); - } - - //----------------------------------------------------------------------- - /** - * Returns the ISO time formatter that prints/parses a time, with the - * offset if available, such as '10:15', '10:15:30' or '10:15:30+01:00'. - *

      - * This returns an immutable formatter capable of printing and parsing - * the ISO-8601 extended offset time format. - * The format consists of: - *

        - *
      • The {@link #isoLocalTime()} - *
      • If the offset is not available to print/parse then the format is complete. - *
      • The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then - * they will be handled even though this is not part of the ISO-8601 standard. - * Parsing is case insensitive. - *

      - * As this formatter has an optional element, it may be necessary to parse using - * {@link DateTimeFormatter#parseBest}. - * - * @return the ISO time formatter, not null - */ - public static DateTimeFormatter isoTime() { - return ISO_TIME; - } - - /** Singleton date formatter. */ - private static final DateTimeFormatter ISO_TIME; - static { - ISO_TIME = new DateTimeFormatterBuilder() - .parseCaseInsensitive() - .append(ISO_LOCAL_TIME) - .optionalStart() - .appendOffsetId() - .toFormatter(); - } - - //----------------------------------------------------------------------- - /** - * Returns the ISO date formatter that prints/parses a date-time - * without an offset, such as '2011-12-03T10:15:30'. - *

      - * This returns an immutable formatter capable of printing and parsing - * the ISO-8601 extended offset date-time format. - * The format consists of: - *

        - *
      • The {@link #isoLocalDate()} - *
      • The letter 'T'. Parsing is case insensitive. - *
      • The {@link #isoLocalTime()} - *

      - * - * @return the ISO local date-time formatter, not null - */ - public static DateTimeFormatter isoLocalDateTime() { - return ISO_LOCAL_DATE_TIME; - } - - /** Singleton date formatter. */ - private static final DateTimeFormatter ISO_LOCAL_DATE_TIME; - static { - ISO_LOCAL_DATE_TIME = new DateTimeFormatterBuilder() - .parseCaseInsensitive() - .append(ISO_LOCAL_DATE) - .appendLiteral('T') - .append(ISO_LOCAL_TIME) - .toFormatter(); - } - - //----------------------------------------------------------------------- - /** - * Returns the ISO date formatter that prints/parses a date-time - * with an offset, such as '2011-12-03T10:15:30+01:00'. - *

      - * This returns an immutable formatter capable of printing and parsing - * the ISO-8601 extended offset date-time format. - * The format consists of: - *

        - *
      • The {@link #isoLocalDateTime()} - *
      • The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then - * they will be handled even though this is not part of the ISO-8601 standard. - * Parsing is case insensitive. - *

      - * - * @return the ISO offset date-time formatter, not null - */ - public static DateTimeFormatter isoOffsetDateTime() { - return ISO_OFFSET_DATE_TIME; - } - - /** Singleton date formatter. */ - private static final DateTimeFormatter ISO_OFFSET_DATE_TIME; - static { - ISO_OFFSET_DATE_TIME = new DateTimeFormatterBuilder() - .parseCaseInsensitive() - .append(ISO_LOCAL_DATE_TIME) - .appendOffsetId() - .toFormatter(); - } - - //----------------------------------------------------------------------- - /** - * Returns the ISO date formatter that prints/parses a date-time with - * offset and zone, such as '2011-12-03T10:15:30+01:00[Europe/Paris]'. - *

      - * This returns an immutable formatter capable of printing and parsing - * a format that extends the ISO-8601 extended offset date-time format - * to add the time-zone. - * The format consists of: - *

        - *
      • The {@link #isoOffsetDateTime()} - *
      • If the zone ID is not available or is a {@code ZoneOffset} then the format is complete. - *
      • An open square bracket '['. - *
      • The {@link ZoneId#getId() zone ID}. This is not part of the ISO-8601 standard. - * Parsing is case sensitive. - *
      • A close square bracket ']'. - *

      - * - * @return the ISO zoned date-time formatter, not null - */ - public static DateTimeFormatter isoZonedDateTime() { - return ISO_ZONED_DATE_TIME; - } - - /** Singleton date formatter. */ - private static final DateTimeFormatter ISO_ZONED_DATE_TIME; - static { - ISO_ZONED_DATE_TIME = new DateTimeFormatterBuilder() - .append(ISO_OFFSET_DATE_TIME) - .optionalStart() - .appendLiteral('[') - .parseCaseSensitive() - .appendZoneRegionId() - .appendLiteral(']') - .toFormatter(); - } - - //----------------------------------------------------------------------- - /** - * Returns the ISO date formatter that prints/parses a date-time - * with the offset and zone if available, such as '2011-12-03T10:15:30', - * '2011-12-03T10:15:30+01:00' or '2011-12-03T10:15:30+01:00[Europe/Paris]'. - *

      - * This returns an immutable formatter capable of printing and parsing - * the ISO-8601 extended offset date-time format. - * The format consists of: - *

        - *
      • The {@link #isoLocalDateTime()} - *
      • If the offset is not available to print/parse then the format is complete. - *
      • The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then - * they will be handled even though this is not part of the ISO-8601 standard. - *
      • If the zone ID is not available or is a {@code ZoneOffset} then the format is complete. - *
      • An open square bracket '['. - *
      • The {@link ZoneId#getId() zone ID}. This is not part of the ISO-8601 standard. - * Parsing is case sensitive. - *
      • A close square bracket ']'. - *

      - * As this formatter has an optional element, it may be necessary to parse using - * {@link DateTimeFormatter#parseBest}. - * - * @return the ISO date-time formatter, not null - */ - public static DateTimeFormatter isoDateTime() { - return ISO_DATE_TIME; - } - - /** Singleton date formatter. */ - private static final DateTimeFormatter ISO_DATE_TIME; - static { - ISO_DATE_TIME = new DateTimeFormatterBuilder() - .append(ISO_LOCAL_DATE_TIME) - .optionalStart() - .appendOffsetId() - .optionalStart() - .appendLiteral('[') - .parseCaseSensitive() - .appendZoneRegionId() - .appendLiteral(']') - .toFormatter(); - } - - //----------------------------------------------------------------------- - /** - * Returns the ISO date formatter that prints/parses the ordinal date - * without an offset, such as '2012-337'. - *

      - * This returns an immutable formatter capable of printing and parsing - * the ISO-8601 extended ordinal date format. - * The format consists of: - *

        - *
      • Four digits or more for the {@link ChronoField#YEAR year}. - * Years in the range 0000 to 9999 will be pre-padded by zero to ensure four digits. - * Years outside that range will have a prefixed positive or negative symbol. - *
      • A dash - *
      • Three digits for the {@link ChronoField#DAY_OF_YEAR day-of-year}. - * This is pre-padded by zero to ensure three digits. - *
      • If the offset is not available to print/parse then the format is complete. - *
      • The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then - * they will be handled even though this is not part of the ISO-8601 standard. - * Parsing is case insensitive. - *

      - * As this formatter has an optional element, it may be necessary to parse using - * {@link DateTimeFormatter#parseBest}. - * - * @return the ISO ordinal date formatter, not null - */ - public static DateTimeFormatter isoOrdinalDate() { - return ISO_ORDINAL_DATE; - } - - /** Singleton date formatter. */ - private static final DateTimeFormatter ISO_ORDINAL_DATE; - static { - ISO_ORDINAL_DATE = new DateTimeFormatterBuilder() - .parseCaseInsensitive() - .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD) - .appendLiteral('-') - .appendValue(DAY_OF_YEAR, 3) - .optionalStart() - .appendOffsetId() - .toFormatter(); - } - - //----------------------------------------------------------------------- - /** - * Returns the ISO date formatter that prints/parses the week-based date - * without an offset, such as '2012-W48-6'. - *

      - * This returns an immutable formatter capable of printing and parsing - * the ISO-8601 extended week-based date format. - * The format consists of: - *

        - *
      • Four digits or more for the {@link ISOFields#WEEK_BASED_YEAR week-based-year}. - * Years in the range 0000 to 9999 will be pre-padded by zero to ensure four digits. - * Years outside that range will have a prefixed positive or negative symbol. - *
      • A dash - *
      • The letter 'W'. Parsing is case insensitive. - *
      • Two digits for the {@link ISOFields#WEEK_OF_WEEK_BASED_YEAR week-of-week-based-year}. - * This is pre-padded by zero to ensure three digits. - *
      • A dash - *
      • One digit for the {@link ChronoField#DAY_OF_WEEK day-of-week}. - * The value run from Monday (1) to Sunday (7). - *
      • If the offset is not available to print/parse then the format is complete. - *
      • The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then - * they will be handled even though this is not part of the ISO-8601 standard. - * Parsing is case insensitive. - *

      - * As this formatter has an optional element, it may be necessary to parse using - * {@link DateTimeFormatter#parseBest}. - * - * @return the ISO week-based date formatter, not null - */ - public static DateTimeFormatter isoWeekDate() { - return ISO_WEEK_DATE; - } - - /** Singleton date formatter. */ - private static final DateTimeFormatter ISO_WEEK_DATE; - static { - ISO_WEEK_DATE = new DateTimeFormatterBuilder() - .parseCaseInsensitive() - .appendValue(ISOFields.WEEK_BASED_YEAR, 4, 10, SignStyle.EXCEEDS_PAD) - .appendLiteral("-W") - .appendValue(ISOFields.WEEK_OF_WEEK_BASED_YEAR, 2) - .appendLiteral('-') - .appendValue(DAY_OF_WEEK, 1) - .optionalStart() - .appendOffsetId() - .toFormatter(); - } - - //----------------------------------------------------------------------- - /** - * Returns the ISO instant formatter that prints/parses an instant in UTC. - *

      - * This returns an immutable formatter capable of printing and parsing - * the ISO-8601 instant format. - * The format consists of: - *

        - *
      • The {@link #isoOffsetDateTime()} where the instant is converted from - * {@link ChronoField#INSTANT_SECONDS} and {@link ChronoField#NANO_OF_SECOND} - * using the {@code UTC} offset. Parsing is case insensitive. - *

      - * - * @return the ISO instant formatter, not null - */ - public static DateTimeFormatter isoInstant() { - return ISO_INSTANT; - } - - /** Singleton formatter. */ - private static final DateTimeFormatter ISO_INSTANT; - static { - ISO_INSTANT = new DateTimeFormatterBuilder() - .parseCaseInsensitive() - .appendInstant() - .toFormatter(); - } - - //----------------------------------------------------------------------- - /** - * Returns the ISO date formatter that prints/parses a date without an offset, - * such as '20111203'. - *

      - * This returns an immutable formatter capable of printing and parsing - * the ISO-8601 basic local date format. - * The format consists of: - *

        - *
      • Four digits for the {@link ChronoField#YEAR year}. - * Only years in the range 0000 to 9999 are supported. - *
      • Two digits for the {@link ChronoField#MONTH_OF_YEAR month-of-year}. - * This is pre-padded by zero to ensure two digits. - *
      • Two digits for the {@link ChronoField#DAY_OF_MONTH day-of-month}. - * This is pre-padded by zero to ensure two digits. - *
      • If the offset is not available to print/parse then the format is complete. - *
      • The {@link ZoneOffset#getId() offset ID} without colons. If the offset has - * seconds then they will be handled even though this is not part of the ISO-8601 standard. - * Parsing is case insensitive. - *

      - * As this formatter has an optional element, it may be necessary to parse using - * {@link DateTimeFormatter#parseBest}. - * - * @return the ISO basic local date formatter, not null - */ - public static DateTimeFormatter basicIsoDate() { - return BASIC_ISO_DATE; - } - - /** Singleton date formatter. */ - private static final DateTimeFormatter BASIC_ISO_DATE; - static { - BASIC_ISO_DATE = new DateTimeFormatterBuilder() - .parseCaseInsensitive() - .appendValue(YEAR, 4) - .appendValue(MONTH_OF_YEAR, 2) - .appendValue(DAY_OF_MONTH, 2) - .optionalStart() - .appendOffset("+HHMMss", "Z") - .toFormatter(); - } - - //----------------------------------------------------------------------- - /** - * Returns the RFC-1123 date-time formatter, such as 'Tue, 3 Jun 2008 11:05:30 GMT'. - *

      - * This returns an immutable formatter capable of printing and parsing - * most of the RFC-1123 format. - * RFC-1123 updates RFC-822 changing the year from two digits to four. - * This implementation requires a four digit year. - * This implementation also does not handle North American or military zone - * names, only 'GMT' and offset amounts. - *

      - * The format consists of: - *

        - *
      • If the day-of-week is not available to print/parse then jump to day-of-month. - *
      • Three letter {@link ChronoField#DAY_OF_WEEK day-of-week} in English. - *
      • A comma - *
      • A space - *
      • One or two digits for the {@link ChronoField#DAY_OF_MONTH day-of-month}. - *
      • A space - *
      • Three letter {@link ChronoField#MONTH_OF_YEAR month-of-year} in English. - *
      • A space - *
      • Four digits for the {@link ChronoField#YEAR year}. - * Only years in the range 0000 to 9999 are supported. - *
      • A space - *
      • Two digits for the {@link ChronoField#HOUR_OF_DAY hour-of-day}. - * This is pre-padded by zero to ensure two digits. - *
      • A colon - *
      • Two digits for the {@link ChronoField#MINUTE_OF_HOUR minute-of-hour}. - * This is pre-padded by zero to ensure two digits. - *
      • If the second-of-minute is not available to print/parse then jump to the next space. - *
      • A colon - *
      • Two digits for the {@link ChronoField#SECOND_OF_MINUTE second-of-minute}. - * This is pre-padded by zero to ensure two digits. - *
      • A space - *
      • The {@link ZoneOffset#getId() offset ID} without colons or seconds. - * An offset of zero uses "GMT". North American zone names and military zone names are not handled. - *

      - * Parsing is case insensitive. - * - * @return the RFC-1123 formatter, not null - */ - public static DateTimeFormatter rfc1123() { - return RFC_1123_DATE_TIME; - } - - /** Singleton date formatter. */ - private static final DateTimeFormatter RFC_1123_DATE_TIME; - static { - // manually code maps to ensure correct data always used - // (locale data can be changed by application code) - Map dow = new HashMap<>(); - dow.put(1L, "Mon"); - dow.put(2L, "Tue"); - dow.put(3L, "Wed"); - dow.put(4L, "Thu"); - dow.put(5L, "Fri"); - dow.put(6L, "Sat"); - dow.put(7L, "Sun"); - Map moy = new HashMap<>(); - moy.put(1L, "Jan"); - moy.put(2L, "Feb"); - moy.put(3L, "Mar"); - moy.put(4L, "Apr"); - moy.put(5L, "May"); - moy.put(6L, "Jun"); - moy.put(7L, "Jul"); - moy.put(8L, "Aug"); - moy.put(9L, "Sep"); - moy.put(10L, "Oct"); - moy.put(11L, "Nov"); - moy.put(12L, "Dec"); - RFC_1123_DATE_TIME = new DateTimeFormatterBuilder() - .parseCaseInsensitive() - .parseLenient() - .optionalStart() - .appendText(DAY_OF_WEEK, dow) - .appendLiteral(", ") - .optionalEnd() - .appendValue(DAY_OF_MONTH, 1, 2, SignStyle.NOT_NEGATIVE) - .appendLiteral(' ') - .appendText(MONTH_OF_YEAR, moy) - .appendLiteral(' ') - .appendValue(YEAR, 4) // 2 digit year not handled - .appendLiteral(' ') - .appendValue(HOUR_OF_DAY, 2) - .appendLiteral(':') - .appendValue(MINUTE_OF_HOUR, 2) - .optionalStart() - .appendLiteral(':') - .appendValue(SECOND_OF_MINUTE, 2) - .optionalEnd() - .appendLiteral(' ') - .appendOffset("+HHMM", "GMT") // should handle UT/Z/EST/EDT/CST/CDT/MST/MDT/PST/MDT - .toFormatter(); - } - -} diff --git a/jdk/src/share/classes/java/time/format/DateTimeParseContext.java b/jdk/src/share/classes/java/time/format/DateTimeParseContext.java index 6da730ea1d4..62f80dba377 100644 --- a/jdk/src/share/classes/java/time/format/DateTimeParseContext.java +++ b/jdk/src/share/classes/java/time/format/DateTimeParseContext.java @@ -61,10 +61,19 @@ */ package java.time.format; +import java.time.DateTimeException; +import java.time.ZoneId; +import java.time.chrono.Chronology; +import java.time.chrono.IsoChronology; +import java.time.temporal.ChronoField; +import java.time.temporal.Queries; +import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalField; +import java.time.temporal.TemporalQuery; import java.util.ArrayList; -import java.util.List; +import java.util.HashMap; import java.util.Locale; +import java.util.Map; import java.util.Objects; /** @@ -84,7 +93,7 @@ import java.util.Objects; * * @since 1.8 */ -final class DateTimeParseContext { +final class DateTimeParseContext implements TemporalAccessor { /** * The formatter, not null. @@ -130,7 +139,7 @@ final class DateTimeParseContext { * * @return the locale, not null */ - public Locale getLocale() { + Locale getLocale() { return formatter.getLocale(); } @@ -141,17 +150,33 @@ final class DateTimeParseContext { * * @return the formatting symbols, not null */ - public DateTimeFormatSymbols getSymbols() { + DateTimeFormatSymbols getSymbols() { return formatter.getSymbols(); } + /** + * Gets the effective chronology during parsing. + * + * @return the effective parsing chronology, not null + */ + Chronology getEffectiveChronology() { + Chronology chrono = currentParsed().chrono; + if (chrono == null) { + chrono = formatter.getChronology(); + if (chrono == null) { + chrono = IsoChronology.INSTANCE; + } + } + return chrono; + } + //----------------------------------------------------------------------- /** * Checks if parsing is case sensitive. * * @return true if parsing is case sensitive, false if case insensitive */ - public boolean isCaseSensitive() { + boolean isCaseSensitive() { return caseSensitive; } @@ -160,10 +185,11 @@ final class DateTimeParseContext { * * @param caseSensitive changes the parsing to be case sensitive or not from now on */ - public void setCaseSensitive(boolean caseSensitive) { + void setCaseSensitive(boolean caseSensitive) { this.caseSensitive = caseSensitive; } + //----------------------------------------------------------------------- /** * Helper to compare two {@code CharSequence} instances. * This uses {@link #isCaseSensitive()}. @@ -175,7 +201,7 @@ final class DateTimeParseContext { * @param length the length to check, valid * @return true if equal */ - public boolean subSequenceEquals(CharSequence cs1, int offset1, CharSequence cs2, int offset2, int length) { + boolean subSequenceEquals(CharSequence cs1, int offset1, CharSequence cs2, int offset2, int length) { if (offset1 + length > cs1.length() || offset2 + length > cs2.length()) { return false; } @@ -200,6 +226,34 @@ final class DateTimeParseContext { return true; } + /** + * Helper to compare two {@code char}. + * This uses {@link #isCaseSensitive()}. + * + * @param ch1 the first character + * @param ch2 the second character + * @return true if equal + */ + boolean charEquals(char ch1, char ch2) { + if (isCaseSensitive()) { + return ch1 == ch2; + } + return charEqualsIgnoreCase(ch1, ch2); + } + + /** + * Compares two characters ignoring case. + * + * @param c1 the first + * @param c2 the second + * @return true if equal + */ + static boolean charEqualsIgnoreCase(char c1, char c2) { + return c1 == c2 || + Character.toUpperCase(c1) == Character.toUpperCase(c2) || + Character.toLowerCase(c1) == Character.toLowerCase(c2); + } + //----------------------------------------------------------------------- /** * Checks if parsing is strict. @@ -208,7 +262,7 @@ final class DateTimeParseContext { * * @return true if parsing is strict, false if lenient */ - public boolean isStrict() { + boolean isStrict() { return strict; } @@ -217,7 +271,7 @@ final class DateTimeParseContext { * * @param strict changes the parsing to be strict or lenient from now on */ - public void setStrict(boolean strict) { + void setStrict(boolean strict) { this.strict = strict; } @@ -264,45 +318,8 @@ final class DateTimeParseContext { * @param field the field to query from the map, null returns null * @return the value mapped to the specified field, null if field was not parsed */ - public Long getParsed(TemporalField field) { - for (Object obj : currentParsed().parsed) { - if (obj instanceof FieldValue) { - FieldValue fv = (FieldValue) obj; - if (fv.field.equals(field)) { - return fv.value; - } - } - } - return null; - } - - /** - * Gets the first value that was parsed for the specified type. - *

      - * This searches the results of the parse, returning the first date-time found - * of the specified type. No attempt is made to derive a value. - * - * @param clazz the type to query from the map, not null - * @return the temporal object, null if it was not parsed - */ - @SuppressWarnings("unchecked") - public T getParsed(Class clazz) { - for (Object obj : currentParsed().parsed) { - if (clazz.isInstance(obj)) { - return (T) obj; - } - } - return null; - } - - /** - * Gets the list of parsed temporal information. - * - * @return the list of parsed temporal objects, not null, no nulls - */ - List getParsed() { - // package scoped for testing - return currentParsed().parsed; + Long getParsed(TemporalField field) { + return currentParsed().fieldValues.get(field); } /** @@ -313,23 +330,40 @@ final class DateTimeParseContext { * * @param field the field to set in the field-value map, not null * @param value the value to set in the field-value map + * @param errorPos the position of the field being parsed + * @param successPos the position after the field being parsed + * @return the new position */ - public void setParsedField(TemporalField field, long value) { + int setParsedField(TemporalField field, long value, int errorPos, int successPos) { Objects.requireNonNull(field, "field"); - currentParsed().parsed.add(new FieldValue(field, value)); + Long old = currentParsed().fieldValues.put(field, value); + return (old != null && old.longValue() != value) ? ~errorPos : successPos; } /** - * Stores the parsed complete object. + * Stores the parsed chronology. *

      - * This stores a complete object that has been parsed. - * No validation is performed on the date-time other than ensuring it is not null. + * This stores the chronology that has been parsed. + * No validation is performed other than ensuring it is not null. * - * @param object the parsed object, not null + * @param chrono the parsed chronology, not null */ - public void setParsed(Object object) { - Objects.requireNonNull(object, "object"); - currentParsed().parsed.add(object); + void setParsed(Chronology chrono) { + Objects.requireNonNull(chrono, "chrono"); + currentParsed().chrono = chrono; + } + + /** + * Stores the parsed zone. + *

      + * This stores the zone that has been parsed. + * No validation is performed other than ensuring it is not null. + * + * @param zone the parsed zone, not null + */ + void setParsed(ZoneId zone) { + Objects.requireNonNull(zone, "zone"); + currentParsed().zone = zone; } //----------------------------------------------------------------------- @@ -345,20 +379,98 @@ final class DateTimeParseContext { * * @return a new builder with the results of the parse, not null */ - public DateTimeBuilder toBuilder() { - List cals = currentParsed().parsed; + DateTimeBuilder toBuilder() { + Parsed parsed = currentParsed(); DateTimeBuilder builder = new DateTimeBuilder(); - for (Object obj : cals) { - if (obj instanceof FieldValue) { - FieldValue fv = (FieldValue) obj; - builder.addFieldValue(fv.field, fv.value); - } else { - builder.addCalendrical(obj); - } + for (Map.Entry fv : parsed.fieldValues.entrySet()) { + builder.addFieldValue(fv.getKey(), fv.getValue()); + } + builder.addObject(getEffectiveChronology()); + if (parsed.zone != null) { + builder.addObject(parsed.zone); } return builder; } + /** + * Resolves the fields in this context. + * + * @return this, for method chaining + * @throws DateTimeException if resolving one field results in a value for + * another field that is in conflict + */ + DateTimeParseContext resolveFields() { + Parsed data = currentParsed(); + outer: + while (true) { + for (Map.Entry entry : data.fieldValues.entrySet()) { + TemporalField targetField = entry.getKey(); + Map changes = targetField.resolve(this, entry.getValue()); + if (changes != null) { + resolveMakeChanges(data, targetField, changes); + data.fieldValues.remove(targetField); // helps avoid infinite loops + continue outer; // have to restart to avoid concurrent modification + } + } + break; + } + return this; + } + + private void resolveMakeChanges(Parsed data, TemporalField targetField, Map changes) { + for (Map.Entry change : changes.entrySet()) { + TemporalField changeField = change.getKey(); + Long changeValue = change.getValue(); + Objects.requireNonNull(changeField, "changeField"); + if (changeValue != null) { + Long old = currentParsed().fieldValues.put(changeField, changeValue); + if (old != null && old.longValue() != changeValue.longValue()) { + throw new DateTimeException("Conflict found: " + changeField + " " + old + + " differs from " + changeField + " " + changeValue + + " while resolving " + targetField); + } + } else { + data.fieldValues.remove(changeField); + } + } + } + + //----------------------------------------------------------------------- + // TemporalAccessor methods + // should only to be used once parsing is complete + @Override + public boolean isSupported(TemporalField field) { + if (currentParsed().fieldValues.containsKey(field)) { + return true; + } + return (field instanceof ChronoField == false) && field.isSupportedBy(this); + } + + @Override + public long getLong(TemporalField field) { + Long value = currentParsed().fieldValues.get(field); + if (value != null) { + return value; + } + if (field instanceof ChronoField) { + throw new DateTimeException("Unsupported field: " + field.getName()); + } + return field.getFrom(this); + } + + @SuppressWarnings("unchecked") + @Override + public R query(TemporalQuery query) { + if (query == Queries.chronology()) { + return (R) currentParsed().chrono; + } else if (query == Queries.zoneId()) { + return (R) currentParsed().zone; + } else if (query == Queries.precision()) { + return null; + } + return query.queryFrom(this); + } + //----------------------------------------------------------------------- /** * Returns a string version of the context for debugging. @@ -375,34 +487,21 @@ final class DateTimeParseContext { * Temporary store of parsed data. */ private static final class Parsed { - final List parsed = new ArrayList<>(); + Chronology chrono = null; + ZoneId zone = null; + final Map fieldValues = new HashMap<>(); private Parsed() { } protected Parsed copy() { Parsed cloned = new Parsed(); - cloned.parsed.addAll(this.parsed); + cloned.chrono = this.chrono; + cloned.zone = this.zone; + cloned.fieldValues.putAll(this.fieldValues); return cloned; } @Override public String toString() { - return parsed.toString(); - } - } - - //----------------------------------------------------------------------- - /** - * Temporary store of a field-value pair. - */ - private static final class FieldValue { - final TemporalField field; - final long value; - private FieldValue(TemporalField field, long value) { - this.field = field; - this.value = value; - } - @Override - public String toString() { - return field.getName() + ' ' + value; + return fieldValues.toString() + "," + chrono + "," + zone; } } diff --git a/jdk/src/share/classes/java/time/format/DateTimePrintContext.java b/jdk/src/share/classes/java/time/format/DateTimePrintContext.java index 6314c0de7af..060d8dd8890 100644 --- a/jdk/src/share/classes/java/time/format/DateTimePrintContext.java +++ b/jdk/src/share/classes/java/time/format/DateTimePrintContext.java @@ -67,9 +67,9 @@ import static java.time.temporal.ChronoField.INSTANT_SECONDS; import java.time.DateTimeException; import java.time.Instant; import java.time.ZoneId; -import java.time.temporal.Chrono; +import java.time.chrono.Chronology; import java.time.temporal.ChronoField; -import java.time.temporal.ChronoLocalDate; +import java.time.chrono.ChronoLocalDate; import java.time.temporal.Queries; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalField; @@ -81,12 +81,12 @@ import java.util.Objects; /** * Context object used during date and time printing. *

      - * This class provides a single wrapper to items used in the print. + * This class provides a single wrapper to items used in the format. * *

      Specification for implementors

      * This class is a mutable context intended for use from a single thread. * Usage of the class is thread-safe within standard printing as the framework creates - * a new instance of the class for each print and printing is single-threaded. + * a new instance of the class for each format and printing is single-threaded. * * @since 1.8 */ @@ -109,7 +109,7 @@ final class DateTimePrintContext { * Creates a new instance of the context. * * @param temporal the temporal object being output, not null - * @param formatter the formatter controlling the print, not null + * @param formatter the formatter controlling the format, not null */ DateTimePrintContext(TemporalAccessor temporal, DateTimeFormatter formatter) { super(); @@ -119,14 +119,14 @@ final class DateTimePrintContext { private static TemporalAccessor adjust(final TemporalAccessor temporal, DateTimeFormatter formatter) { // normal case first - Chrono overrideChrono = formatter.getChrono(); + Chronology overrideChrono = formatter.getChronology(); ZoneId overrideZone = formatter.getZone(); if (overrideChrono == null && overrideZone == null) { return temporal; } // ensure minimal change - Chrono temporalChrono = Chrono.from(temporal); // default to ISO, handles Instant + Chronology temporalChrono = Chronology.from(temporal); // default to ISO, handles Instant ZoneId temporalZone = temporal.query(Queries.zone()); // zone then offset, handles OffsetDateTime if (temporal.isSupported(EPOCH_DAY) == false || Objects.equals(overrideChrono, temporalChrono)) { overrideChrono = null; @@ -144,8 +144,8 @@ final class DateTimePrintContext { } else if (overrideZone != null) { return temporalChrono.zonedDateTime(Instant.from(temporal), overrideZone); } else { // overrideChrono != null - // need class here to handle non-standard cases like OffsetDate - final ChronoLocalDate date = overrideChrono.date(temporal); + // need class here to handle non-standard cases + final ChronoLocalDate date = overrideChrono.date(temporal); return new TemporalAccessor() { @Override public boolean isSupported(TemporalField field) { @@ -160,7 +160,7 @@ final class DateTimePrintContext { return temporal.range(field); } } - return field.doRange(this); + return field.rangeRefinedBy(this); } @Override public long getLong(TemporalField field) { @@ -171,11 +171,15 @@ final class DateTimePrintContext { return temporal.getLong(field); } } - return field.doGet(this); + return field.getFrom(this); } + @SuppressWarnings("unchecked") @Override public R query(TemporalQuery query) { - if (query == Queries.zoneId() || query == Queries.chrono() || query == Queries.precision()) { + if (query == Queries.chronology()) { + return (R) date.getChronology(); + } + if (query == Queries.zoneId() || query == Queries.precision()) { return temporal.query(query); } return query.queryFrom(this); @@ -197,7 +201,7 @@ final class DateTimePrintContext { /** * Gets the locale. *

      - * This locale is used to control localization in the print output except + * This locale is used to control localization in the format output except * where localization is controlled by the symbols. * * @return the locale, not null diff --git a/jdk/src/share/classes/java/time/format/DateTimePrintException.java b/jdk/src/share/classes/java/time/format/DateTimePrintException.java deleted file mode 100644 index e03a3e51e8c..00000000000 --- a/jdk/src/share/classes/java/time/format/DateTimePrintException.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * 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 java.time.format; - -import java.io.IOException; -import java.time.DateTimeException; - -/** - * An exception thrown when an error occurs during printing. - *

      - * This will be triggered by violations specific to printing or an IO exception. - * - *

      Specification for implementors

      - * This class is intended for use in a single thread. - * - * @since 1.8 - */ -public class DateTimePrintException extends DateTimeException { - - /** - * Serialization version. - */ - private static final long serialVersionUID = 2263939197574006408L; - - /** - * Constructs a new exception with the specified message. - * - * @param message the message to use for this exception, may be null - */ - public DateTimePrintException(String message) { - super(message, null); - } - - /** - * Constructs a new 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 DateTimePrintException(String message, Throwable cause) { - super(message, cause); - } - - //----------------------------------------------------------------------- - /** - * Checks if the cause of this exception was an IOException, and if so - * re-throws it - *

      - * This method is useful if you call a printer with an open stream or - * writer and want to ensure that IOExceptions are not lost. - *

      -     * try {
      -     *   printer.print(writer, dateTime);
      -     * } catch (DateTimePrintException ex) {
      -     *   ex.rethrowIOException();
      -     *   // if code reaches here exception was caused by date-time issues
      -     * }
      -     * 
      - * Note that calling this method will re-throw the original IOException, - * causing this DateTimePrintException to be lost. - * - * @throws IOException if the cause of this exception is an IOException - */ - public void rethrowIOException() throws IOException { - if (getCause() instanceof IOException) { - throw (IOException) getCause(); - } - } - -} diff --git a/jdk/src/share/classes/java/time/format/DateTimeTextProvider.java b/jdk/src/share/classes/java/time/format/DateTimeTextProvider.java index 042b6136a5a..5127f0c80b5 100644 --- a/jdk/src/share/classes/java/time/format/DateTimeTextProvider.java +++ b/jdk/src/share/classes/java/time/format/DateTimeTextProvider.java @@ -63,12 +63,13 @@ package 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.ERA; import static java.time.temporal.ChronoField.MONTH_OF_YEAR; -import java.time.temporal.Chrono; -import java.time.temporal.ISOChrono; -import java.time.calendar.JapaneseChrono; -import java.time.calendar.ThaiBuddhistChrono; +import java.time.chrono.Chronology; +import java.time.chrono.IsoChronology; +import java.time.chrono.JapaneseChronology; +import java.time.temporal.ChronoField; import java.time.temporal.TemporalField; import java.util.AbstractMap.SimpleImmutableEntry; import java.util.ArrayList; @@ -83,9 +84,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import java.util.spi.CalendarNameProvider; -import sun.util.locale.provider.LocaleProviderAdapter; import sun.util.locale.provider.CalendarDataUtility; /** @@ -122,7 +121,7 @@ class DateTimeTextProvider { /** * Gets the text for the specified field, locale and style - * for the purpose of printing. + * for the purpose of formatting. *

      * The text associated with the value is returned. * The null return value should be used if there is no applicable text, or @@ -152,37 +151,57 @@ class DateTimeTextProvider { } /** - * Gets the era text for the specified chrono, value, style and locale - * for the purpose of printing. + * Gets the text for the specified chrono, field, locale and style + * for the purpose of formatting. *

      - * The era text associated with the value is returned. + * The text associated with the value is returned. * The null return value should be used if there is no applicable text, or * if the text would be a numeric representation of the value. * - * @param chrono the chrono to get text for, not null + * @param chrono the Chronology to get text for, not null + * @param field the field to get text for, not null * @param value the field value to get text for, not null * @param style the style to get text for, not null * @param locale the locale to get text for, not null - * @return the era text for the value, null if no text found + * @return the text for the field value, null if no text found */ - public String getEraText(Chrono chrono, long value, TextStyle style, Locale locale) { - String type = null; - if (chrono == ISOChrono.INSTANCE) { - type = "gregory"; - } else if (chrono == JapaneseChrono.INSTANCE) { - type = "japanese"; - if (value == -999) { - value = 0; + public String getText(Chronology chrono, TemporalField field, long value, + TextStyle style, Locale locale) { + if (chrono == IsoChronology.INSTANCE + || !(field instanceof ChronoField)) { + return getText(field, value, style, locale); + } + + int fieldIndex; + int fieldValue; + if (field == ERA) { + fieldIndex = Calendar.ERA; + if (chrono == JapaneseChronology.INSTANCE) { + if (value == -999) { + fieldValue = 0; + } else { + fieldValue = (int) value + 2; + } } else { - value += 2; + fieldValue = (int) value; } - } else if (chrono == ThaiBuddhistChrono.INSTANCE) { - type = "buddhist"; + } else if (field == MONTH_OF_YEAR) { + fieldIndex = Calendar.MONTH; + fieldValue = (int) value - 1; + } else if (field == DAY_OF_WEEK) { + fieldIndex = Calendar.DAY_OF_WEEK; + fieldValue = (int) value + 1; + if (fieldValue > 7) { + fieldValue = Calendar.SUNDAY; + } + } else if (field == AMPM_OF_DAY) { + fieldIndex = Calendar.AM_PM; + fieldValue = (int) value; } else { return null; } - return CalendarDataUtility.retrieveFieldValueName( - type, Calendar.ERA, (int)value, toStyle(style), locale); + return CalendarDataUtility.retrieveCldrFieldValueName( + chrono.getCalendarType(), fieldIndex, fieldValue, toStyle(style), locale); } /** @@ -209,6 +228,88 @@ class DateTimeTextProvider { return null; } + /** + * Gets an iterator of text to field for the specified chrono, field, locale and style + * for the purpose of parsing. + *

      + * The iterator must be returned in order from the longest text to the shortest. + *

      + * The null return value should be used if there is no applicable parsable text, or + * if the text would be a numeric representation of the value. + * Text can only be parsed if all the values for that field-style-locale combination are unique. + * + * @param chrono the Chronology to get text for, not null + * @param field the field to get text for, not null + * @param style the style to get text for, null for all parsable text + * @param locale the locale to get text for, not null + * @return the iterator of text to field pairs, in order from longest text to shortest text, + * null if the field or style is not parsable + */ + public Iterator> getTextIterator(Chronology chrono, TemporalField field, + TextStyle style, Locale locale) { + if (chrono == IsoChronology.INSTANCE + || !(field instanceof ChronoField)) { + return getTextIterator(field, style, locale); + } + + int fieldIndex; + switch ((ChronoField)field) { + case ERA: + fieldIndex = Calendar.ERA; + break; + case MONTH_OF_YEAR: + fieldIndex = Calendar.MONTH; + break; + case DAY_OF_WEEK: + fieldIndex = Calendar.DAY_OF_WEEK; + break; + case AMPM_OF_DAY: + fieldIndex = Calendar.AM_PM; + break; + default: + return null; + } + + Map map = CalendarDataUtility.retrieveCldrFieldValueNames( + chrono.getCalendarType(), fieldIndex, toStyle(style), locale); + if (map == null) { + return null; + } + + List> list = new ArrayList<>(map.size()); + switch (fieldIndex) { + case Calendar.ERA: + for (String key : map.keySet()) { + int era = map.get(key); + if (chrono == JapaneseChronology.INSTANCE) { + if (era == 0) { + era = -999; + } else { + era -= 2; + } + } + list.add(createEntry(key, (long) era)); + } + break; + case Calendar.MONTH: + for (String key : map.keySet()) { + list.add(createEntry(key, (long)(map.get(key) + 1))); + } + break; + case Calendar.DAY_OF_WEEK: + for (String key : map.keySet()) { + list.add(createEntry(key, (long)toWeekDay(map.get(key)))); + } + break; + default: + for (String key : map.keySet()) { + list.add(createEntry(key, (long)map.get(key))); + } + break; + } + return list.iterator(); + } + private Object findStore(TemporalField field, Locale locale) { Entry key = createEntry(field, locale); Object store = CACHE.get(key); @@ -229,67 +330,91 @@ class DateTimeTextProvider { } private Object createStore(TemporalField field, Locale locale) { - CalendarNameProvider provider = LocaleProviderAdapter.getAdapter(CalendarNameProvider.class, locale) - .getCalendarNameProvider(); Map> styleMap = new HashMap<>(); + if (field == ERA) { + for (TextStyle textStyle : TextStyle.values()) { + Map map = new HashMap<>(); + for (Entry entry : + CalendarDataUtility.retrieveCldrFieldValueNames( + "gregory", Calendar.ERA, toStyle(textStyle), locale).entrySet()) { + map.put((long) entry.getValue(), entry.getKey()); + } + if (!map.isEmpty()) { + styleMap.put(textStyle, map); + } + } + return new LocaleStore(styleMap); + } + if (field == MONTH_OF_YEAR) { Map map = new HashMap<>(); for (Entry entry : - provider.getDisplayNames("gregory", Calendar.MONTH, Calendar.LONG_FORMAT, locale).entrySet()) { - map.put((long)(entry.getValue() + 1), entry.getKey()); + CalendarDataUtility.retrieveCldrFieldValueNames( + "gregory", Calendar.MONTH, Calendar.LONG_FORMAT, locale).entrySet()) { + map.put((long) (entry.getValue() + 1), entry.getKey()); } styleMap.put(TextStyle.FULL, map); map = new HashMap<>(); for (Entry entry : - provider.getDisplayNames("gregory", Calendar.MONTH, Calendar.SHORT_FORMAT, locale).entrySet()) { - map.put((long)(entry.getValue() + 1), entry.getKey()); + CalendarDataUtility.retrieveCldrFieldValueNames( + "gregory", Calendar.MONTH, Calendar.SHORT_FORMAT, locale).entrySet()) { + map.put((long) (entry.getValue() + 1), entry.getKey()); } styleMap.put(TextStyle.SHORT, map); map = new HashMap<>(); for (int month = Calendar.JANUARY; month <= Calendar.DECEMBER; month++) { - String name = provider.getDisplayName("gregory", Calendar.MONTH, month, Calendar.NARROW_STANDALONE, locale); + String name; + name = CalendarDataUtility.retrieveCldrFieldValueName( + "gregory", Calendar.MONTH, month, Calendar.NARROW_STANDALONE, locale); if (name != null) { map.put((long)(month + 1), name); } } - if (map.size() != 0) { + if (!map.isEmpty()) { styleMap.put(TextStyle.NARROW, map); } return new LocaleStore(styleMap); } + if (field == DAY_OF_WEEK) { Map map = new HashMap<>(); for (Entry entry : - provider.getDisplayNames("gregory", Calendar.DAY_OF_WEEK, Calendar.LONG_FORMAT, locale).entrySet()) { + CalendarDataUtility.retrieveCldrFieldValueNames( + "gregory", Calendar.DAY_OF_WEEK, Calendar.LONG_FORMAT, locale).entrySet()) { map.put((long)toWeekDay(entry.getValue()), entry.getKey()); } styleMap.put(TextStyle.FULL, map); map = new HashMap<>(); for (Entry entry : - provider.getDisplayNames("gregory", Calendar.DAY_OF_WEEK, Calendar.SHORT_FORMAT, locale).entrySet()) { - map.put((long)toWeekDay(entry.getValue()), entry.getKey()); + CalendarDataUtility.retrieveCldrFieldValueNames( + "gregory", Calendar.DAY_OF_WEEK, Calendar.SHORT_FORMAT, locale).entrySet()) { + map.put((long) toWeekDay(entry.getValue()), entry.getKey()); } styleMap.put(TextStyle.SHORT, map); map = new HashMap<>(); for (int wday = Calendar.SUNDAY; wday <= Calendar.SATURDAY; wday++) { - map.put((long)toWeekDay(wday), - provider.getDisplayName("gregory", Calendar.DAY_OF_WEEK, wday, Calendar.NARROW_FORMAT, locale)); + map.put((long) toWeekDay(wday), + CalendarDataUtility.retrieveCldrFieldValueName( + "gregory", Calendar.DAY_OF_WEEK, wday, Calendar.NARROW_FORMAT, locale)); } styleMap.put(TextStyle.NARROW, map); return new LocaleStore(styleMap); } + if (field == AMPM_OF_DAY) { Map map = new HashMap<>(); for (Entry entry : - provider.getDisplayNames("gregory", Calendar.AM_PM, Calendar.LONG_FORMAT, locale).entrySet()) { - map.put((long)entry.getValue(), entry.getKey()); + CalendarDataUtility.retrieveCldrFieldValueNames( + "gregory", Calendar.AM_PM, Calendar.LONG_FORMAT, locale).entrySet()) { + map.put((long) entry.getValue(), entry.getKey()); } styleMap.put(TextStyle.FULL, map); styleMap.put(TextStyle.SHORT, map); // re-use, as we don't have different data return new LocaleStore(styleMap); } + return ""; // null marker for map } diff --git a/jdk/src/share/classes/java/time/format/FormatStyle.java b/jdk/src/share/classes/java/time/format/FormatStyle.java index 58cebe48cbb..0be538e28dd 100644 --- a/jdk/src/share/classes/java/time/format/FormatStyle.java +++ b/jdk/src/share/classes/java/time/format/FormatStyle.java @@ -65,7 +65,7 @@ package java.time.format; * Enumeration of the style of a localized date, time or date-time formatter. *

      * These styles are used when obtaining a date-time style from configuration. - * See {@link DateTimeFormatters} and {@link DateTimeFormatterBuilder} for usage. + * See {@link DateTimeFormatter} and {@link DateTimeFormatterBuilder} for usage. * *

      Specification for implementors

      * This is an immutable and thread-safe enum. diff --git a/jdk/src/share/classes/java/time/format/ZoneName.java b/jdk/src/share/classes/java/time/format/ZoneName.java new file mode 100644 index 00000000000..f1f6170c920 --- /dev/null +++ b/jdk/src/share/classes/java/time/format/ZoneName.java @@ -0,0 +1,800 @@ +/* + * 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.time.format; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +/** + * A helper class to map a zone name to metazone and back to the + * appropriate zone id for the particular locale. + *

      + * The zid<->metazone mappings are based on CLDR metaZones.xml. + * The alias mappings are based on Link entries in tzdb data files. + */ +class ZoneName { + + public static String toZid(String zid, Locale locale) { + String mzone = zidToMzone.get(zid); + if (mzone == null && aliases.containsKey(zid)) { + zid = aliases.get(zid); + mzone = zidToMzone.get(zid); + } + if (mzone != null) { + Map map = mzoneToZidL.get(mzone); + if (map != null && map.containsKey(locale.getCountry())) { + zid = map.get(locale.getCountry()); + } else { + zid = mzoneToZid.get(mzone); + } + } + return toZid(zid); + } + + public static String toZid(String zid) { + if (aliases.containsKey(zid)) { + return aliases.get(zid); + } + return zid; + } + + private static final String[] zidMap = new String[] { + "Pacific/Rarotonga", "Cook", "Pacific/Rarotonga", + "Europe/Tirane", "Europe_Central", "Europe/Paris", + "America/Recife", "Brasilia", "America/Sao_Paulo", + "America/Argentina/San_Juan", "Argentina", "America/Buenos_Aires", + "Asia/Kolkata", "India", "Asia/Calcutta", + "America/Guayaquil", "Ecuador", "America/Guayaquil", + "Europe/Samara", "Moscow", "Europe/Moscow", + "Indian/Antananarivo", "Africa_Eastern", "Africa/Nairobi", + "America/Santa_Isabel", "America_Pacific", "America/Los_Angeles", + "America/Montserrat", "Atlantic", "America/Halifax", + "Pacific/Port_Moresby", "Papua_New_Guinea", "Pacific/Port_Moresby", + "Europe/Paris", "Europe_Central", "Europe/Paris", + "America/Argentina/Salta", "Argentina", "America/Buenos_Aires", + "Asia/Omsk", "Omsk", "Asia/Omsk", + "Africa/Ceuta", "Europe_Central", "Europe/Paris", + "America/Argentina/San_Luis", "Argentina_Western", "America/Argentina/San_Luis", + "America/Atikokan", "America_Eastern", "America/New_York", + "Asia/Vladivostok", "Vladivostok", "Asia/Vladivostok", + "America/Argentina/Jujuy", "Argentina", "America/Buenos_Aires", + "Asia/Almaty", "Kazakhstan_Eastern", "Asia/Almaty", + "Atlantic/Canary", "Europe_Western", "Atlantic/Canary", + "Asia/Bangkok", "Indochina", "Asia/Saigon", + "America/Caracas", "Venezuela", "America/Caracas", + "Australia/Hobart", "Australia_Eastern", "Australia/Sydney", + "America/Havana", "Cuba", "America/Havana", + "Africa/Malabo", "Africa_Western", "Africa/Lagos", + "Australia/Lord_Howe", "Lord_Howe", "Australia/Lord_Howe", + "Pacific/Fakaofo", "Tokelau", "Pacific/Fakaofo", + "America/Matamoros", "America_Central", "America/Chicago", + "America/Guadeloupe", "Atlantic", "America/Halifax", + "Europe/Helsinki", "Europe_Eastern", "Europe/Bucharest", + "Asia/Calcutta", "India", "Asia/Calcutta", + "Africa/Kinshasa", "Africa_Western", "Africa/Lagos", + "America/Miquelon", "Pierre_Miquelon", "America/Miquelon", + "Europe/Athens", "Europe_Eastern", "Europe/Bucharest", + "Asia/Novosibirsk", "Novosibirsk", "Asia/Novosibirsk", + "Indian/Cocos", "Cocos", "Indian/Cocos", + "Africa/Bujumbura", "Africa_Central", "Africa/Maputo", + "Europe/Mariehamn", "Europe_Eastern", "Europe/Bucharest", + "America/Winnipeg", "America_Central", "America/Chicago", + "America/Buenos_Aires", "Argentina", "America/Buenos_Aires", + "America/Yellowknife", "America_Mountain", "America/Denver", + "Pacific/Midway", "Samoa", "Pacific/Apia", + "Africa/Dar_es_Salaam", "Africa_Eastern", "Africa/Nairobi", + "Pacific/Tahiti", "Tahiti", "Pacific/Tahiti", + "Asia/Gaza", "Europe_Eastern", "Europe/Bucharest", + "Australia/Lindeman", "Australia_Eastern", "Australia/Sydney", + "Europe/Kaliningrad", "Europe_Eastern", "Europe/Bucharest", + "Europe/Bucharest", "Europe_Eastern", "Europe/Bucharest", + "America/Lower_Princes", "Atlantic", "America/Halifax", + "Pacific/Chuuk", "Truk", "Pacific/Truk", + "America/Anchorage", "Alaska", "America/Juneau", + "America/Rankin_Inlet", "America_Central", "America/Chicago", + "America/Marigot", "Atlantic", "America/Halifax", + "Africa/Juba", "Africa_Eastern", "Africa/Nairobi", + "Africa/Algiers", "Europe_Central", "Europe/Paris", + "Europe/Kiev", "Europe_Eastern", "Europe/Bucharest", + "America/Santarem", "Brasilia", "America/Sao_Paulo", + "Africa/Brazzaville", "Africa_Western", "Africa/Lagos", + "Asia/Choibalsan", "Choibalsan", "Asia/Choibalsan", + "Indian/Christmas", "Christmas", "Indian/Christmas", + "America/Nassau", "America_Eastern", "America/New_York", + "Africa/Tunis", "Europe_Central", "Europe/Paris", + "Pacific/Noumea", "New_Caledonia", "Pacific/Noumea", + "Africa/El_Aaiun", "Europe_Western", "Atlantic/Canary", + "Europe/Sarajevo", "Europe_Central", "Europe/Paris", + "America/Campo_Grande", "Amazon", "America/Manaus", + "America/Puerto_Rico", "Atlantic", "America/Halifax", + "Antarctica/Mawson", "Mawson", "Antarctica/Mawson", + "Pacific/Galapagos", "Galapagos", "Pacific/Galapagos", + "Asia/Tehran", "Iran", "Asia/Tehran", + "America/Port-au-Prince", "America_Eastern", "America/New_York", + "America/Scoresbysund", "Greenland_Eastern", "America/Scoresbysund", + "Africa/Harare", "Africa_Central", "Africa/Maputo", + "America/Dominica", "Atlantic", "America/Halifax", + "Europe/Chisinau", "Europe_Eastern", "Europe/Bucharest", + "America/Chihuahua", "America_Mountain", "America/Denver", + "America/La_Paz", "Bolivia", "America/La_Paz", + "Indian/Chagos", "Indian_Ocean", "Indian/Chagos", + "Australia/Broken_Hill", "Australia_Central", "Australia/Adelaide", + "America/Grenada", "Atlantic", "America/Halifax", + "America/North_Dakota/New_Salem", "America_Central", "America/Chicago", + "Pacific/Majuro", "Marshall_Islands", "Pacific/Majuro", + "Australia/Adelaide", "Australia_Central", "Australia/Adelaide", + "Europe/Warsaw", "Europe_Central", "Europe/Paris", + "Europe/Vienna", "Europe_Central", "Europe/Paris", + "Atlantic/Cape_Verde", "Cape_Verde", "Atlantic/Cape_Verde", + "America/Mendoza", "Argentina", "America/Buenos_Aires", + "Pacific/Gambier", "Gambier", "Pacific/Gambier", + "Europe/Istanbul", "Europe_Eastern", "Europe/Bucharest", + "America/Kentucky/Monticello", "America_Eastern", "America/New_York", + "America/Chicago", "America_Central", "America/Chicago", + "Asia/Ulaanbaatar", "Mongolia", "Asia/Ulaanbaatar", + "Indian/Maldives", "Maldives", "Indian/Maldives", + "America/Mexico_City", "America_Central", "America/Chicago", + "Africa/Asmara", "Africa_Eastern", "Africa/Nairobi", + "Asia/Chongqing", "China", "Asia/Shanghai", + "America/Argentina/La_Rioja", "Argentina", "America/Buenos_Aires", + "America/Tijuana", "America_Pacific", "America/Los_Angeles", + "Asia/Harbin", "China", "Asia/Shanghai", + "Pacific/Honolulu", "Hawaii_Aleutian", "Pacific/Honolulu", + "Atlantic/Azores", "Azores", "Atlantic/Azores", + "Indian/Mayotte", "Africa_Eastern", "Africa/Nairobi", + "America/Guatemala", "America_Central", "America/Chicago", + "America/Indianapolis", "America_Eastern", "America/New_York", + "America/Halifax", "Atlantic", "America/Halifax", + "America/Resolute", "America_Central", "America/Chicago", + "Europe/London", "GMT", "Atlantic/Reykjavik", + "America/Hermosillo", "America_Mountain", "America/Denver", + "Atlantic/Madeira", "Europe_Western", "Atlantic/Canary", + "Europe/Zagreb", "Europe_Central", "Europe/Paris", + "America/Boa_Vista", "Amazon", "America/Manaus", + "America/Regina", "America_Central", "America/Chicago", + "America/Cordoba", "Argentina", "America/Buenos_Aires", + "America/Shiprock", "America_Mountain", "America/Denver", + "Europe/Luxembourg", "Europe_Central", "Europe/Paris", + "America/Cancun", "America_Central", "America/Chicago", + "Pacific/Enderbury", "Phoenix_Islands", "Pacific/Enderbury", + "Africa/Bissau", "GMT", "Atlantic/Reykjavik", + "Antarctica/Vostok", "Vostok", "Antarctica/Vostok", + "Pacific/Apia", "Samoa", "Pacific/Apia", + "Australia/Perth", "Australia_Western", "Australia/Perth", + "America/Juneau", "Alaska", "America/Juneau", + "Africa/Mbabane", "Africa_Southern", "Africa/Johannesburg", + "Pacific/Niue", "Niue", "Pacific/Niue", + "Europe/Zurich", "Europe_Central", "Europe/Paris", + "America/Rio_Branco", "Amazon", "America/Manaus", + "Africa/Ndjamena", "Africa_Western", "Africa/Lagos", + "Asia/Macau", "China", "Asia/Shanghai", + "America/Lima", "Peru", "America/Lima", + "Africa/Windhoek", "Africa_Western", "Africa/Lagos", + "America/Sitka", "Alaska", "America/Juneau", + "America/Mazatlan", "America_Mountain", "America/Denver", + "Asia/Saigon", "Indochina", "Asia/Saigon", + "Asia/Kamchatka", "Magadan", "Asia/Magadan", + "America/Menominee", "America_Central", "America/Chicago", + "America/Belize", "America_Central", "America/Chicago", + "America/Sao_Paulo", "Brasilia", "America/Sao_Paulo", + "America/Barbados", "Atlantic", "America/Halifax", + "America/Porto_Velho", "Amazon", "America/Manaus", + "America/Costa_Rica", "America_Central", "America/Chicago", + "Europe/Monaco", "Europe_Central", "Europe/Paris", + "Europe/Riga", "Europe_Eastern", "Europe/Bucharest", + "Europe/Vatican", "Europe_Central", "Europe/Paris", + "Europe/Madrid", "Europe_Central", "Europe/Paris", + "Africa/Dakar", "GMT", "Atlantic/Reykjavik", + "Asia/Damascus", "Europe_Eastern", "Europe/Bucharest", + "Asia/Hong_Kong", "Hong_Kong", "Asia/Hong_Kong", + "America/Adak", "Hawaii_Aleutian", "Pacific/Honolulu", + "Europe/Vilnius", "Europe_Eastern", "Europe/Bucharest", + "America/Indiana/Indianapolis", "America_Eastern", "America/New_York", + "Africa/Freetown", "GMT", "Atlantic/Reykjavik", + "Atlantic/Reykjavik", "GMT", "Atlantic/Reykjavik", + "Asia/Ho_Chi_Minh", "Indochina", "Asia/Saigon", + "America/St_Kitts", "Atlantic", "America/Halifax", + "America/Martinique", "Atlantic", "America/Halifax", + "America/Thule", "Atlantic", "America/Halifax", + "America/Asuncion", "Paraguay", "America/Asuncion", + "Africa/Luanda", "Africa_Western", "Africa/Lagos", + "America/Monterrey", "America_Central", "America/Chicago", + "Pacific/Fiji", "Fiji", "Pacific/Fiji", + "Africa/Banjul", "GMT", "Atlantic/Reykjavik", + "America/Grand_Turk", "America_Eastern", "America/New_York", + "Pacific/Pitcairn", "Pitcairn", "Pacific/Pitcairn", + "America/Montevideo", "Uruguay", "America/Montevideo", + "America/Bahia_Banderas", "America_Central", "America/Chicago", + "America/Cayman", "America_Eastern", "America/New_York", + "Pacific/Norfolk", "Norfolk", "Pacific/Norfolk", + "Africa/Ouagadougou", "GMT", "Atlantic/Reykjavik", + "America/Maceio", "Brasilia", "America/Sao_Paulo", + "Pacific/Guam", "Chamorro", "Pacific/Saipan", + "Africa/Monrovia", "GMT", "Atlantic/Reykjavik", + "Africa/Bamako", "GMT", "Atlantic/Reykjavik", + "Asia/Colombo", "India", "Asia/Calcutta", + "Asia/Urumqi", "China", "Asia/Shanghai", + "Asia/Kabul", "Afghanistan", "Asia/Kabul", + "America/Yakutat", "Alaska", "America/Juneau", + "America/Phoenix", "America_Mountain", "America/Denver", + "Asia/Nicosia", "Europe_Eastern", "Europe/Bucharest", + "Asia/Phnom_Penh", "Indochina", "Asia/Saigon", + "America/Rainy_River", "America_Central", "America/Chicago", + "Europe/Uzhgorod", "Europe_Eastern", "Europe/Bucharest", + "Pacific/Saipan", "Chamorro", "Pacific/Saipan", + "America/St_Vincent", "Atlantic", "America/Halifax", + "Europe/Rome", "Europe_Central", "Europe/Paris", + "America/Nome", "Alaska", "America/Juneau", + "Africa/Mogadishu", "Africa_Eastern", "Africa/Nairobi", + "Europe/Zaporozhye", "Europe_Eastern", "Europe/Bucharest", + "Pacific/Funafuti", "Tuvalu", "Pacific/Funafuti", + "Atlantic/South_Georgia", "South_Georgia", "Atlantic/South_Georgia", + "Europe/Skopje", "Europe_Central", "Europe/Paris", + "Asia/Yekaterinburg", "Yekaterinburg", "Asia/Yekaterinburg", + "Australia/Melbourne", "Australia_Eastern", "Australia/Sydney", + "America/Argentina/Cordoba", "Argentina", "America/Buenos_Aires", + "Africa/Kigali", "Africa_Central", "Africa/Maputo", + "Africa/Blantyre", "Africa_Central", "Africa/Maputo", + "Africa/Tripoli", "Europe_Eastern", "Europe/Bucharest", + "Africa/Gaborone", "Africa_Central", "Africa/Maputo", + "Asia/Kuching", "Malaysia", "Asia/Kuching", + "Pacific/Nauru", "Nauru", "Pacific/Nauru", + "America/Aruba", "Atlantic", "America/Halifax", + "America/Antigua", "Atlantic", "America/Halifax", + "Europe/Volgograd", "Volgograd", "Europe/Volgograd", + "Africa/Djibouti", "Africa_Eastern", "Africa/Nairobi", + "America/Catamarca", "Argentina", "America/Buenos_Aires", + "Asia/Manila", "Philippines", "Asia/Manila", + "Pacific/Kiritimati", "Line_Islands", "Pacific/Kiritimati", + "Asia/Shanghai", "China", "Asia/Shanghai", + "Pacific/Truk", "Truk", "Pacific/Truk", + "Pacific/Tarawa", "Gilbert_Islands", "Pacific/Tarawa", + "Africa/Conakry", "GMT", "Atlantic/Reykjavik", + "Asia/Bishkek", "Kyrgystan", "Asia/Bishkek", + "Europe/Gibraltar", "Europe_Central", "Europe/Paris", + "Asia/Rangoon", "Myanmar", "Asia/Rangoon", + "Asia/Baku", "Azerbaijan", "Asia/Baku", + "America/Santiago", "Chile", "America/Santiago", + "America/El_Salvador", "America_Central", "America/Chicago", + "America/Noronha", "Noronha", "America/Noronha", + "America/St_Thomas", "Atlantic", "America/Halifax", + "Atlantic/St_Helena", "GMT", "Atlantic/Reykjavik", + "Asia/Krasnoyarsk", "Krasnoyarsk", "Asia/Krasnoyarsk", + "America/Vancouver", "America_Pacific", "America/Los_Angeles", + "Europe/Belgrade", "Europe_Central", "Europe/Paris", + "America/St_Barthelemy", "Atlantic", "America/Halifax", + "Asia/Pontianak", "Indonesia_Western", "Asia/Jakarta", + "Africa/Lusaka", "Africa_Central", "Africa/Maputo", + "America/Godthab", "Greenland_Western", "America/Godthab", + "Asia/Dhaka", "Bangladesh", "Asia/Dhaka", + "Asia/Dubai", "Gulf", "Asia/Dubai", + "Europe/Moscow", "Moscow", "Europe/Moscow", + "America/Louisville", "America_Eastern", "America/New_York", + "Australia/Darwin", "Australia_Central", "Australia/Adelaide", + "America/Santo_Domingo", "Atlantic", "America/Halifax", + "America/Argentina/Ushuaia", "Argentina", "America/Buenos_Aires", + "America/Tegucigalpa", "America_Central", "America/Chicago", + "Asia/Aden", "Arabian", "Asia/Riyadh", + "America/Inuvik", "America_Mountain", "America/Denver", + "Asia/Beirut", "Europe_Eastern", "Europe/Bucharest", + "Asia/Qatar", "Arabian", "Asia/Riyadh", + "Europe/Oslo", "Europe_Central", "Europe/Paris", + "Asia/Anadyr", "Magadan", "Asia/Magadan", + "Pacific/Palau", "Palau", "Pacific/Palau", + "Arctic/Longyearbyen", "Europe_Central", "Europe/Paris", + "America/Anguilla", "Atlantic", "America/Halifax", + "Asia/Aqtau", "Kazakhstan_Western", "Asia/Aqtobe", + "Asia/Yerevan", "Armenia", "Asia/Yerevan", + "Africa/Lagos", "Africa_Western", "Africa/Lagos", + "America/Denver", "America_Mountain", "America/Denver", + "Antarctica/Palmer", "Chile", "America/Santiago", + "Europe/Stockholm", "Europe_Central", "Europe/Paris", + "America/Bahia", "Brasilia", "America/Sao_Paulo", + "America/Danmarkshavn", "GMT", "Atlantic/Reykjavik", + "Indian/Mauritius", "Mauritius", "Indian/Mauritius", + "Pacific/Chatham", "Chatham", "Pacific/Chatham", + "Europe/Prague", "Europe_Central", "Europe/Paris", + "America/Blanc-Sablon", "Atlantic", "America/Halifax", + "America/Bogota", "Colombia", "America/Bogota", + "America/Managua", "America_Central", "America/Chicago", + "Pacific/Auckland", "New_Zealand", "Pacific/Auckland", + "Atlantic/Faroe", "Europe_Western", "Atlantic/Canary", + "America/Cambridge_Bay", "America_Mountain", "America/Denver", + "America/Los_Angeles", "America_Pacific", "America/Los_Angeles", + "Africa/Khartoum", "Africa_Eastern", "Africa/Nairobi", + "Europe/Simferopol", "Europe_Eastern", "Europe/Bucharest", + "Australia/Currie", "Australia_Eastern", "Australia/Sydney", + "Europe/Guernsey", "GMT", "Atlantic/Reykjavik", + "Asia/Thimphu", "Bhutan", "Asia/Thimphu", + "America/Eirunepe", "Amazon", "America/Manaus", + "Africa/Nairobi", "Africa_Eastern", "Africa/Nairobi", + "Asia/Yakutsk", "Yakutsk", "Asia/Yakutsk", + "America/Goose_Bay", "Atlantic", "America/Halifax", + "Africa/Maseru", "Africa_Southern", "Africa/Johannesburg", + "America/Swift_Current", "America_Central", "America/Chicago", + "America/Guyana", "Guyana", "America/Guyana", + "Asia/Tokyo", "Japan", "Asia/Tokyo", + "Indian/Kerguelen", "French_Southern", "Indian/Kerguelen", + "America/Belem", "Brasilia", "America/Sao_Paulo", + "Pacific/Wallis", "Wallis", "Pacific/Wallis", + "America/Whitehorse", "America_Pacific", "America/Los_Angeles", + "America/North_Dakota/Beulah", "America_Central", "America/Chicago", + "Asia/Jerusalem", "Israel", "Asia/Jerusalem", + "Antarctica/Syowa", "Syowa", "Antarctica/Syowa", + "America/Thunder_Bay", "America_Eastern", "America/New_York", + "Asia/Brunei", "Brunei", "Asia/Brunei", + "America/Metlakatla", "America_Pacific", "America/Los_Angeles", + "Asia/Dushanbe", "Tajikistan", "Asia/Dushanbe", + "Pacific/Kosrae", "Kosrae", "Pacific/Kosrae", + "America/Coral_Harbour", "America_Eastern", "America/New_York", + "America/Tortola", "Atlantic", "America/Halifax", + "Asia/Karachi", "Pakistan", "Asia/Karachi", + "Indian/Reunion", "Reunion", "Indian/Reunion", + "America/Detroit", "America_Eastern", "America/New_York", + "Australia/Eucla", "Australia_CentralWestern", "Australia/Eucla", + "Asia/Seoul", "Korea", "Asia/Seoul", + "Asia/Singapore", "Singapore", "Asia/Singapore", + "Africa/Casablanca", "Europe_Western", "Atlantic/Canary", + "Asia/Dili", "East_Timor", "Asia/Dili", + "America/Indiana/Vincennes", "America_Eastern", "America/New_York", + "Europe/Dublin", "GMT", "Atlantic/Reykjavik", + "America/St_Johns", "Newfoundland", "America/St_Johns", + "Antarctica/Macquarie", "Macquarie", "Antarctica/Macquarie", + "America/Port_of_Spain", "Atlantic", "America/Halifax", + "Europe/Budapest", "Europe_Central", "Europe/Paris", + "America/Fortaleza", "Brasilia", "America/Sao_Paulo", + "Australia/Brisbane", "Australia_Eastern", "Australia/Sydney", + "Atlantic/Bermuda", "Atlantic", "America/Halifax", + "Asia/Amman", "Europe_Eastern", "Europe/Bucharest", + "Asia/Tashkent", "Uzbekistan", "Asia/Tashkent", + "Antarctica/DumontDUrville", "DumontDUrville", "Antarctica/DumontDUrville", + "Antarctica/Casey", "Australia_Western", "Australia/Perth", + "Asia/Vientiane", "Indochina", "Asia/Saigon", + "Pacific/Johnston", "Hawaii_Aleutian", "Pacific/Honolulu", + "America/Jamaica", "America_Eastern", "America/New_York", + "Africa/Addis_Ababa", "Africa_Eastern", "Africa/Nairobi", + "Pacific/Ponape", "Ponape", "Pacific/Ponape", + "Europe/Jersey", "GMT", "Atlantic/Reykjavik", + "Africa/Lome", "GMT", "Atlantic/Reykjavik", + "America/Manaus", "Amazon", "America/Manaus", + "Africa/Niamey", "Africa_Western", "Africa/Lagos", + "Asia/Kashgar", "China", "Asia/Shanghai", + "Pacific/Tongatapu", "Tonga", "Pacific/Tongatapu", + "Europe/Minsk", "Europe_Eastern", "Europe/Bucharest", + "America/Edmonton", "America_Mountain", "America/Denver", + "Asia/Baghdad", "Arabian", "Asia/Riyadh", + "Asia/Kathmandu", "Nepal", "Asia/Katmandu", + "America/Ojinaga", "America_Mountain", "America/Denver", + "Africa/Abidjan", "GMT", "Atlantic/Reykjavik", + "America/Indiana/Winamac", "America_Eastern", "America/New_York", + "Asia/Qyzylorda", "Kazakhstan_Eastern", "Asia/Almaty", + "Australia/Sydney", "Australia_Eastern", "Australia/Sydney", + "Asia/Ashgabat", "Turkmenistan", "Asia/Ashgabat", + "Europe/Amsterdam", "Europe_Central", "Europe/Paris", + "America/Dawson_Creek", "America_Mountain", "America/Denver", + "Africa/Cairo", "Europe_Eastern", "Europe/Bucharest", + "Asia/Pyongyang", "Korea", "Asia/Seoul", + "Africa/Kampala", "Africa_Eastern", "Africa/Nairobi", + "America/Araguaina", "Brasilia", "America/Sao_Paulo", + "Asia/Novokuznetsk", "Novosibirsk", "Asia/Novosibirsk", + "Pacific/Kwajalein", "Marshall_Islands", "Pacific/Majuro", + "Africa/Lubumbashi", "Africa_Central", "Africa/Maputo", + "Asia/Sakhalin", "Sakhalin", "Asia/Sakhalin", + "America/Indiana/Vevay", "America_Eastern", "America/New_York", + "Africa/Maputo", "Africa_Central", "Africa/Maputo", + "Atlantic/Faeroe", "Europe_Western", "Atlantic/Canary", + "America/North_Dakota/Center", "America_Central", "America/Chicago", + "Pacific/Wake", "Wake", "Pacific/Wake", + "Pacific/Pago_Pago", "Samoa", "Pacific/Apia", + "America/Moncton", "Atlantic", "America/Halifax", + "Africa/Sao_Tome", "GMT", "Atlantic/Reykjavik", + "America/Glace_Bay", "Atlantic", "America/Halifax", + "Asia/Jakarta", "Indonesia_Western", "Asia/Jakarta", + "Africa/Asmera", "Africa_Eastern", "Africa/Nairobi", + "Europe/Lisbon", "Europe_Western", "Atlantic/Canary", + "America/Dawson", "America_Pacific", "America/Los_Angeles", + "America/Cayenne", "French_Guiana", "America/Cayenne", + "Asia/Bahrain", "Arabian", "Asia/Riyadh", + "Europe/Malta", "Europe_Central", "Europe/Paris", + "America/Indiana/Tell_City", "America_Central", "America/Chicago", + "America/Indiana/Petersburg", "America_Eastern", "America/New_York", + "Antarctica/Rothera", "Rothera", "Antarctica/Rothera", + "Asia/Aqtobe", "Kazakhstan_Western", "Asia/Aqtobe", + "Europe/Vaduz", "Europe_Central", "Europe/Paris", + "America/Indiana/Marengo", "America_Eastern", "America/New_York", + "Europe/Brussels", "Europe_Central", "Europe/Paris", + "Europe/Andorra", "Europe_Central", "Europe/Paris", + "America/Indiana/Knox", "America_Central", "America/Chicago", + "Pacific/Easter", "Easter", "Pacific/Easter", + "America/Argentina/Rio_Gallegos", "Argentina", "America/Buenos_Aires", + "Asia/Oral", "Kazakhstan_Western", "Asia/Aqtobe", + "Europe/Copenhagen", "Europe_Central", "Europe/Paris", + "Africa/Johannesburg", "Africa_Southern", "Africa/Johannesburg", + "Pacific/Pohnpei", "Ponape", "Pacific/Ponape", + "America/Argentina/Tucuman", "Argentina", "America/Buenos_Aires", + "America/Toronto", "America_Eastern", "America/New_York", + "Asia/Makassar", "Indonesia_Central", "Asia/Makassar", + "Europe/Berlin", "Europe_Central", "Europe/Paris", + "America/Argentina/Mendoza", "Argentina", "America/Buenos_Aires", + "America/Cuiaba", "Amazon", "America/Manaus", + "America/Creston", "America_Mountain", "America/Denver", + "Asia/Samarkand", "Uzbekistan", "Asia/Tashkent", + "Asia/Hovd", "Hovd", "Asia/Hovd", + "Europe/Bratislava", "Europe_Central", "Europe/Paris", + "Africa/Accra", "GMT", "Atlantic/Reykjavik", + "Africa/Douala", "Africa_Western", "Africa/Lagos", + "Africa/Nouakchott", "GMT", "Atlantic/Reykjavik", + "Europe/Sofia", "Europe_Eastern", "Europe/Bucharest", + "Antarctica/Davis", "Davis", "Antarctica/Davis", + "Antarctica/McMurdo", "New_Zealand", "Pacific/Auckland", + "Europe/San_Marino", "Europe_Central", "Europe/Paris", + "Africa/Porto-Novo", "Africa_Western", "Africa/Lagos", + "Asia/Jayapura", "Indonesia_Eastern", "Asia/Jayapura", + "America/St_Lucia", "Atlantic", "America/Halifax", + "America/Nipigon", "America_Eastern", "America/New_York", + "America/Argentina/Catamarca", "Argentina", "America/Buenos_Aires", + "Europe/Isle_of_Man", "GMT", "Atlantic/Reykjavik", + "America/Kentucky/Louisville", "America_Eastern", "America/New_York", + "America/Merida", "America_Central", "America/Chicago", + "Pacific/Marquesas", "Marquesas", "Pacific/Marquesas", + "Asia/Magadan", "Magadan", "Asia/Magadan", + "Africa/Libreville", "Africa_Western", "Africa/Lagos", + "Pacific/Efate", "Vanuatu", "Pacific/Efate", + "Asia/Kuala_Lumpur", "Malaysia", "Asia/Kuching", + "America/Iqaluit", "America_Eastern", "America/New_York", + "Indian/Comoro", "Africa_Eastern", "Africa/Nairobi", + "America/Panama", "America_Eastern", "America/New_York", + "Asia/Hebron", "Europe_Eastern", "Europe/Bucharest", + "America/Jujuy", "Argentina", "America/Buenos_Aires", + "America/Pangnirtung", "America_Eastern", "America/New_York", + "Asia/Tbilisi", "Georgia", "Asia/Tbilisi", + "Europe/Podgorica", "Europe_Central", "Europe/Paris", + "America/Boise", "America_Mountain", "America/Denver", + "Asia/Muscat", "Gulf", "Asia/Dubai", + "Indian/Mahe", "Seychelles", "Indian/Mahe", + "America/Montreal", "America_Eastern", "America/New_York", + "Africa/Bangui", "Africa_Western", "Africa/Lagos", + "America/Curacao", "Atlantic", "America/Halifax", + "Asia/Taipei", "Taipei", "Asia/Taipei", + "Europe/Ljubljana", "Europe_Central", "Europe/Paris", + "Atlantic/Stanley", "Falkland", "Atlantic/Stanley", + "Pacific/Guadalcanal", "Solomon", "Pacific/Guadalcanal", + "Asia/Kuwait", "Arabian", "Asia/Riyadh", + "Asia/Riyadh", "Arabian", "Asia/Riyadh", + "Europe/Tallinn", "Europe_Eastern", "Europe/Bucharest", + "America/New_York", "America_Eastern", "America/New_York", + "America/Paramaribo", "Suriname", "America/Paramaribo", + "America/Argentina/Buenos_Aires", "Argentina", "America/Buenos_Aires", + "Asia/Irkutsk", "Irkutsk", "Asia/Irkutsk", + "Asia/Katmandu", "Nepal", "Asia/Katmandu", + "America/Kralendijk", "Atlantic", "America/Halifax", + }; + private static final String[] mzoneMap = new String[] { + "GMT", "ST", "Africa/Sao_Tome", + "GMT", "ML", "Africa/Bamako", + "GMT", "IE", "Europe/Dublin", + "GMT", "SN", "Africa/Dakar", + "GMT", "GH", "Africa/Accra", + "GMT", "CI", "Africa/Abidjan", + "GMT", "BF", "Africa/Ouagadougou", + "GMT", "MR", "Africa/Nouakchott", + "GMT", "GM", "Africa/Banjul", + "GMT", "SL", "Africa/Freetown", + "GMT", "GN", "Africa/Conakry", + "GMT", "SH", "Atlantic/St_Helena", + "GMT", "GB", "Europe/London", + "GMT", "LR", "Africa/Monrovia", + "GMT", "TG", "Africa/Lome", + "Africa_Western", "CF", "Africa/Bangui", + "Africa_Western", "NE", "Africa/Niamey", + "Africa_Western", "CM", "Africa/Douala", + "Africa_Western", "CD", "Africa/Kinshasa", + "Africa_Western", "CG", "Africa/Brazzaville", + "Africa_Western", "GA", "Africa/Libreville", + "Africa_Western", "TD", "Africa/Ndjamena", + "Africa_Western", "AO", "Africa/Luanda", + "Africa_Western", "GQ", "Africa/Malabo", + "Africa_Eastern", "YT", "Indian/Mayotte", + "Africa_Eastern", "UG", "Africa/Kampala", + "Africa_Eastern", "ET", "Africa/Addis_Ababa", + "Africa_Eastern", "MG", "Indian/Antananarivo", + "Africa_Eastern", "TZ", "Africa/Dar_es_Salaam", + "Africa_Eastern", "SO", "Africa/Mogadishu", + "Africa_Eastern", "ER", "Africa/Asmera", + "Africa_Eastern", "KM", "Indian/Comoro", + "Africa_Eastern", "DJ", "Africa/Djibouti", + "Europe_Central", "GI", "Europe/Gibraltar", + "Europe_Central", "DK", "Europe/Copenhagen", + "Europe_Central", "SE", "Europe/Stockholm", + "Europe_Central", "CH", "Europe/Zurich", + "Europe_Central", "AL", "Europe/Tirane", + "Europe_Central", "RS", "Europe/Belgrade", + "Europe_Central", "HU", "Europe/Budapest", + "Europe_Central", "MT", "Europe/Malta", + "Europe_Central", "PL", "Europe/Warsaw", + "Europe_Central", "ME", "Europe/Podgorica", + "Europe_Central", "ES", "Europe/Madrid", + "Europe_Central", "CZ", "Europe/Prague", + "Europe_Central", "IT", "Europe/Rome", + "Europe_Central", "SI", "Europe/Ljubljana", + "Europe_Central", "LI", "Europe/Vaduz", + "Europe_Central", "AT", "Europe/Vienna", + "Europe_Central", "VA", "Europe/Vatican", + "Europe_Central", "DE", "Europe/Berlin", + "Europe_Central", "NO", "Europe/Oslo", + "Europe_Central", "SK", "Europe/Bratislava", + "Europe_Central", "AD", "Europe/Andorra", + "Europe_Central", "SM", "Europe/San_Marino", + "Europe_Central", "MK", "Europe/Skopje", + "Europe_Central", "TN", "Africa/Tunis", + "Europe_Central", "HR", "Europe/Zagreb", + "Europe_Central", "NL", "Europe/Amsterdam", + "Europe_Central", "BE", "Europe/Brussels", + "Europe_Central", "MC", "Europe/Monaco", + "Europe_Central", "LU", "Europe/Luxembourg", + "Europe_Central", "BA", "Europe/Sarajevo", + "China", "MO", "Asia/Macau", + "America_Pacific", "MX", "America/Tijuana", + "America_Pacific", "CA", "America/Vancouver", + "Indochina", "LA", "Asia/Vientiane", + "Indochina", "KH", "Asia/Phnom_Penh", + "Indochina", "TH", "Asia/Bangkok", + "Korea", "KP", "Asia/Pyongyang", + "America_Mountain", "MX", "America/Hermosillo", + "America_Mountain", "CA", "America/Edmonton", + "Africa_Southern", "LS", "Africa/Maseru", + "Africa_Southern", "SZ", "Africa/Mbabane", + "Chile", "AQ", "Antarctica/Palmer", + "New_Zealand", "AQ", "Antarctica/McMurdo", + "Gulf", "OM", "Asia/Muscat", + "Europe_Western", "FO", "Atlantic/Faeroe", + "America_Eastern", "TC", "America/Grand_Turk", + "America_Eastern", "CA", "America/Toronto", + "America_Eastern", "BS", "America/Nassau", + "America_Eastern", "PA", "America/Panama", + "America_Eastern", "JM", "America/Jamaica", + "America_Eastern", "KY", "America/Cayman", + "Africa_Central", "BI", "Africa/Bujumbura", + "Africa_Central", "ZM", "Africa/Lusaka", + "Africa_Central", "ZW", "Africa/Harare", + "Africa_Central", "CD", "Africa/Lubumbashi", + "Africa_Central", "BW", "Africa/Gaborone", + "Africa_Central", "RW", "Africa/Kigali", + "Africa_Central", "MW", "Africa/Blantyre", + "America_Central", "MX", "America/Mexico_City", + "America_Central", "HN", "America/Tegucigalpa", + "America_Central", "CA", "America/Winnipeg", + "America_Central", "GT", "America/Guatemala", + "America_Central", "SV", "America/El_Salvador", + "America_Central", "CR", "America/Costa_Rica", + "America_Central", "BZ", "America/Belize", + "Atlantic", "MS", "America/Montserrat", + "Atlantic", "AG", "America/Antigua", + "Atlantic", "TT", "America/Port_of_Spain", + "Atlantic", "MQ", "America/Martinique", + "Atlantic", "DM", "America/Dominica", + "Atlantic", "KN", "America/St_Kitts", + "Atlantic", "BM", "Atlantic/Bermuda", + "Atlantic", "PR", "America/Puerto_Rico", + "Atlantic", "AW", "America/Aruba", + "Atlantic", "VG", "America/Tortola", + "Atlantic", "GD", "America/Grenada", + "Atlantic", "GL", "America/Thule", + "Atlantic", "BB", "America/Barbados", + "Atlantic", "BQ", "America/Kralendijk", + "Atlantic", "SX", "America/Lower_Princes", + "Atlantic", "VI", "America/St_Thomas", + "Atlantic", "MF", "America/Marigot", + "Atlantic", "AI", "America/Anguilla", + "Atlantic", "AN", "America/Curacao", + "Atlantic", "LC", "America/St_Lucia", + "Atlantic", "GP", "America/Guadeloupe", + "Atlantic", "VC", "America/St_Vincent", + "Arabian", "QA", "Asia/Qatar", + "Arabian", "YE", "Asia/Aden", + "Arabian", "KW", "Asia/Kuwait", + "Arabian", "BH", "Asia/Bahrain", + "Arabian", "IQ", "Asia/Baghdad", + "India", "LK", "Asia/Colombo", + "Europe_Eastern", "SY", "Asia/Damascus", + "Europe_Eastern", "BG", "Europe/Sofia", + "Europe_Eastern", "GR", "Europe/Athens", + "Europe_Eastern", "JO", "Asia/Amman", + "Europe_Eastern", "CY", "Asia/Nicosia", + "Europe_Eastern", "AX", "Europe/Mariehamn", + "Europe_Eastern", "LB", "Asia/Beirut", + "Europe_Eastern", "FI", "Europe/Helsinki", + "Europe_Eastern", "EG", "Africa/Cairo", + "Chamorro", "GU", "Pacific/Guam", + }; + private static final String[] aliasMap = new String[] { + "Brazil/Acre", "America/Rio_Branco", + "US/Indiana-Starke", "America/Indiana/Knox", + "America/Atka", "America/Adak", + "America/St_Barthelemy", "America/Guadeloupe", + "Australia/North", "Australia/Darwin", + "Europe/Zagreb", "Europe/Belgrade", + "Etc/Universal", "Etc/UTC", + "NZ-CHAT", "Pacific/Chatham", + "Asia/Macao", "Asia/Macau", + "Pacific/Yap", "Pacific/Chuuk", + "Egypt", "Africa/Cairo", + "US/Central", "America/Chicago", + "Canada/Atlantic", "America/Halifax", + "Brazil/East", "America/Sao_Paulo", + "America/Cordoba", "America/Argentina/Cordoba", + "US/Hawaii", "Pacific/Honolulu", + "America/Louisville", "America/Kentucky/Louisville", + "America/Shiprock", "America/Denver", + "Australia/Canberra", "Australia/Sydney", + "Asia/Chungking", "Asia/Chongqing", + "Universal", "Etc/UTC", + "US/Alaska", "America/Anchorage", + "Asia/Ujung_Pandang", "Asia/Makassar", + "Japan", "Asia/Tokyo", + "Atlantic/Faeroe", "Atlantic/Faroe", + "Asia/Istanbul", "Europe/Istanbul", + "US/Pacific", "America/Los_Angeles", + "Mexico/General", "America/Mexico_City", + "Poland", "Europe/Warsaw", + "Africa/Asmera", "Africa/Asmara", + "Asia/Saigon", "Asia/Ho_Chi_Minh", + "US/Michigan", "America/Detroit", + "America/Argentina/ComodRivadavia", "America/Argentina/Catamarca", + "W-SU", "Europe/Moscow", + "Australia/ACT", "Australia/Sydney", + "Asia/Calcutta", "Asia/Kolkata", + "Arctic/Longyearbyen", "Europe/Oslo", + "America/Knox_IN", "America/Indiana/Knox", + "ROC", "Asia/Taipei", + "Zulu", "Etc/UTC", + "Australia/Yancowinna", "Australia/Broken_Hill", + "Australia/West", "Australia/Perth", + "Singapore", "Asia/Singapore", + "Europe/Mariehamn", "Europe/Helsinki", + "ROK", "Asia/Seoul", + "America/Porto_Acre", "America/Rio_Branco", + "Etc/Zulu", "Etc/UTC", + "Canada/Yukon", "America/Whitehorse", + "Europe/Vatican", "Europe/Rome", + "Africa/Timbuktu", "Africa/Bamako", + "America/Buenos_Aires", "America/Argentina/Buenos_Aires", + "Canada/Pacific", "America/Vancouver", + "US/Pacific-New", "America/Los_Angeles", + "Mexico/BajaNorte", "America/Tijuana", + "Europe/Guernsey", "Europe/London", + "Asia/Tel_Aviv", "Asia/Jerusalem", + "Chile/Continental", "America/Santiago", + "Jamaica", "America/Jamaica", + "Mexico/BajaSur", "America/Mazatlan", + "Canada/Eastern", "America/Toronto", + "Australia/Tasmania", "Australia/Hobart", + "NZ", "Pacific/Auckland", + "America/Lower_Princes", "America/Curacao", + "GMT-", "Etc/GMT", + "America/Rosario", "America/Argentina/Cordoba", + "Libya", "Africa/Tripoli", + "Asia/Ashkhabad", "Asia/Ashgabat", + "Australia/NSW", "Australia/Sydney", + "America/Marigot", "America/Guadeloupe", + "Europe/Bratislava", "Europe/Prague", + "Portugal", "Europe/Lisbon", + "Etc/GMT-", "Etc/GMT", + "Europe/San_Marino", "Europe/Rome", + "Europe/Sarajevo", "Europe/Belgrade", + "Antarctica/South_Pole", "Antarctica/McMurdo", + "Canada/Central", "America/Winnipeg", + "Etc/GMT", "Etc/GMT", + "Europe/Isle_of_Man", "Europe/London", + "America/Fort_Wayne", "America/Indiana/Indianapolis", + "Eire", "Europe/Dublin", + "America/Coral_Harbour", "America/Atikokan", + "Europe/Nicosia", "Asia/Nicosia", + "US/Samoa", "Pacific/Pago_Pago", + "Hongkong", "Asia/Hong_Kong", + "Canada/Saskatchewan", "America/Regina", + "Asia/Thimbu", "Asia/Thimphu", + "Kwajalein", "Pacific/Kwajalein", + "GB", "Europe/London", + "Chile/EasterIsland", "Pacific/Easter", + "US/East-Indiana", "America/Indiana/Indianapolis", + "Australia/LHI", "Australia/Lord_Howe", + "Cuba", "America/Havana", + "America/Jujuy", "America/Argentina/Jujuy", + "US/Mountain", "America/Denver", + "Atlantic/Jan_Mayen", "Europe/Oslo", + "Europe/Tiraspol", "Europe/Chisinau", + "Europe/Podgorica", "Europe/Belgrade", + "US/Arizona", "America/Phoenix", + "Navajo", "America/Denver", + "Etc/Greenwich", "Etc/GMT", + "Canada/Mountain", "America/Edmonton", + "Iceland", "Atlantic/Reykjavik", + "Australia/Victoria", "Australia/Melbourne", + "Australia/South", "Australia/Adelaide", + "Brazil/West", "America/Manaus", + "Pacific/Ponape", "Pacific/Pohnpei", + "Europe/Ljubljana", "Europe/Belgrade", + "Europe/Jersey", "Europe/London", + "Australia/Queensland", "Australia/Brisbane", + "UTC", "Etc/UTC", + "Canada/Newfoundland", "America/St_Johns", + "Europe/Skopje", "Europe/Belgrade", + "Canada/East-Saskatchewan", "America/Regina", + "PRC", "Asia/Shanghai", + "UCT", "Etc/UCT", + "America/Mendoza", "America/Argentina/Mendoza", + "Israel", "Asia/Jerusalem", + "US/Eastern", "America/New_York", + "Asia/Ulan_Bator", "Asia/Ulaanbaatar", + "Turkey", "Europe/Istanbul", + "GMT", "Etc/GMT", + "US/Aleutian", "America/Adak", + "Brazil/DeNoronha", "America/Noronha", + "GB-Eire", "Europe/London", + "Asia/Dacca", "Asia/Dhaka", + "America/Ensenada", "America/Tijuana", + "America/Catamarca", "America/Argentina/Catamarca", + "Iran", "Asia/Tehran", + "Greenwich", "Etc/GMT", + "Pacific/Truk", "Pacific/Chuuk", + "Pacific/Samoa", "Pacific/Pago_Pago", + "America/Virgin", "America/St_Thomas", + "Asia/Katmandu", "Asia/Kathmandu", + "America/Indianapolis", "America/Indiana/Indianapolis", + "Europe/Belfast", "Europe/London", + "America/Kralendijk", "America/Curacao", + }; + + private static final Map zidToMzone = new HashMap<>(); + private static final Map mzoneToZid = new HashMap<>(); + private static final Map> mzoneToZidL = new HashMap<>(); + private static final Map aliases = new HashMap<>(); + + static { + for (int i = 0; i < zidMap.length; i += 3) { + zidToMzone.put(zidMap[i], zidMap[i + 1]); + mzoneToZid.put(zidMap[i + 1], zidMap[i + 2]); + } + + for (int i = 0; i < mzoneMap.length; i += 3) { + String mzone = mzoneMap[i]; + Map map = mzoneToZidL.get(mzone); + if (map == null) { + map = new HashMap<>(); + mzoneToZidL.put(mzone, map); + } + map.put(mzoneMap[i + 1], mzoneMap[i + 2]); + } + + for (int i = 0; i < aliasMap.length; i += 2) { + aliases.put(aliasMap[i], aliasMap[i + 1]); + } + } +} diff --git a/jdk/src/share/classes/java/time/format/package-info.java b/jdk/src/share/classes/java/time/format/package-info.java index 9f96532f667..94a0600dc8e 100644 --- a/jdk/src/share/classes/java/time/format/package-info.java +++ b/jdk/src/share/classes/java/time/format/package-info.java @@ -68,7 +68,7 @@ * Printing and parsing is based around the * {@link java.time.format.DateTimeFormatter DateTimeFormatter} class. * Instances are generally obtained from - * {@link java.time.format.DateTimeFormatters DateTimeFormatters}, however + * {@link java.time.format.DateTimeFormatter DateTimeFormatter}, however * {@link java.time.format.DateTimeFormatterBuilder DateTimeFormatterBuilder} * can be used if more power is needed. *

      diff --git a/jdk/src/share/classes/java/time/overview.html b/jdk/src/share/classes/java/time/overview.html index c522c4b4708..ef102f800f8 100644 --- a/jdk/src/share/classes/java/time/overview.html +++ b/jdk/src/share/classes/java/time/overview.html @@ -87,12 +87,6 @@ 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. @@ -105,7 +99,8 @@ Detailed information is made available about the rules of each time-zone.

      - The {@link java.time.calendar} package contains alternate calendar systems. + {@link java.time.chrono} contains the basic part of the calendar neutral API + and 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.

      @@ -136,7 +131,7 @@ 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}. + By contrast, some additional classes were used for dates, such as {@link java.time.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.

      @@ -161,7 +156,7 @@

      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 + This is supported by {@link java.time.chrono.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, diff --git a/jdk/src/share/classes/java/time/package-info.java b/jdk/src/share/classes/java/time/package-info.java index 9d06ff9352c..5bc428319d1 100644 --- a/jdk/src/share/classes/java/time/package-info.java +++ b/jdk/src/share/classes/java/time/package-info.java @@ -79,13 +79,13 @@ * 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}. + * The {@code java.time.chrono} package contains the calendar neutral API + * {@link java.time.chrono.ChronoLocalDate ChronoLocalDate}, + * {@link java.time.chrono.ChronoLocalDateTime ChronoLocalDateTime}, + * {@link java.time.chrono.ChronoZonedDateTime ChronoZonedDateTime} and + * {@link java.time.chrono.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 + * It is recommended that applications use the ISO-8601 date 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. *

      @@ -135,29 +135,25 @@ * This stores a single day-of-week in isolation, such as 'TUESDAY'. *

      *

      - * {@link java.time.temporal.Year} stores a year on its own. + * {@link java.time.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. + * {@link java.time.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. + * {@link java.time.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. + * {@link java.time.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. + * {@link java.time.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. @@ -206,7 +202,7 @@ * with the time-zone added at the user interface (UI) layer. *

      *

      - * The offset-based date-time types, {@code OffsetDate}, {@code OffsetTime} and {@code OffsetDateTime}, + * The offset-based date-time types {@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'. @@ -261,7 +257,7 @@ *

      * 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 + * This is supported by {@link java.time.chrono.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, diff --git a/jdk/src/share/classes/java/time/temporal/ChronoField.java b/jdk/src/share/classes/java/time/temporal/ChronoField.java index f163654225b..2a421157a5e 100644 --- a/jdk/src/share/classes/java/time/temporal/ChronoField.java +++ b/jdk/src/share/classes/java/time/temporal/ChronoField.java @@ -72,8 +72,10 @@ import static java.time.temporal.ChronoUnit.YEARS; import java.time.DayOfWeek; import java.time.Instant; +import java.time.Year; import java.time.ZoneOffset; -import java.time.format.DateTimeBuilder; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.Chronology; /** * A standard set of fields. @@ -521,6 +523,23 @@ public enum ChronoField implements TemporalField { return rangeUnit; } + /** + * 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 returns the range of the field in the ISO-8601 calendar system. + * This range may be incorrect for other calendar systems. + * Use {@link Chronology#range(ChronoField)} to access the correct range + * for a different 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 + */ @Override public ValueRange range() { return range; @@ -551,6 +570,11 @@ public enum ChronoField implements TemporalField { *

      * This validates that the value is within the outer range of valid values * returned by {@link #range()}. + *

      + * This method checks against the range of the field in the ISO-8601 calendar system. + * This range may be incorrect for other calendar systems. + * Use {@link Chronology#range(ChronoField)} to access the correct range + * for a different calendar system. * * @param value the value to check * @return the value that was passed in @@ -565,6 +589,11 @@ public enum ChronoField implements TemporalField { * 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}. + *

      + * This method checks against the range of the field in the ISO-8601 calendar system. + * This range may be incorrect for other calendar systems. + * Use {@link Chronology#range(ChronoField)} to access the correct range + * for a different calendar system. * * @param value the value to check * @return the value that was passed in @@ -575,32 +604,26 @@ public enum ChronoField implements TemporalField { //----------------------------------------------------------------------- @Override - public boolean doIsSupported(TemporalAccessor temporal) { + public boolean isSupportedBy(TemporalAccessor temporal) { return temporal.isSupported(this); } @Override - public ValueRange doRange(TemporalAccessor temporal) { + public ValueRange rangeRefinedBy(TemporalAccessor temporal) { return temporal.range(this); } @Override - public long doGet(TemporalAccessor temporal) { + public long getFrom(TemporalAccessor temporal) { return temporal.getLong(this); } @SuppressWarnings("unchecked") @Override - public R doWith(R temporal, long newValue) { + public R adjustInto(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() { diff --git a/jdk/src/share/classes/java/time/temporal/ChronoUnit.java b/jdk/src/share/classes/java/time/temporal/ChronoUnit.java index 33f1318bbf6..0551858ffe8 100644 --- a/jdk/src/share/classes/java/time/temporal/ChronoUnit.java +++ b/jdk/src/share/classes/java/time/temporal/ChronoUnit.java @@ -57,6 +57,9 @@ package java.time.temporal; import java.time.Duration; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.ChronoLocalDateTime; +import java.time.chrono.ChronoZonedDateTime; /** * A standard set of date periods units. @@ -254,7 +257,7 @@ public enum ChronoUnit implements TemporalUnit { //----------------------------------------------------------------------- @Override - public boolean isSupported(Temporal temporal) { + public boolean isSupportedBy(Temporal temporal) { if (this == FOREVER) { return false; } @@ -264,19 +267,19 @@ public enum ChronoUnit implements TemporalUnit { if (temporal instanceof ChronoLocalDateTime || temporal instanceof ChronoZonedDateTime) { return true; } - return TemporalUnit.super.isSupported(temporal); + return TemporalUnit.super.isSupportedBy(temporal); } @SuppressWarnings("unchecked") @Override - public R doPlus(R dateTime, long periodToAdd) { - return (R) dateTime.plus(periodToAdd, this); + public R addTo(R temporal, long amount) { + return (R) temporal.plus(amount, this); } //----------------------------------------------------------------------- @Override - public SimplePeriod between(R dateTime1, R dateTime2) { - return new SimplePeriod(dateTime1.periodUntil(dateTime2, this), this); + public long between(Temporal temporal1, Temporal temporal2) { + return temporal1.periodUntil(temporal2, this); } //----------------------------------------------------------------------- diff --git a/jdk/src/share/classes/java/time/temporal/ISOFields.java b/jdk/src/share/classes/java/time/temporal/IsoFields.java similarity index 76% rename from jdk/src/share/classes/java/time/temporal/ISOFields.java rename to jdk/src/share/classes/java/time/temporal/IsoFields.java index 548d1d5e31b..5e03c1c12e1 100644 --- a/jdk/src/share/classes/java/time/temporal/ISOFields.java +++ b/jdk/src/share/classes/java/time/temporal/IsoFields.java @@ -72,7 +72,10 @@ import static java.time.temporal.ChronoUnit.YEARS; import java.time.DateTimeException; import java.time.Duration; import java.time.LocalDate; -import java.time.format.DateTimeBuilder; +import java.time.chrono.Chronology; +import java.time.chrono.IsoChronology; +import java.util.HashMap; +import java.util.Map; /** * Fields and units specific to the ISO-8601 calendar system, @@ -143,7 +146,7 @@ import java.time.format.DateTimeBuilder; * * @since 1.8 */ -public final class ISOFields { +public final class IsoFields { /** * The field that represents the day-of-quarter. @@ -216,7 +219,7 @@ public final class ISOFields { /** * Restricted constructor. */ - private ISOFields() { + private IsoFields() { throw new AssertionError("Not instantiable"); } @@ -243,19 +246,19 @@ public final class ISOFields { return ValueRange.of(1, 90, 92); } @Override - public boolean doIsSupported(TemporalAccessor temporal) { + public boolean isSupportedBy(TemporalAccessor temporal) { return temporal.isSupported(DAY_OF_YEAR) && temporal.isSupported(MONTH_OF_YEAR) && - temporal.isSupported(YEAR) && Chrono.from(temporal).equals(ISOChrono.INSTANCE); + temporal.isSupported(YEAR) && isIso(temporal); } @Override - public ValueRange doRange(TemporalAccessor temporal) { - if (doIsSupported(temporal) == false) { + public ValueRange rangeRefinedBy(TemporalAccessor temporal) { + if (isSupportedBy(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)); + return (IsoChronology.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) { @@ -264,20 +267,37 @@ public final class ISOFields { return range(); } @Override - public long doGet(TemporalAccessor temporal) { - if (doIsSupported(temporal) == false) { + public long getFrom(TemporalAccessor temporal) { + if (isSupportedBy(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)]; + return doy - QUARTER_DAYS[((moy - 1) / 3) + (IsoChronology.INSTANCE.isLeapYear(year) ? 4 : 0)]; + } + @SuppressWarnings("unchecked") + @Override + public R adjustInto(R temporal, long newValue) { + // calls getFrom() to check if supported + long curValue = getFrom(temporal); + range().checkValidValue(newValue, this); // leniently check from 1 to 92 TODO: check + return (R) temporal.with(DAY_OF_YEAR, temporal.getLong(DAY_OF_YEAR) + (newValue - curValue)); } @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)); + public Map resolve(TemporalAccessor temporal, long value) { + if ((temporal.isSupported(YEAR) && temporal.isSupported(DAY_OF_QUARTER)) == false) { + return null; + } + int y = temporal.get(YEAR); + int qoy = temporal.get(QUARTER_OF_YEAR); + range().checkValidValue(value, this); // leniently check from 1 to 92 TODO: check + LocalDate date = LocalDate.of(y, ((qoy - 1) * 3) + 1, 1).plusDays(value - 1); + Map result = new HashMap<>(4, 1.0f); + result.put(EPOCH_DAY, date.toEpochDay()); + result.put(YEAR, null); + result.put(QUARTER_OF_YEAR, null); + return result; } }, QUARTER_OF_YEAR { @@ -298,36 +318,25 @@ public final class ISOFields { return ValueRange.of(1, 4); } @Override - public boolean doIsSupported(TemporalAccessor temporal) { - return temporal.isSupported(MONTH_OF_YEAR) && Chrono.from(temporal).equals(ISOChrono.INSTANCE); + public boolean isSupportedBy(TemporalAccessor temporal) { + return temporal.isSupported(MONTH_OF_YEAR) && isIso(temporal); } @Override - public long doGet(TemporalAccessor temporal) { - if (doIsSupported(temporal) == false) { - throw new DateTimeException("Unsupported field: DayOfQuarter"); + public long getFrom(TemporalAccessor temporal) { + if (isSupportedBy(temporal) == false) { + throw new DateTimeException("Unsupported field: QuarterOfYear"); } long moy = temporal.getLong(MONTH_OF_YEAR); return ((moy + 2) / 3); } + @SuppressWarnings("unchecked") @Override - public R doWith(R temporal, long newValue) { - long curValue = doGet(temporal); - range().checkValidValue(newValue, this); + public R adjustInto(R temporal, long newValue) { + // calls getFrom() to check if supported + long curValue = getFrom(temporal); + range().checkValidValue(newValue, this); // strictly check from 1 to 4 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 @@ -347,21 +356,44 @@ public final class ISOFields { return ValueRange.of(1, 52, 53); } @Override - public boolean doIsSupported(TemporalAccessor temporal) { - return temporal.isSupported(EPOCH_DAY); + public boolean isSupportedBy(TemporalAccessor temporal) { + return temporal.isSupported(EPOCH_DAY) && isIso(temporal); } @Override - public ValueRange doRange(TemporalAccessor temporal) { + public ValueRange rangeRefinedBy(TemporalAccessor temporal) { + if (isSupportedBy(temporal) == false) { + throw new DateTimeException("Unsupported field: WeekOfWeekBasedYear"); + } return getWeekRange(LocalDate.from(temporal)); } @Override - public long doGet(TemporalAccessor temporal) { + public long getFrom(TemporalAccessor temporal) { + if (isSupportedBy(temporal) == false) { + throw new DateTimeException("Unsupported field: WeekOfWeekBasedYear"); + } return getWeek(LocalDate.from(temporal)); } + @SuppressWarnings("unchecked") @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); + public R adjustInto(R temporal, long newValue) { + // calls getFrom() to check if supported + range().checkValidValue(newValue, this); // lenient range + return (R) temporal.plus(Math.subtractExact(newValue, getFrom(temporal)), WEEKS); + } + @Override + public Map resolve(TemporalAccessor temporal, long value) { + if ((temporal.isSupported(WEEK_BASED_YEAR) && temporal.isSupported(DAY_OF_WEEK)) == false) { + return null; + } + int wby = temporal.get(WEEK_BASED_YEAR); + int dow = temporal.get(DAY_OF_WEEK); + range().checkValidValue(value, this); // lenient range + LocalDate date = LocalDate.of(wby, 1, 4).plusWeeks(value - 1).with(DAY_OF_WEEK, dow); + Map result = new HashMap<>(2, 1.0f); + result.put(EPOCH_DAY, date.toEpochDay()); + result.put(WEEK_BASED_YEAR, null); + result.put(DAY_OF_WEEK, null); + return result; } }, WEEK_BASED_YEAR { @@ -382,46 +414,35 @@ public final class ISOFields { return YEAR.range(); } @Override - public boolean doIsSupported(TemporalAccessor temporal) { - return temporal.isSupported(EPOCH_DAY); + public boolean isSupportedBy(TemporalAccessor temporal) { + return temporal.isSupported(EPOCH_DAY) && isIso(temporal); } @Override - public long doGet(TemporalAccessor temporal) { + public long getFrom(TemporalAccessor temporal) { + if (isSupportedBy(temporal) == false) { + throw new DateTimeException("Unsupported field: WeekBasedYear"); + } return getWeekBasedYear(LocalDate.from(temporal)); } + @SuppressWarnings("unchecked") @Override - public R doWith(R temporal, long newValue) { - int newVal = range().checkValidIntValue(newValue, WEEK_BASED_YEAR); + public R adjustInto(R temporal, long newValue) { + if (isSupportedBy(temporal) == false) { + throw new DateTimeException("Unsupported field: WeekBasedYear"); + } + int newVal = range().checkValidIntValue(newValue, WEEK_BASED_YEAR); // strict check 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) { + public ValueRange rangeRefinedBy(TemporalAccessor temporal) { return range(); } - @Override - public boolean resolve(DateTimeBuilder builder, long value) { - return false; - } - @Override public String toString() { return getName(); @@ -430,6 +451,10 @@ public final class ISOFields { //------------------------------------------------------------------------- private static final int[] QUARTER_DAYS = {0, 90, 181, 273, 0, 91, 182, 274}; + private static boolean isIso(TemporalAccessor temporal) { + return Chronology.from(temporal).equals(IsoChronology.INSTANCE); + } + private static ValueRange getWeekRange(LocalDate date) { int wby = getWeekBasedYear(date); date = date.withDayOfYear(1).withYear(wby); @@ -520,36 +545,34 @@ public final class ISOFields { } @Override - public boolean isSupported(Temporal temporal) { + public boolean isSupportedBy(Temporal temporal) { return temporal.isSupported(EPOCH_DAY); } + @SuppressWarnings("unchecked") @Override - public R doPlus(R dateTime, long periodToAdd) { + public R addTo(R temporal, long amount) { switch(this) { case WEEK_BASED_YEARS: - return (R) dateTime.with(WEEK_BASED_YEAR, - Math.addExact(dateTime.get(WEEK_BASED_YEAR), periodToAdd)); + return (R) temporal.with(WEEK_BASED_YEAR, + Math.addExact(temporal.get(WEEK_BASED_YEAR), amount)); case QUARTER_YEARS: // no overflow (256 is multiple of 4) - return (R) dateTime.plus(periodToAdd / 256, YEARS) - .plus((periodToAdd % 256) * 3, MONTHS); + return (R) temporal.plus(amount / 256, YEARS) + .plus((amount % 256) * 3, MONTHS); default: throw new IllegalStateException("Unreachable"); } } @Override - public SimplePeriod between(R dateTime1, R dateTime2) { + public long between(Temporal temporal1, Temporal temporal2) { 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); + return Math.subtractExact(temporal2.getLong(WEEK_BASED_YEAR), + temporal1.getLong(WEEK_BASED_YEAR)); case QUARTER_YEARS: - long period2 = Math.subtractExact(dateTime2.getLong(QUARTER_OF_YEAR), - dateTime1.getLong(QUARTER_OF_YEAR)); - return new SimplePeriod(period2, QUARTER_YEARS); + return temporal1.periodUntil(temporal2, MONTHS) / 3; default: throw new IllegalStateException("Unreachable"); } diff --git a/jdk/src/share/classes/java/time/temporal/JulianFields.java b/jdk/src/share/classes/java/time/temporal/JulianFields.java index 79a9e96bac7..d0a9d871fc3 100644 --- a/jdk/src/share/classes/java/time/temporal/JulianFields.java +++ b/jdk/src/share/classes/java/time/temporal/JulianFields.java @@ -65,11 +65,9 @@ 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; +import java.util.Collections; +import java.util.Map; /** * A set of date fields that provide access to Julian Days. @@ -77,6 +75,10 @@ import java.time.format.DateTimeBuilder; * 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. + *

      + * The fields are implemented relative to {@link ChronoField#EPOCH_DAY EPOCH_DAY}. + * The fields are supported, and can be queried and set if {@code EPOCH_DAY} is available. + * The fields work with all chronologies. * *

      Specification for implementors

      * This is an immutable and thread-safe class. @@ -99,10 +101,10 @@ public final class JulianFields { * 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 + * For date-times, 'JULIAN_DAY.getFrom()' 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 + * When 'JULIAN_DAY.adjustInto()' is applied to a date-time, the time of day portion remains unaltered. + * 'JULIAN_DAY.adjustInto()' and 'JULIAN_DAY.getFrom()' 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. *

      @@ -129,7 +131,7 @@ public final class JulianFields { * 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); + public static final TemporalField JULIAN_DAY = Field.JULIAN_DAY; /** * Modified Julian Day field. @@ -140,10 +142,10 @@ public final class JulianFields { * 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 + * For date-times, 'MODIFIED_JULIAN_DAY.getFrom()' 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 + * When 'MODIFIED_JULIAN_DAY.adjustInto()' is applied to a date-time, the time of day portion remains unaltered. + * 'MODIFIED_JULIAN_DAY.adjustInto()' and 'MODIFIED_JULIAN_DAY.getFrom()' 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. *

      @@ -165,7 +167,7 @@ public final class JulianFields { * 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); + public static final TemporalField MODIFIED_JULIAN_DAY = Field.MODIFIED_JULIAN_DAY; /** * Rata Die field. @@ -173,14 +175,14 @@ public final class JulianFields { * 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 + * For date-times, 'RATA_DIE.getFrom()' 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 + * When 'RATA_DIE.adjustInto()' is applied to a date-time, the time of day portion remains unaltered. + * 'RATA_DIE.adjustInto()' and 'RATA_DIE.getFrom()' 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); + public static final TemporalField RATA_DIE = Field.RATA_DIE; /** * Restricted constructor. @@ -190,13 +192,16 @@ public final class JulianFields { } /** - * implementation of JulianFields. Each instance is a singleton. + * Implementation of JulianFields. Each instance is a singleton. */ - private static class Field implements TemporalField, Serializable { + private static enum Field implements TemporalField { + JULIAN_DAY("JulianDay", DAYS, FOREVER, JULIAN_DAY_OFFSET), + MODIFIED_JULIAN_DAY("ModifiedJulianDay", DAYS, FOREVER, 40587L), + RATA_DIE("RataDie", DAYS, FOREVER, 719163L); private static final long serialVersionUID = -7501623920830201812L; - private final String name; + private final transient String name; private final transient TemporalUnit baseUnit; private final transient TemporalUnit rangeUnit; private final transient ValueRange range; @@ -210,25 +215,6 @@ public final class JulianFields { 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() { @@ -252,25 +238,26 @@ public final class JulianFields { //----------------------------------------------------------------------- @Override - public boolean doIsSupported(TemporalAccessor temporal) { + public boolean isSupportedBy(TemporalAccessor temporal) { return temporal.isSupported(EPOCH_DAY); } @Override - public ValueRange doRange(TemporalAccessor temporal) { - if (doIsSupported(temporal) == false) { + public ValueRange rangeRefinedBy(TemporalAccessor temporal) { + if (isSupportedBy(temporal) == false) { throw new DateTimeException("Unsupported field: " + this); } return range(); } @Override - public long doGet(TemporalAccessor temporal) { + public long getFrom(TemporalAccessor temporal) { return temporal.getLong(EPOCH_DAY) + offset; } + @SuppressWarnings("unchecked") @Override - public R doWith(R temporal, long newValue) { + public R adjustInto(R temporal, long newValue) { if (range().isValidValue(newValue) == false) { throw new DateTimeException("Invalid value: " + name + " " + newValue); } @@ -279,27 +266,14 @@ public final class JulianFields { //----------------------------------------------------------------------- @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; + public Map resolve(TemporalAccessor temporal, long value) { + return Collections.singletonMap(EPOCH_DAY, Math.subtractExact(value, offset)); } //----------------------------------------------------------------------- @Override public String toString() { - return getName(); + return name; } } } diff --git a/jdk/src/share/classes/java/time/temporal/OffsetDate.java b/jdk/src/share/classes/java/time/temporal/OffsetDate.java deleted file mode 100644 index 2503de927bd..00000000000 --- a/jdk/src/share/classes/java/time/temporal/OffsetDate.java +++ /dev/null @@ -1,1351 +0,0 @@ -/* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * 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/Queries.java b/jdk/src/share/classes/java/time/temporal/Queries.java index 74b8f1adf85..a4c0a420fe2 100644 --- a/jdk/src/share/classes/java/time/temporal/Queries.java +++ b/jdk/src/share/classes/java/time/temporal/Queries.java @@ -61,10 +61,17 @@ */ 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.ChronoField.OFFSET_SECONDS; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.OffsetDateTime; import java.time.ZoneId; import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.chrono.Chronology; /** * Common implementations of {@code TemporalQuery}. @@ -116,9 +123,8 @@ public final class Queries { * 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. + * Thus a {@link ZonedDateTime} will return the result of {@code getZone()}, + * but an {@link OffsetDateTime} will return null. *

      * In most cases, applications should use {@link #ZONE} as this query is too strict. *

      @@ -127,7 +133,6 @@ public final class Queries { * {@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
      @@ -141,20 +146,18 @@ public final class Queries { * {@code MonthDay} returns null
      * {@code ZoneOffset} returns null
      * {@code Instant} returns null
      - * @return a ZoneId, may be null + * + * @return a query that can obtain the zone ID of a temporal, not 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); - } + static final TemporalQuery ZONE_ID = (temporal) -> { + return temporal.query(ZONE_ID); }; /** - * A query for the {@code Chrono}. + * A query for the {@code Chronology}. *

      * This queries a {@code TemporalAccessor} for the chronology. * If the target {@code TemporalAccessor} represents a date, or part of a date, @@ -163,39 +166,36 @@ public final class Queries { * {@code LocalTime}, will return null. *

      * The result from JDK classes implementing {@code TemporalAccessor} is as follows:
      - * {@code LocalDate} returns {@code ISOChrono.INSTANCE}
      + * {@code LocalDate} returns {@code IsoChronology.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 LocalDateTime} returns {@code IsoChronology.INSTANCE}
      + * {@code ZonedDateTime} returns {@code IsoChronology.INSTANCE}
      * {@code OffsetTime} returns null (does not represent a date)
      - * {@code OffsetDateTime} returns {@code ISOChrono.INSTANCE}
      + * {@code OffsetDateTime} returns {@code IsoChronology.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 Month} returns {@code IsoChronology.INSTANCE}
      + * {@code Year} returns {@code IsoChronology.INSTANCE}
      + * {@code YearMonth} returns {@code IsoChronology.INSTANCE}
      + * {@code MonthDay} returns null {@code IsoChronology.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}. + * The method {@link Chronology#from(TemporalAccessor)} can be used as a + * {@code TemporalQuery} via a method reference, {@code Chronology::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 + * + * @return a query that can obtain the chronology of a temporal, not null */ - public static final TemporalQuery> chrono() { + public static final TemporalQuery chronology() { return CHRONO; } - static final TemporalQuery> CHRONO = new TemporalQuery>() { - @Override - public Chrono queryFrom(TemporalAccessor temporal) { - return temporal.query(this); - } + static final TemporalQuery CHRONO = (temporal) -> { + return temporal.query(CHRONO); }; /** @@ -215,7 +215,6 @@ public final class Queries { * {@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}
      @@ -229,16 +228,14 @@ public final class Queries { * {@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 + * + * @return a query that can obtain the precision of a temporal, not null */ - public static final TemporalQuery precision() { + public static final TemporalQuery precision() { return PRECISION; } - static final TemporalQuery PRECISION = new TemporalQuery() { - @Override - public ChronoUnit queryFrom(TemporalAccessor temporal) { - return temporal.query(this); - } + static final TemporalQuery PRECISION = (temporal) -> { + return temporal.query(PRECISION); }; //----------------------------------------------------------------------- @@ -249,54 +246,111 @@ public final class Queries { * 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()}. + * Thus a {@link ZonedDateTime} will return the result of {@code getZone()}, + * while an {@link OffsetDateTime} will return the result of {@code getOffset()}. *

      * 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 + * + * @return a query that can obtain the zone ID or offset of a temporal, not 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)); - } + static final TemporalQuery ZONE = (temporal) -> { + ZoneId zone = temporal.query(ZONE_ID); + return (zone != null ? zone : temporal.query(OFFSET)); }; /** - * A query for the {@code ZoneOffset}. + * A query for {@code ZoneOffset} returning null if not found. *

      - * This queries a {@code TemporalAccessor} for the offset. + * This returns a {@code TemporalQuery} that can be used to query a temporal + * object for the offset. The query will return null if the temporal + * object cannot supply an offset. *

      - * This query examines the {@link java.time.temporal.ChronoField#OFFSET_SECONDS offset-seconds} + * The query implementation examines the {@link 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 + * This query and {@code ZoneOffset::from} will return the same result if the + * temporal object contains an offset. If the temporal object does not contain + * an offset, then the method reference will throw an exception, whereas this + * query will return null. + * + * @return a query that can obtain the offset of a temporal, not 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; + static final TemporalQuery OFFSET = (temporal) -> { + if (temporal.isSupported(OFFSET_SECONDS)) { + return ZoneOffset.ofTotalSeconds(temporal.get(OFFSET_SECONDS)); } + return null; + }; + + /** + * A query for {@code LocalDate} returning null if not found. + *

      + * This returns a {@code TemporalQuery} that can be used to query a temporal + * object for the local date. The query will return null if the temporal + * object cannot supply a local date. + *

      + * The query implementation examines the {@link ChronoField#EPOCH_DAY EPOCH_DAY} + * field and uses it to create a {@code LocalDate}. + *

      + * The method {@link ZoneOffset#from(TemporalAccessor)} can be used as a + * {@code TemporalQuery} via a method reference, {@code LocalDate::from}. + * This query and {@code LocalDate::from} will return the same result if the + * temporal object contains a date. If the temporal object does not contain + * a date, then the method reference will throw an exception, whereas this + * query will return null. + * + * @return a query that can obtain the date of a temporal, not null + */ + public static final TemporalQuery localDate() { + return LOCAL_DATE; + } + static final TemporalQuery LOCAL_DATE = (temporal) -> { + if (temporal.isSupported(EPOCH_DAY)) { + return LocalDate.ofEpochDay(temporal.getLong(EPOCH_DAY)); + } + return null; + }; + + /** + * A query for {@code LocalTime} returning null if not found. + *

      + * This returns a {@code TemporalQuery} that can be used to query a temporal + * object for the local time. The query will return null if the temporal + * object cannot supply a local time. + *

      + * The query implementation examines the {@link ChronoField#NANO_OF_DAY NANO_OF_DAY} + * field and uses it to create a {@code LocalTime}. + *

      + * The method {@link ZoneOffset#from(TemporalAccessor)} can be used as a + * {@code TemporalQuery} via a method reference, {@code LocalTime::from}. + * This query and {@code LocalTime::from} will return the same result if the + * temporal object contains a time. If the temporal object does not contain + * a time, then the method reference will throw an exception, whereas this + * query will return null. + * + * @return a query that can obtain the time of a temporal, not null + */ + public static final TemporalQuery localTime() { + return LOCAL_TIME; + } + static final TemporalQuery LOCAL_TIME = (temporal) -> { + if (temporal.isSupported(NANO_OF_DAY)) { + return LocalTime.ofNanoOfDay(temporal.getLong(NANO_OF_DAY)); + } + return null; }; } diff --git a/jdk/src/share/classes/java/time/temporal/Ser.java b/jdk/src/share/classes/java/time/temporal/Ser.java deleted file mode 100644 index 2f182e0439b..00000000000 --- a/jdk/src/share/classes/java/time/temporal/Ser.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * Copyright (c) 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 deleted file mode 100644 index 5eb60f5c903..00000000000 --- a/jdk/src/share/classes/java/time/temporal/SimplePeriod.java +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * 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 index 0eddf27b964..3eeed90b096 100644 --- a/jdk/src/share/classes/java/time/temporal/Temporal.java +++ b/jdk/src/share/classes/java/time/temporal/Temporal.java @@ -81,7 +81,7 @@ import java.time.ZoneId; * 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}. + * the {@linkplain java.time.chrono.Chronology chronology} and the {@linkplain ZoneId time-zone}. * These can be accessed via {@link #query(TemporalQuery) queries} using * the static methods defined on {@link Queries}. *

      @@ -90,7 +90,7 @@ import java.time.ZoneId; * 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. + * See {@link java.time.chrono.ChronoLocalDate} for a fuller discussion of the issues. * *

      When to implement

      *

      @@ -183,7 +183,7 @@ public interface Temporal extends TemporalAccessor { * 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)} + * is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)} * passing {@code this} as the first argument. *

      * Implementations must not alter either this object or the specified temporal object. @@ -202,9 +202,9 @@ public interface Temporal extends TemporalAccessor { /** * 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}. + * This adjusts this temporal, adding according to the rules of the specified amount. + * The amount is typically a {@link java.time.Period} but may be any other type implementing + * the {@link TemporalAmount} interface, such as {@link java.time.Duration}. *

      * Some example code indicating how and why this method is used: *

      @@ -224,16 +224,16 @@ public interface Temporal extends TemporalAccessor {
            * 

      * The default implementation must behave equivalent to this code: *

      -     *  return adder.addTo(this);
      +     *  return amount.addTo(this);
            * 
      * - * @param adder the adder to use, not null + * @param amount the amount to add, 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); + public default Temporal plus(TemporalAmount amount) { + return amount.addTo(this); } /** @@ -258,7 +258,7 @@ public interface Temporal extends TemporalAccessor { * 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)} + * is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)} * passing {@code this} as the first argument. *

      * Implementations must not alter either this object or the specified temporal object. @@ -277,9 +277,9 @@ public interface Temporal extends TemporalAccessor { /** * 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}. + * This adjusts this temporal, subtracting according to the rules of the specified amount. + * The amount is typically a {@link java.time.Period} but may be any other type implementing + * the {@link TemporalAmount} interface, such as {@link java.time.Duration}. *

      * Some example code indicating how and why this method is used: *

      @@ -299,16 +299,16 @@ public interface Temporal extends TemporalAccessor {
            * 

      * The default implementation must behave equivalent to this code: *

      -     *  return subtractor.subtractFrom(this);
      +     *  return amount.subtractFrom(this);
            * 
      * - * @param subtractor the subtractor to use, not null + * @param amount the amount to subtract, 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); + public default Temporal minus(TemporalAmount amount) { + return amount.subtractFrom(this); } /** @@ -366,13 +366,22 @@ public interface Temporal extends TemporalAccessor { * 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: + * There are two equivalent ways of using this method. + * The first is to invoke this method directly. + * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: *

      -     *   long period = start.periodUntil(end, HOURS);   // this method
      -     *   dateTime.plus(HOURS.between(start, end));      // use in plus/minus
      +     *   // these two lines are equivalent
      +     *   temporal = start.periodUntil(end, unit);
      +     *   temporal = unit.between(start, end);
      +     * 
      + * The choice should be made based on which makes the code more readable. + *

      + * For example, this method allows the number of days between two dates to + * be calculated: + *

      +     *  long daysBetween = start.periodUntil(end, DAYS);
      +     *  // or alternatively
      +     *  long daysBetween = DAYS.between(start, end);
            * 
      * *

      Specification for implementors

      @@ -394,14 +403,16 @@ public interface Temporal extends TemporalAccessor { * // if unit is supported, then calculate and return result * // else throw DateTimeException for unsupported units * } - * return unit.between(this, endTime).getAmount(); + * return unit.between(this, endTemporal); *
      *

      - * The target object must not be altered by this method. + * Neither this object, nor the specified temporal, may be altered. * * @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 + * @return the period between this temporal object and the specified one in terms of + * the unit; positive if the specified object is later than this one, negative if + * it is earlier than this one * @throws DateTimeException if the period cannot be calculated * @throws ArithmeticException if numeric overflow occurs */ diff --git a/jdk/src/share/classes/java/time/temporal/TemporalAccessor.java b/jdk/src/share/classes/java/time/temporal/TemporalAccessor.java index 2f88fa74c7a..cd09573c7d8 100644 --- a/jdk/src/share/classes/java/time/temporal/TemporalAccessor.java +++ b/jdk/src/share/classes/java/time/temporal/TemporalAccessor.java @@ -79,7 +79,7 @@ import java.time.ZoneId; * 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}. + * the {@linkplain java.time.chrono.Chronology chronology} and the {@linkplain ZoneId time-zone}. * These can be accessed via {@link #query(TemporalQuery) queries} using * the static methods defined on {@link Queries}. *

      @@ -91,7 +91,7 @@ import java.time.ZoneId; * 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. + * See {@link java.time.chrono.ChronoLocalDate} for a fuller discussion of the issues. * *

      Specification for implementors

      * This interface places no restrictions on the mutability of implementations, @@ -113,7 +113,7 @@ public interface TemporalAccessor { * 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)} + * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} * passing {@code this} as the argument. *

      * Implementations must not alter either this object. @@ -142,7 +142,7 @@ public interface TemporalAccessor { * 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)} + * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessorl)} * passing {@code this} as the argument. *

      * Implementations must not alter either this object. @@ -155,7 +155,7 @@ public interface TemporalAccessor { * } * throw new DateTimeException("Unsupported field: " + field.getName()); * } - * return field.doRange(this); + * return field.rangeRefinedBy(this); *

      * * @param field the field to query the range for, not null @@ -169,7 +169,7 @@ public interface TemporalAccessor { } throw new DateTimeException("Unsupported field: " + field.getName()); } - return field.doRange(this); + return field.rangeRefinedBy(this); } /** @@ -187,7 +187,7 @@ public interface TemporalAccessor { * 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)} + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} * passing {@code this} as the argument. *

      * Implementations must not alter either this object. @@ -222,7 +222,7 @@ public interface TemporalAccessor { * 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)} + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} * passing {@code this} as the argument. *

      * Implementations must not alter either this object. @@ -253,7 +253,7 @@ public interface TemporalAccessor { *

      Specification for implementors

      * The default implementation must behave equivalent to this code: *
      -     *  if (query == Queries.zoneId() || query == Queries.chrono() || query == Queries.precision()) {
      +     *  if (query == Queries.zoneId() || query == Queries.chronology() || query == Queries.precision()) {
            *    return null;
            *  }
            *  return query.queryFrom(this);
      @@ -283,7 +283,7 @@ public interface TemporalAccessor {
            * @throws ArithmeticException if numeric overflow occurs
            */
           public default  R query(TemporalQuery query) {
      -        if (query == Queries.zoneId() || query == Queries.chrono() || query == Queries.precision()) {
      +        if (query == Queries.zoneId() || query == Queries.chronology() || 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
      deleted file mode 100644
      index fad2db42abb..00000000000
      --- a/jdk/src/share/classes/java/time/temporal/TemporalAdder.java
      +++ /dev/null
      @@ -1,139 +0,0 @@
      -/*
      - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
      - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      - *
      - * This code is free software; you can redistribute it and/or modify it
      - * under the terms of the GNU General Public License version 2 only, as
      - * published by the Free Software Foundation.  Oracle designates this
      - * particular file as subject to the "Classpath" exception as provided
      - * by Oracle in the LICENSE file that accompanied this code.
      - *
      - * This code is distributed in the hope that it will be useful, but WITHOUT
      - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      - * version 2 for more details (a copy is included in the LICENSE file that
      - * accompanied this code).
      - *
      - * You should have received a copy of the GNU General Public License version
      - * 2 along with this work; if not, write to the Free Software Foundation,
      - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      - *
      - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      - * or visit www.oracle.com if you need additional information or have any
      - * questions.
      - */
      -
      -/*
      - * 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 index 4a6f03d2875..2b808b6795b 100644 --- a/jdk/src/share/classes/java/time/temporal/TemporalAdjuster.java +++ b/jdk/src/share/classes/java/time/temporal/TemporalAdjuster.java @@ -93,6 +93,7 @@ import java.time.DateTimeException; * * @since 1.8 */ +@FunctionalInterface public interface TemporalAdjuster { /** @@ -127,7 +128,7 @@ public interface TemporalAdjuster { *

      * 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}. + * or reject non-ISO temporal objects by {@link Queries#chronology() querying the chronology}. *

      * This method may be called from multiple threads in parallel. * It must be thread-safe when invoked. diff --git a/jdk/src/share/classes/java/time/temporal/TemporalAmount.java b/jdk/src/share/classes/java/time/temporal/TemporalAmount.java new file mode 100644 index 00000000000..6fa4e47a36f --- /dev/null +++ b/jdk/src/share/classes/java/time/temporal/TemporalAmount.java @@ -0,0 +1,218 @@ +/* + * 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, 2013 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; +import java.util.List; + +/** + * Framework-level interface defining an amount of time, such as + * "6 hours", "8 days" or "2 years and 3 months". + *

      + * This is the base interface type for amounts of time. + * An amount is distinct from a date or time-of-day in that it is not tied + * to any specific point on the time-line. + *

      + * The amount can be thought of as a {@code Map} of {@link TemporalUnit} to + * {@code long}, exposed via {@link #getUnits()}and {@link #get(TemporalUnit)}. + * A simple case might have a single unit-value pair, such as "6 hours". + * A more complex case may have multiple unit-value pairs, such as + * "7 years, 3 months and 5 days". + *

      + * There are two common implementations. + * {@link Period} is a date-based implementation, storing years, months and days. + * {@link Duration} is a time-based implementation, storing seconds and nanoseconds, + * but providing some access using other duration based units such as minutes, + * hours and fixed 24-hour days. + *

      + * 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 Period} and {@code Duration}. + * + *

      Specification for implementors

      + * This interface places no restrictions on the mutability of implementations, + * however immutability is strongly recommended. + * + * @since 1.8 + */ +public interface TemporalAmount { + + /** + * Returns the value of the requested unit. + * The units returned from {@link #getUnits()} uniquely define the + * value of the {@code TemporalAmount}. A value must be returned + * for each unit listed in {@code getUnits}. + * + *

      Specification for implementors

      + * Implementations may declare support for units not listed by {@link #getUnits()}. + * Typically, the implementation would define additional units + * as conversions for the convenience of developers. + * + * @param unit the {@code TemporalUnit} for which to return the value + * @return the long value of the unit + * @throws DateTimeException if the {@code unit} is not supported + */ + public long get(TemporalUnit unit); + + /** + * Returns the list of units uniquely defining the value of this TemporalAmount. + * The list of {@code TemporalUnits} is defined by the implementation class. + * The list is a snapshot of the units at the time {@code getUnits} + * is called and is not mutable. + * The units are ordered from longest duration to the shortest duration + * of the unit. + * + *

      Specification for implementors

      + * The list of units completely and uniquely represents the + * state of the object without omissions, overlaps or duplication. + * The units are in order from longest duration to shortest. + * + * @return the List of {@code TemporalUnits}; not null + */ + public List getUnits(); + + /** + * Adds to the specified temporal object. + *

      + * Adds the amount 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(TemporalAmount)}: + *

      +     *   // These two lines are equivalent, but the second approach is recommended
      +     *   dateTime = amount.addTo(dateTime);
      +     *   dateTime = dateTime.plus(adder);
      +     * 
      + * It is recommended to use the second approach, {@code plus(TemporalAmount)}, + * 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#chronology() 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 add the amount to, 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 + */ + public Temporal addTo(Temporal temporal); + + /** + * Subtracts this object from the specified temporal object. + *

      + * Subtracts the amount from 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(TemporalAmount)}: + *

      +     *   // these two lines are equivalent, but the second approach is recommended
      +     *   dateTime = amount.subtractFrom(dateTime);
      +     *   dateTime = dateTime.minus(amount);
      +     * 
      + * It is recommended to use the second approach, {@code minus(TemporalAmount)}, + * 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#chronology() 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 subtract the amount from, 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 + */ + public Temporal subtractFrom(Temporal temporal); +} diff --git a/jdk/src/share/classes/java/time/temporal/TemporalField.java b/jdk/src/share/classes/java/time/temporal/TemporalField.java index 187d9e9b049..c456f56e866 100644 --- a/jdk/src/share/classes/java/time/temporal/TemporalField.java +++ b/jdk/src/share/classes/java/time/temporal/TemporalField.java @@ -62,8 +62,8 @@ package java.time.temporal; import java.time.DateTimeException; -import java.time.format.DateTimeBuilder; import java.util.Comparator; +import java.util.Map; /** * A field of date-time, such as month-of-year or hour-of-minute. @@ -72,7 +72,7 @@ import java.util.Comparator; * 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}. + * 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 @@ -83,7 +83,8 @@ import java.util.Comparator; *

      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. + * Implementations should be {@code Serializable} where possible. + * An enum is as effective implementation choice. * * @since 1.8 */ @@ -174,7 +175,7 @@ public interface TemporalField extends Comparator { * 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 = thisField.isSupportedBy(temporal);
            *   temporal = temporal.isSupported(thisField);
            * 
      * It is recommended to use the second approach, {@code isSupported(TemporalField)}, @@ -186,7 +187,7 @@ public interface TemporalField extends Comparator { * @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); + boolean isSupportedBy(TemporalAccessor temporal); /** * Get the range of valid values for this field using the temporal object to @@ -204,7 +205,7 @@ public interface TemporalField extends Comparator { * 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 = thisField.rangeRefinedBy(temporal);
            *   temporal = temporal.range(thisField);
            * 
      * It is recommended to use the second approach, {@code range(TemporalField)}, @@ -218,7 +219,7 @@ public interface TemporalField extends Comparator { * @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); + ValueRange rangeRefinedBy(TemporalAccessor temporal); /** * Gets the value of this field from the specified temporal object. @@ -231,7 +232,7 @@ public interface TemporalField extends Comparator { * (or {@link TemporalAccessor#get(TemporalField)}): *
            *   // these two lines are equivalent, but the second approach is recommended
      -     *   temporal = thisField.doGet(temporal);
      +     *   temporal = thisField.getFrom(temporal);
            *   temporal = temporal.getLong(thisField);
            * 
      * It is recommended to use the second approach, {@code getLong(TemporalField)}, @@ -244,8 +245,9 @@ public interface TemporalField extends Comparator { * @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 + * @throws ArithmeticException if numeric overflow occurs */ - long doGet(TemporalAccessor temporal); + long getFrom(TemporalAccessor temporal); /** * Returns a copy of the specified temporal object with the value of this field set. @@ -266,7 +268,7 @@ public interface TemporalField extends Comparator { * 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 = thisField.adjustInto(temporal);
            *   temporal = temporal.with(thisField);
            * 
      * It is recommended to use the second approach, {@code with(TemporalField)}, @@ -285,21 +287,45 @@ public interface TemporalField extends Comparator { * @param newValue the new value of the field * @return the adjusted temporal object, not null * @throws DateTimeException if the field cannot be set + * @throws ArithmeticException if numeric overflow occurs */ - R doWith(R temporal, long newValue); + R adjustInto(R temporal, long newValue); /** - * Resolves the date/time information in the builder + * Resolves this field to provide a simpler alternative. *

      - * 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} + * This method is invoked during the resolve phase of parsing. + * It is designed to allow application defined fields to be simplified into + * more standard fields, such as those on {@code ChronoField}. + *

      + * The method will only be invoked if the specified temporal supports this field. + * The value of this field is provided. + *

      + * The temporal must be queried using the methods of {@code TemporalAccessor}, + * not using {@code getFrom}, {@code isSupportedBy} or {@code rangeRefinedBy}. + * Before querying any field, implementations must ensure it is supported, as + * exceptions of this type would negatively affect the calculation of a parsed result. + *

      + * If this field can resolve, it must return a map, if not it must return null. + * The returned map contains the changes to be made to the temporal, expressed + * as field-value pairs. If the value for a field is null, the field is to be + * removed from the temporal. A null key must not be added to the result map. + *

      + * If the result is non-null, this field will be removed from the temporal. + * This field should not be added to the result map. + *

      + * The default implementation must return null. * - * @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 + * @param temporal the temporal to resolve, not null + * @param value the value of this field + * @return a map of fields to update in the temporal, with a mapping to null + * indicating a deletion. The whole map must be null if no resolving occurred + * @throws DateTimeException if resolving results in an error. This must not be thrown + * by querying a field on the temporal without first checking if it is supported + * @throws ArithmeticException if numeric overflow occurs */ - boolean resolve(DateTimeBuilder builder, long value); + public default Map resolve(TemporalAccessor temporal, long value) { + return null; + } } diff --git a/jdk/src/share/classes/java/time/temporal/TemporalQuery.java b/jdk/src/share/classes/java/time/temporal/TemporalQuery.java index a31964567b4..40b3943e740 100644 --- a/jdk/src/share/classes/java/time/temporal/TemporalQuery.java +++ b/jdk/src/share/classes/java/time/temporal/TemporalQuery.java @@ -98,6 +98,7 @@ import java.time.DateTimeException; * * @since 1.8 */ +@FunctionalInterface public interface TemporalQuery { /** @@ -128,7 +129,7 @@ public interface TemporalQuery { *

      * 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}. + * or reject non-ISO temporal objects by {@link Queries#chronology() querying the chronology}. *

      * This method may be called from multiple threads in parallel. * It must be thread-safe when invoked. diff --git a/jdk/src/share/classes/java/time/temporal/TemporalSubtractor.java b/jdk/src/share/classes/java/time/temporal/TemporalSubtractor.java deleted file mode 100644 index 4da8f30bea4..00000000000 --- a/jdk/src/share/classes/java/time/temporal/TemporalSubtractor.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * 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 index 7c8a32b4a3d..2f117fc2f16 100644 --- a/jdk/src/share/classes/java/time/temporal/TemporalUnit.java +++ b/jdk/src/share/classes/java/time/temporal/TemporalUnit.java @@ -75,7 +75,7 @@ import java.time.Period; * 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}. + * 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 @@ -105,6 +105,7 @@ public interface TemporalUnit { * Gets the duration of this unit, which may be an estimate. *

      * All units return a duration measured in standard nanoseconds from this method. + * The duration will be positive and non-zero. * 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. @@ -142,7 +143,7 @@ public interface TemporalUnit { * @param temporal the temporal object to check, not null * @return true if the unit is supported */ - public default boolean isSupported(Temporal temporal) { + public default boolean isSupportedBy(Temporal temporal) { try { temporal.plus(1, this); return true; @@ -169,7 +170,7 @@ public interface TemporalUnit { * 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 = thisUnit.addTo(temporal);
            *   temporal = temporal.plus(thisUnit);
            * 
      * It is recommended to use the second approach, {@code plus(TemporalUnit)}, @@ -177,42 +178,68 @@ public interface TemporalUnit { *

      * 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. + * If the unit 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 + * @param temporal the temporal object to adjust, not null + * @param amount the amount 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); + R addTo(R temporal, long amount); //----------------------------------------------------------------------- /** - * Calculates the period in terms of this unit between two temporal objects of the same type. + * 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. + * This calculates the period between two temporals in terms of this unit. + * The start and end points are supplied as temporal objects and must be + * of the same type. + * 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 HOURS.between(startTime, endTime)}. *

      - * The result can be queried for the {@link SimplePeriod#getAmount() amount}, the - * {@link SimplePeriod#getUnit() unit} and used directly in addition/subtraction: + * 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. + *

      + * There are two equivalent ways of using this method. + * The first is to invoke this method directly. + * The second is to use {@link Temporal#periodUntil(Temporal, TemporalUnit)}: *

      -     *  date = date.minus(MONTHS.between(start, end));
      +     *   // these two lines are equivalent
      +     *   temporal = thisUnit.between(start, end);
      +     *   temporal = start.periodUntil(end, thisUnit);
            * 
      + * The choice should be made based on which makes the code more readable. + *

      + * For example, this method allows the number of days between two dates to + * be calculated: + *

      +     *  long daysBetween = DAYS.between(start, end);
      +     *  // or alternatively
      +     *  long daysBetween = start.periodUntil(end, DAYS);
      +     * 
      + *

      + * Implementations should perform any queries or calculations using the units + * available in {@link ChronoUnit} or the fields available in {@link ChronoField}. + * If the unit is not supported a {@code DateTimeException} must be thrown. + * Implementations must not alter the specified temporal objects. * - * @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 + * @param temporal1 the base temporal object, not null + * @param temporal2 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 + * positive if datetime2 is later than datetime1, negative if earlier + * @throws DateTimeException if the period cannot be calculated + * @throws ArithmeticException if numeric overflow occurs */ - SimplePeriod between(R dateTime1, R dateTime2); + long between(Temporal temporal1, Temporal temporal2); //----------------------------------------------------------------------- /** diff --git a/jdk/src/share/classes/java/time/temporal/WeekFields.java b/jdk/src/share/classes/java/time/temporal/WeekFields.java index 364aa91798e..b9d7c15f30e 100644 --- a/jdk/src/share/classes/java/time/temporal/WeekFields.java +++ b/jdk/src/share/classes/java/time/temporal/WeekFields.java @@ -61,15 +61,30 @@ */ 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.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.MONTHS; +import static java.time.temporal.ChronoUnit.WEEKS; +import static java.time.temporal.ChronoUnit.YEARS; + import java.io.InvalidObjectException; import java.io.Serializable; import java.time.DayOfWeek; -import java.time.format.DateTimeBuilder; -import java.util.GregorianCalendar; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.Chronology; +import java.util.Collections; +import java.util.HashMap; import java.util.Locale; +import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import sun.util.locale.provider.CalendarDataUtility; /** * Localized definitions of the day-of-week, week-of-month and week-of-year fields. @@ -135,8 +150,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] + // allow week-of-month outer range [0 to 6] + // allow week-of-year outer range [0 to 54] // this is because callers shouldn't be expected to know the details of validity /** @@ -209,12 +224,9 @@ public final class WeekFields implements Serializable { 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(); + int calDow = CalendarDataUtility.retrieveFirstDayOfWeek(locale); DayOfWeek dow = DayOfWeek.SUNDAY.plus(calDow - 1); - int minDays = gcal.getMinimalDaysInFirstWeek(); + int minDays = CalendarDataUtility.retrieveMinimalDaysInFirstWeek(locale); return WeekFields.of(dow, minDays); } @@ -437,8 +449,7 @@ public final class WeekFields implements Serializable { * 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); + return new ComputedDayOfField("DayOfWeek", weekDef, DAYS, WEEKS, DAY_OF_WEEK_RANGE); } /** @@ -447,8 +458,7 @@ public final class WeekFields implements Serializable { * @see WeekFields#weekOfMonth() */ static ComputedDayOfField ofWeekOfMonthField(WeekFields weekDef) { - return new ComputedDayOfField("WeekOfMonth", weekDef, - ChronoUnit.WEEKS, ChronoUnit.MONTHS, WEEK_OF_MONTH_RANGE); + return new ComputedDayOfField("WeekOfMonth", weekDef, WEEKS, MONTHS, WEEK_OF_MONTH_RANGE); } /** @@ -457,8 +467,7 @@ public final class WeekFields implements Serializable { * @see WeekFields#weekOfYear() */ static ComputedDayOfField ofWeekOfYearField(WeekFields weekDef) { - return new ComputedDayOfField("WeekOfYear", weekDef, - ChronoUnit.WEEKS, ChronoUnit.YEARS, WEEK_OF_YEAR_RANGE); + return new ComputedDayOfField("WeekOfYear", weekDef, WEEKS, YEARS, WEEK_OF_YEAR_RANGE); } private final String name; private final WeekFields weekDef; @@ -475,31 +484,43 @@ public final class WeekFields implements Serializable { } 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); + private static final ValueRange WEEK_OF_MONTH_RANGE = ValueRange.of(0, 1, 4, 6); + private static final ValueRange WEEK_OF_YEAR_RANGE = ValueRange.of(0, 1, 52, 54); @Override - public long doGet(TemporalAccessor temporal) { + public long getFrom(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; + int dow = localizedDayOfWeek(temporal, sow); - if (rangeUnit == ChronoUnit.WEEKS) { + if (rangeUnit == WEEKS) { // day-of-week 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 if (rangeUnit == MONTHS) { // week-of-month + return localizedWeekOfMonth(temporal, dow); + } else if (rangeUnit == YEARS) { // week-of-year + return localizedWeekOfYear(temporal, dow); } else { throw new IllegalStateException("unreachable"); } } + private int localizedDayOfWeek(TemporalAccessor temporal, int sow) { + int isoDow = temporal.get(DAY_OF_WEEK); + return Math.floorMod(isoDow - sow, 7) + 1; + } + + private long localizedWeekOfMonth(TemporalAccessor temporal, int dow) { + int dom = temporal.get(DAY_OF_MONTH); + int offset = startOfWeekOffset(dom, dow); + return computeWeek(offset, dom); + } + + private long localizedWeekOfYear(TemporalAccessor temporal, int dow) { + int doy = temporal.get(DAY_OF_YEAR); + int offset = startOfWeekOffset(doy, dow); + return computeWeek(offset, doy); + } + /** * Returns an offset to align week start with a day of month or day of year. * @@ -530,59 +551,62 @@ public final class WeekFields implements Serializable { return ((7 + offset + (day - 1)) / 7); } + @SuppressWarnings("unchecked") @Override - public R doWith(R temporal, long newValue) { + public R adjustInto(R temporal, long newValue) { // Check the new value and get the old value of the field - int newVal = range.checkValidIntValue(newValue, this); + int newVal = range.checkValidIntValue(newValue, this); // lenient check range 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); + return (R) temporal.plus(newVal - currentVal, baseUnit); } @Override - public boolean resolve(DateTimeBuilder builder, long value) { + public Map resolve(TemporalAccessor temporal, 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; + if (rangeUnit == WEEKS) { // day-of-week + int isoDow = Math.floorMod((sow - 1) + (newValue - 1), 7) + 1; + return Collections.singletonMap(DAY_OF_WEEK, (long) isoDow); + } + if ((temporal.isSupported(YEAR) && temporal.isSupported(DAY_OF_WEEK)) == false) { + return null; + } + int dow = localizedDayOfWeek(temporal, sow); + int year = temporal.get(YEAR); + Chronology chrono = Chronology.from(temporal); // defaults to ISO + if (rangeUnit == MONTHS) { // week-of-month + if (temporal.isSupported(MONTH_OF_YEAR) == false) { + return null; + } + int month = temporal.get(ChronoField.MONTH_OF_YEAR); + ChronoLocalDate date = chrono.date(year, month, 1); + int dateDow = localizedDayOfWeek(date, sow); + long weeks = newValue - localizedWeekOfMonth(date, dateDow); + int days = dow - dateDow; + date = date.plus(weeks * 7 + days, DAYS); + Map result = new HashMap<>(4, 1.0f); + result.put(EPOCH_DAY, date.toEpochDay()); + result.put(YEAR, null); + result.put(MONTH_OF_YEAR, null); + result.put(DAY_OF_WEEK, null); + return result; + } else if (rangeUnit == YEARS) { // week-of-year + ChronoLocalDate date = chrono.date(year, 1, 1); + int dateDow = localizedDayOfWeek(date, sow); + long weeks = newValue - localizedWeekOfYear(date, dateDow); + int days = dow - dateDow; + date = date.plus(weeks * 7 + days, DAYS); + Map result = new HashMap<>(4, 1.0f); + result.put(EPOCH_DAY, date.toEpochDay()); + result.put(YEAR, null); + result.put(DAY_OF_WEEK, null); + return result; } 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; + throw new IllegalStateException("unreachable"); } } @@ -607,46 +631,39 @@ public final class WeekFields implements Serializable { 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) { + public boolean isSupportedBy(TemporalAccessor temporal) { + if (temporal.isSupported(DAY_OF_WEEK)) { + if (rangeUnit == WEEKS) { // day-of-week 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); + } else if (rangeUnit == MONTHS) { // week-of-month + return temporal.isSupported(DAY_OF_MONTH); + } else if (rangeUnit == YEARS) { // week-of-year + return temporal.isSupported(DAY_OF_YEAR); } } return false; } @Override - public ValueRange doRange(TemporalAccessor temporal) { - if (rangeUnit == ChronoUnit.WEEKS) { + public ValueRange rangeRefinedBy(TemporalAccessor temporal) { + if (rangeUnit == ChronoUnit.WEEKS) { // day-of-week return range; } TemporalField field = null; - if (rangeUnit == ChronoUnit.MONTHS) { - field = ChronoField.DAY_OF_MONTH; - } else if (rangeUnit == ChronoUnit.YEARS) { - field = ChronoField.DAY_OF_YEAR; + if (rangeUnit == MONTHS) { // week-of-month + field = DAY_OF_MONTH; + } else if (rangeUnit == YEARS) { // week-of-year + field = 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 dow = localizedDayOfWeek(temporal, sow); int offset = startOfWeekOffset(temporal.get(field), dow); ValueRange fieldRange = temporal.range(field); diff --git a/jdk/src/share/classes/java/time/temporal/package-info.java b/jdk/src/share/classes/java/time/temporal/package-info.java index da9a4b702e8..d769120f4fd 100644 --- a/jdk/src/share/classes/java/time/temporal/package-info.java +++ b/jdk/src/share/classes/java/time/temporal/package-info.java @@ -62,8 +62,7 @@ /** *

      - * Access to date and time using fields and units, additional value type classes and - * base support for calendar systems other than the default ISO. + * Access to date and time using fields and units, and date time adjusters. *

      *

      * This package expands on the base package to provide additional functionality for @@ -74,8 +73,6 @@ *

    • 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

      @@ -91,7 +88,7 @@ * 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}. + * and {@link java.time.temporal.IsoFields}. * The field interface is designed to allow applications defined fields. *

      *

      @@ -122,8 +119,7 @@ * 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}. + * The {@link java.time.temporal.TemporalAmount} interface models amounts of relative time. *

      *

      * In addition to adjusting a date-time, an interface is provided to enable querying - @@ -144,60 +140,9 @@ *

      * 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}. + * 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 diff --git a/jdk/src/share/classes/java/time/zone/TzdbZoneRulesProvider.java b/jdk/src/share/classes/java/time/zone/TzdbZoneRulesProvider.java index ed81a06dae2..22f6ffddd24 100644 --- a/jdk/src/share/classes/java/time/zone/TzdbZoneRulesProvider.java +++ b/jdk/src/share/classes/java/time/zone/TzdbZoneRulesProvider.java @@ -66,43 +66,36 @@ 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.List; +import java.util.Map; 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.concurrent.ConcurrentHashMap; 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<>(); + private List regionIds; /** - * All the versions that are available. + * Version Id of this tzdb rules */ - private final ConcurrentNavigableMap versions = new ConcurrentSkipListMap<>(); + private String versionId; + /** + * Region to rules mapping + */ + private final Map regionToRules = new ConcurrentHashMap<>(); /** * Creates an instance. @@ -111,94 +104,61 @@ final class TzdbZoneRulesProvider extends ZoneRulesProvider { * @throws ZoneRulesException if unable to load */ public TzdbZoneRulesProvider() { - super(); - if (load(ClassLoader.getSystemClassLoader()) == false) { - throw new ZoneRulesException("No time-zone rules found for 'TZDB'"); + try { + String libDir = System.getProperty("java.home") + File.separator + "lib"; + File tzdbJar = new File(libDir, "tzdb.jar"); + try (ZipFile zf = new ZipFile(tzdbJar); + DataInputStream dis = new DataInputStream( + zf.getInputStream(zf.getEntry("TZDB.dat")))) { + load(dis); + } + } catch (Exception ex) { + throw new ZoneRulesException("Unable to load TZDB time-zone rules", ex); } } - //----------------------------------------------------------------------- @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) { + protected ZoneRules provideRules(String zoneId, boolean forCaching) { + // forCaching flag is ignored because this is not a dynamic provider + Object obj = regionToRules.get(zoneId); + if (obj == null) { throw new ZoneRulesException("Unknown time-zone ID: " + zoneId); } - return rules; + try { + if (obj instanceof byte[]) { + byte[] bytes = (byte[]) obj; + DataInputStream dis = new DataInputStream(new ByteArrayInputStream(bytes)); + obj = Ser.read(dis); + regionToRules.put(zoneId, obj); + } + return (ZoneRules) obj; + } catch (Exception ex) { + throw new ZoneRulesException("Invalid binary time-zone data: TZDB:" + zoneId + ", version: " + versionId, ex); + } } @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); - } + ZoneRules rules = getRules(zoneId, false); + if (rules != null) { + map.put(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 { + private void load(DataInputStream dis) throws Exception { if (dis.readByte() != 1) { throw new StreamCorruptedException("File format not recognised"); } @@ -209,9 +169,8 @@ final class TzdbZoneRulesProvider extends ZoneRulesProvider { } // versions int versionCount = dis.readShort(); - String[] versionArray = new String[versionCount]; for (int i = 0; i < versionCount; i++) { - versionArray[i] = dis.readUTF(); + versionId = dis.readUTF(); } // regions int regionCount = dis.readShort(); @@ -219,7 +178,7 @@ final class TzdbZoneRulesProvider extends ZoneRulesProvider { for (int i = 0; i < regionCount; i++) { regionArray[i] = dis.readUTF(); } - regionIds.addAll(Arrays.asList(regionArray)); + regionIds = Arrays.asList(regionArray); // rules int ruleCount = dis.readShort(); Object[] ruleArray = new Object[ruleCount]; @@ -228,71 +187,20 @@ final class TzdbZoneRulesProvider extends ZoneRulesProvider { 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]; + regionToRules.clear(); for (int j = 0; j < versionRegionCount; j++) { - versionRegionArray[j] = regionArray[dis.readShort()]; - versionRulesArray[j] = dis.readShort(); + String region = regionArray[dis.readShort()]; + Object rule = ruleArray[dis.readShort() & 0xffff]; + regionToRules.put(region, rule); } - versionSet.add(new Version(versionArray[i], versionRegionArray, versionRulesArray, ruleData)); } - return versionSet; } @Override public String toString() { - return "TZDB"; + return "TZDB[" + versionId + "]"; } - - //----------------------------------------------------------------------- - /** - * 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/ZoneOffsetTransitionRule.java b/jdk/src/share/classes/java/time/zone/ZoneOffsetTransitionRule.java index 4b6f7e90722..5275d18417b 100644 --- a/jdk/src/share/classes/java/time/zone/ZoneOffsetTransitionRule.java +++ b/jdk/src/share/classes/java/time/zone/ZoneOffsetTransitionRule.java @@ -74,7 +74,7 @@ import java.time.LocalDateTime; import java.time.LocalTime; import java.time.Month; import java.time.ZoneOffset; -import java.time.temporal.ISOChrono; +import java.time.chrono.IsoChronology; import java.util.Objects; /** @@ -430,7 +430,7 @@ public final class ZoneOffsetTransitionRule implements Serializable { public ZoneOffsetTransition createTransition(int year) { LocalDate date; if (dom < 0) { - date = LocalDate.of(year, month, month.length(ISOChrono.INSTANCE.isLeapYear(year)) + 1 + dom); + date = LocalDate.of(year, month, month.length(IsoChronology.INSTANCE.isLeapYear(year)) + 1 + dom); if (dow != null) { date = date.with(previousOrSame(dow)); } diff --git a/jdk/src/share/classes/java/time/zone/ZoneRules.java b/jdk/src/share/classes/java/time/zone/ZoneRules.java index 159d6e0d36a..fa7498c858f 100644 --- a/jdk/src/share/classes/java/time/zone/ZoneRules.java +++ b/jdk/src/share/classes/java/time/zone/ZoneRules.java @@ -71,7 +71,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZoneOffset; -import java.time.temporal.Year; +import java.time.Year; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; diff --git a/jdk/src/share/classes/java/time/zone/ZoneRulesProvider.java b/jdk/src/share/classes/java/time/zone/ZoneRulesProvider.java index 2c187a7e32e..d3e906d3937 100644 --- a/jdk/src/share/classes/java/time/zone/ZoneRulesProvider.java +++ b/jdk/src/share/classes/java/time/zone/ZoneRulesProvider.java @@ -61,11 +61,11 @@ */ package java.time.zone; -import java.time.DateTimeException; +import java.security.AccessController; +import java.security.PrivilegedAction; 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; @@ -85,6 +85,25 @@ import java.util.concurrent.CopyOnWriteArrayList; * 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. *

      + * ZoneRulesProvider may be installed in an instance of the Java Platform as + * extension classes, that is, jar files placed into any of the usual extension + * directories. Installed providers are loaded using the service-provider loading + * facility defined by the {@link ServiceLoader} class. A ZoneRulesProvider + * identifies itself with a provider configuration file named + * {@code java.time.zone.ZoneRulesProvider} in the resource directory + * {@code META-INF/services}. The file should contain a line that specifies the + * fully qualified concrete zonerules-provider class name. + * Providers may also be made available by adding them to the class path or by + * registering themselves via {@link #registerProvider} method. + *

      + * The Java virtual machine has a default provider that provides zone rules + * for the time-zones defined by IANA Time Zone Database (TZDB). If the system + * property {@code java.time.zone.DefaultZoneRulesProvider} is defined then + * it is taken to be the fully-qualified name of a concrete ZoneRulesProvider + * class to be loaded as the default provider, using the system class loader. + * If this system property is not defined, a system-default provider will be + * loaded to serve as the default provider. + *

      * 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. *

      @@ -99,6 +118,8 @@ import java.util.concurrent.CopyOnWriteArrayList; * Providers must ensure that once a rule has been seen by the application, the * rule must continue to be available. *

      +* Providers are encouraged to implement a meaningful {@code toString} method. + *

      * 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. @@ -112,13 +133,34 @@ public abstract class ZoneRulesProvider { */ private static final CopyOnWriteArrayList PROVIDERS = new CopyOnWriteArrayList<>(); /** - * The lookup from zone region ID to provider. + * The lookup from zone ID to provider. */ private static final ConcurrentMap ZONES = new ConcurrentHashMap<>(512, 0.75f, 2); + static { - registerProvider(new TzdbZoneRulesProvider()); + // if the property java.time.zone.DefaultZoneRulesProvider is + // set then its value is the class name of the default provider + final List loaded = new ArrayList<>(); + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + String prop = System.getProperty("java.time.zone.DefaultZoneRulesProvider"); + if (prop != null) { + try { + Class c = Class.forName(prop, true, ClassLoader.getSystemClassLoader()); + ZoneRulesProvider provider = ZoneRulesProvider.class.cast(c.newInstance()); + registerProvider(provider); + loaded.add(provider); + } catch (Exception x) { + throw new Error(x); + } + } else { + registerProvider(new TzdbZoneRulesProvider()); + } + return null; + } + }); + ServiceLoader sl = ServiceLoader.load(ZoneRulesProvider.class, ClassLoader.getSystemClassLoader()); - List loaded = new ArrayList<>(); Iterator it = sl.iterator(); while (it.hasNext()) { ZoneRulesProvider provider; @@ -130,7 +172,16 @@ public abstract class ZoneRulesProvider { } throw ex; } - registerProvider0(provider); + boolean found = false; + for (ZoneRulesProvider p : loaded) { + if (p.getClass() == provider.getClass()) { + found = true; + } + } + if (!found) { + registerProvider0(provider); + loaded.add(provider); + } } // CopyOnWriteList could be slow if lots of providers and each added individually PROVIDERS.addAll(loaded); @@ -140,7 +191,7 @@ public abstract class ZoneRulesProvider { /** * Gets the set of available zone IDs. *

      - * These zone IDs are loaded and available for use by {@code ZoneId}. + * These IDs are the string form of a {@link ZoneId}. * * @return a modifiable copy of the set of zone IDs, not null */ @@ -155,14 +206,25 @@ public abstract class ZoneRulesProvider { *

      * This method relies on time-zone data provider files that are configured. * These are loaded using a {@code ServiceLoader}. + *

      + * The caching flag is designed to allow provider implementations to + * prevent the rules being cached in {@code ZoneId}. + * Under normal circumstances, the caching of zone rules is highly desirable + * as it will provide greater performance. However, there is a use case where + * the caching would not be desirable, see {@link #provideRules}. * - * @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 + * @param zoneId the zone ID as defined by {@code ZoneId}, not null + * @param forCaching whether the rules are being queried for caching, + * true if the returned rules will be cached by {@code ZoneId}, + * false if they will be returned to the user without being cached in {@code ZoneId} + * @return the rules, null if {@code forCaching} is true and this + * is a dynamic provider that wants to prevent caching in {@code ZoneId}, + * otherwise not null + * @throws ZoneRulesException if rules cannot be obtained for the zone ID */ - public static ZoneRules getRules(String zoneId) { + public static ZoneRules getRules(String zoneId, boolean forCaching) { Objects.requireNonNull(zoneId, "zoneId"); - return getProvider(zoneId).provideRules(zoneId); + return getProvider(zoneId).provideRules(zoneId, forCaching); } /** @@ -184,10 +246,10 @@ public abstract class ZoneRulesProvider { * 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 + * @param zoneId the zone ID as defined 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 + * @throws ZoneRulesException if history cannot be obtained for the zone ID */ public static NavigableMap getVersions(String zoneId) { Objects.requireNonNull(zoneId, "zoneId"); @@ -197,7 +259,7 @@ public abstract class ZoneRulesProvider { /** * Gets the provider for the zone ID. * - * @param zoneId the zone region ID as used by {@code ZoneId}, not null + * @param zoneId the zone ID as defined by {@code ZoneId}, not null * @return the provider, not null * @throws ZoneRulesException if the zone ID is unknown */ @@ -226,7 +288,7 @@ public abstract class ZoneRulesProvider { * to deregister providers. * * @param provider the provider to register, not null - * @throws ZoneRulesException if a region is already registered + * @throws ZoneRulesException if a zone ID is already registered */ public static void registerProvider(ZoneRulesProvider provider) { Objects.requireNonNull(provider, "provider"); @@ -243,7 +305,7 @@ public abstract class ZoneRulesProvider { private static void registerProvider0(ZoneRulesProvider provider) { for (String zoneId : provider.provideZoneIds()) { Objects.requireNonNull(zoneId, "zoneId"); - ZoneRulesProvider old = ZONES.putIfAbsent(zoneId, provider.provideBind(zoneId)); + ZoneRulesProvider old = ZONES.putIfAbsent(zoneId, provider); if (old != null) { throw new ZoneRulesException( "Unable to register zone as one already registered with that ID: " + zoneId + @@ -252,17 +314,25 @@ public abstract class ZoneRulesProvider { } } - //------------------------------------------------------------------------- /** * 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. + * This method allows an application to request that the providers check + * for any updates to the provided rules. * 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. + * Dynamic update of rules is a complex problem and most applications + * should not use this method or dynamic rules. + * To achieve dynamic rules, a provider implementation will have to be written + * as per the specification of this class. + * In addition, instances of {@code ZoneRules} must not be cached in the + * application as they will become stale. However, the boolean flag on + * {@link #provideRules(String, boolean)} allows provider implementations + * to control the caching of {@code ZoneId}, potentially ensuring that + * all objects in the system see the new rules. + * Note that there is likely to be a cost in performance of a dynamic rules + * provider. Note also that no dynamic rules provider is in this specification. * * @return true if the rules were updated * @throws ZoneRulesException if an error occurs during the refresh @@ -275,7 +345,6 @@ public abstract class ZoneRulesProvider { return changed; } - //----------------------------------------------------------------------- /** * Constructor. */ @@ -287,49 +356,43 @@ public abstract class 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. + * A provider should provide data for at least one zone ID. *

      - * 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. + * The returned zone IDs remain available and valid for the lifetime of the application. + * A dynamic provider may increase the set of IDs as more data becomes available. * - * @return the unmodifiable set of region IDs being provided, not null + * @return the set of zone IDs being provided, not null + * @throws ZoneRulesException if a problem occurs while providing the IDs */ 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. + * This loads the rules for the specified zone ID. + * The provider implementation must validate that the zone ID is valid and + * available, throwing a {@code ZoneRulesException} if it is not. + * The result of the method in the valid case depends on the caching flag. + *

      + * If the provider implementation is not dynamic, then the result of the + * method must be the non-null set of rules selected by the ID. + *

      + * If the provider implementation is dynamic, then the flag gives the option + * of preventing the returned rules from being cached in {@link ZoneId}. + * When the flag is true, the provider is permitted to return null, where + * null will prevent the rules from being cached in {@code ZoneId}. + * When the flag is false, the provider must return non-null rules. * - * @param regionId the time-zone region ID, not null - * @return the rules, not null - * @throws DateTimeException if rules cannot be obtained + * @param zoneId the zone ID as defined by {@code ZoneId}, not null + * @param forCaching whether the rules are being queried for caching, + * true if the returned rules will be cached by {@code ZoneId}, + * false if they will be returned to the user without being cached in {@code ZoneId} + * @return the rules, null if {@code forCaching} is true and this + * is a dynamic provider that wants to prevent caching in {@code ZoneId}, + * otherwise not null + * @throws ZoneRulesException if rules cannot be obtained for the zone ID */ - protected abstract ZoneRules provideRules(String regionId); + protected abstract ZoneRules provideRules(String zoneId, boolean forCaching); /** * SPI method to get the history of rules for the zone ID. @@ -343,16 +406,16 @@ public abstract class ZoneRulesProvider { *

      * 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. + * Thus the map will contain at least 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 + * @param zoneId the zone ID as defined 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 + * @throws ZoneRulesException if history cannot be obtained for the zone ID */ protected abstract NavigableMap provideVersions(String zoneId); @@ -367,46 +430,10 @@ public abstract class ZoneRulesProvider { * This implementation returns false. * * @return true if the rules were updated - * @throws DateTimeException if an error occurs during the refresh + * @throws ZoneRulesException 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/util/Base64.java b/jdk/src/share/classes/java/util/Base64.java index f5ff211f8d4..88b17406799 100644 --- a/jdk/src/share/classes/java/util/Base64.java +++ b/jdk/src/share/classes/java/util/Base64.java @@ -64,7 +64,8 @@ import java.nio.charset.StandardCharsets; * RFC 2045 for encoding and decoding operation. The encoded output * must be represented in lines of no more than 76 characters each * and uses a carriage return {@code '\r'} followed immediately by - * a linefeed {@code '\n'} as the line separator. All line separators + * a linefeed {@code '\n'} as the line separator. No line separator + * is added to the end of the encoded output. All line separators * or other characters not found in the base64 alphabet table are * ignored in decoding operation.

      * @@ -413,6 +414,7 @@ public class Base64 { * specified Base64 encoded format */ public OutputStream wrap(OutputStream os) { + Objects.requireNonNull(os); return new EncOutputStream(os, isURL ? toBase64URL : toBase64, newline, linemax); } @@ -613,6 +615,13 @@ public class Base64 { * This class implements a decoder for decoding byte data using the * Base64 encoding scheme as specified in RFC 4648 and RFC 2045. * + *

      The Base64 padding character {@code '='} is accepted and + * interpreted as the end of the encoded byte data, but is not + * required. So if the final unit of the encoded byte data only has + * two or three Base64 characters (without the corresponding padding + * character(s) padded), they are decoded as if followed by padding + * character(s). + * *

      Instances of {@link Decoder} class are safe for use by * multiple concurrent threads. * @@ -695,7 +704,7 @@ public class Base64 { * using the {@link Base64} encoding scheme. * *

      An invocation of this method has exactly the same effect as invoking - * {@code return decode(src.getBytes(StandardCharsets.ISO_8859_1))} + * {@code decode(src.getBytes(StandardCharsets.ISO_8859_1))} * * @param src * the string to decode @@ -856,6 +865,9 @@ public class Base64 { /** * Returns an input stream for decoding {@link Base64} encoded byte stream. * + *

      The {@code read} methods of the returned {@code InputStream} will + * throw {@code IOException} when reading bytes that cannot be decoded. + * *

      Closing the returned input stream will close the underlying * input stream. * @@ -866,6 +878,7 @@ public class Base64 { * byte stream */ public InputStream wrap(InputStream is) { + Objects.requireNonNull(is); return new DecInputStream(is, isURL ? fromBase64URL : fromBase64, isMIME); } @@ -881,13 +894,16 @@ public class Base64 { int dl = dst.arrayOffset() + dst.limit(); int dp0 = dp; int mark = sp; - boolean padding = false; try { while (sp < sl) { int b = sa[sp++] & 0xff; if ((b = base64[b]) < 0) { if (b == -2) { // padding byte - padding = true; + if (shiftto == 6 && (sp == sl || sa[sp++] != '=') || + shiftto == 18) { + throw new IllegalArgumentException( + "Input byte array has wrong 4-byte ending unit"); + } break; } if (isMIME) // skip if for rfc2045 @@ -913,24 +929,23 @@ public class Base64 { if (shiftto == 6) { if (dl - dp < 1) return dp - dp0; - if (padding && (sp + 1 != sl || sa[sp++] != '=')) - throw new IllegalArgumentException( - "Input buffer has wrong 4-byte ending unit"); da[dp++] = (byte)(bits >> 16); - mark = sp; } else if (shiftto == 0) { if (dl - dp < 2) return dp - dp0; - if (padding && sp != sl) - throw new IllegalArgumentException( - "Input buffer has wrong 4-byte ending unit"); da[dp++] = (byte)(bits >> 16); da[dp++] = (byte)(bits >> 8); - mark = sp; - } else if (padding || shiftto != 18) { + } else if (shiftto == 12) { throw new IllegalArgumentException( "Last unit does not have enough valid bits"); } + while (sp < sl) { + if (isMIME && base64[sa[sp++]] < 0) + continue; + throw new IllegalArgumentException( + "Input byte array has incorrect ending byte at " + sp); + } + mark = sp; return dp - dp0; } finally { src.position(mark); @@ -948,14 +963,16 @@ public class Base64 { int dl = dst.limit(); int dp0 = dp; int mark = sp; - boolean padding = false; - try { while (sp < sl) { int b = src.get(sp++) & 0xff; if ((b = base64[b]) < 0) { if (b == -2) { // padding byte - padding = true; + if (shiftto == 6 && (sp == sl || src.get(sp++) != '=') || + shiftto == 18) { + throw new IllegalArgumentException( + "Input byte array has wrong 4-byte ending unit"); + } break; } if (isMIME) // skip if for rfc2045 @@ -981,24 +998,23 @@ public class Base64 { if (shiftto == 6) { if (dl - dp < 1) return dp - dp0; - if (padding && (sp + 1 != sl || src.get(sp++) != '=')) - throw new IllegalArgumentException( - "Input buffer has wrong 4-byte ending unit"); dst.put(dp++, (byte)(bits >> 16)); - mark = sp; } else if (shiftto == 0) { if (dl - dp < 2) return dp - dp0; - if (padding && sp != sl) - throw new IllegalArgumentException( - "Input buffer has wrong 4-byte ending unit"); dst.put(dp++, (byte)(bits >> 16)); dst.put(dp++, (byte)(bits >> 8)); - mark = sp; - } else if (padding || shiftto != 18) { + } else if (shiftto == 12) { throw new IllegalArgumentException( "Last unit does not have enough valid bits"); } + while (sp < sl) { + if (isMIME && base64[src.get(sp++)] < 0) + continue; + throw new IllegalArgumentException( + "Input byte array has incorrect ending byte at " + sp); + } + mark = sp; return dp - dp0; } finally { src.position(mark); @@ -1012,9 +1028,12 @@ public class Base64 { int len = sl - sp; if (len == 0) return 0; - if (len < 2) + if (len < 2) { + if (isMIME && base64[0] == -1) + return 0; throw new IllegalArgumentException( "Input byte[] should at least have 2 bytes for base64 bytes"); + } if (src[sl - 1] == '=') { paddings++; if (src[sl - 2] == '=') @@ -1043,12 +1062,20 @@ public class Base64 { int dp = 0; int bits = 0; int shiftto = 18; // pos of first byte of 4-byte atom - boolean padding = false; while (sp < sl) { int b = src[sp++] & 0xff; if ((b = base64[b]) < 0) { - if (b == -2) { // padding byte - padding = true; + if (b == -2) { // padding byte '=' + // xx= shiftto==6&&sp==sl missing last = + // xx=y shiftto==6 last is not = + // = shiftto==18 unnecessary padding + // x= shiftto==12 be taken care later + // together with single x, invalid anyway + if (shiftto == 6 && (sp == sl || src[sp++] != '=') || + shiftto == 18) { + throw new IllegalArgumentException( + "Input byte array has wrong 4-byte ending unit"); + } break; } if (isMIME) // skip if for rfc2045 @@ -1068,22 +1095,23 @@ public class Base64 { bits = 0; } } - // reach end of byte arry or hit padding '=' characters. - // if '=' presents, they must be the last one or two. - if (shiftto == 6) { // xx== - if (padding && (sp + 1 != sl || src[sp] != '=')) - throw new IllegalArgumentException( - "Input byte array has wrong 4-byte ending unit"); + // reached end of byte array or hit padding '=' characters. + if (shiftto == 6) { dst[dp++] = (byte)(bits >> 16); - } else if (shiftto == 0) { // xxx= - if (padding && sp != sl) - throw new IllegalArgumentException( - "Input byte array has wrong 4-byte ending unit"); + } else if (shiftto == 0) { dst[dp++] = (byte)(bits >> 16); dst[dp++] = (byte)(bits >> 8); - } else if (padding || shiftto != 18) { - throw new IllegalArgumentException( - "last unit does not have enough bytes"); + } else if (shiftto == 12) { + throw new IllegalArgumentException( + "Last unit does not have enough valid bits"); + } + // anything left is invalid, if is not MIME. + // if MIME, ignore all non-base64 character + while (sp < sl) { + if (isMIME && base64[src[sp++]] < 0) + continue; + throw new IllegalArgumentException( + "Input byte array has incorrect ending byte at " + sp); } return dp; } @@ -1247,8 +1275,22 @@ public class Base64 { int v = is.read(); if (v == -1) { eof = true; - if (nextin != 18) - throw new IOException("Base64 stream has un-decoded dangling byte(s)."); + if (nextin != 18) { + if (nextin == 12) + throw new IOException("Base64 stream has one un-decoded dangling byte."); + // treat ending xx/xxx without padding character legal. + // same logic as v == 'v' below + b[off++] = (byte)(bits >> (16)); + len--; + if (nextin == 0) { // only one padding byte + if (len == 0) { // no enough output space + bits >>= 8; // shift to lowest byte + nextout = 0; + } else { + b[off++] = (byte) (bits >> 8); + } + } + } if (off == oldOff) return -1; else diff --git a/jdk/src/share/classes/java/util/Calendar.java b/jdk/src/share/classes/java/util/Calendar.java index 600da93ee52..f14ee6d6ef4 100644 --- a/jdk/src/share/classes/java/util/Calendar.java +++ b/jdk/src/share/classes/java/util/Calendar.java @@ -51,6 +51,7 @@ import java.security.PrivilegedExceptionAction; import java.security.ProtectionDomain; import java.text.DateFormat; import java.text.DateFormatSymbols; +import java.time.Instant; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import sun.util.BuddhistCalendar; @@ -3562,4 +3563,17 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable + * The conversion creates an {@code Instant} that represents the + * same point on the time-line as this {@code Calendar}. + * + * @return the instant representing the same point on the time-line + * @since 1.8 + */ + public final Instant toInstant() { + return Instant.ofEpochMilli(getTimeInMillis()); + } } diff --git a/jdk/src/share/classes/java/util/Comparator.java b/jdk/src/share/classes/java/util/Comparator.java index 453e9b71909..35ead373b82 100644 --- a/jdk/src/share/classes/java/util/Comparator.java +++ b/jdk/src/share/classes/java/util/Comparator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -98,7 +98,7 @@ package java.util; * @see java.io.Serializable * @since 1.2 */ - +@FunctionalInterface public interface Comparator { /** * Compares its two arguments for order. Returns a negative integer, diff --git a/jdk/src/share/classes/java/util/Date.java b/jdk/src/share/classes/java/util/Date.java index 77352094173..61dac350389 100644 --- a/jdk/src/share/classes/java/util/Date.java +++ b/jdk/src/share/classes/java/util/Date.java @@ -26,10 +26,12 @@ package java.util; import java.text.DateFormat; +import java.time.LocalDate; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.ObjectInputStream; import java.lang.ref.SoftReference; +import java.time.Instant; import sun.util.calendar.BaseCalendar; import sun.util.calendar.CalendarDate; import sun.util.calendar.CalendarSystem; @@ -1328,4 +1330,46 @@ public class Date { fastTime = s.readLong(); } + + /** + * Obtains an instance of {@code Date} from an {@code Instant} object. + *

      + * {@code Instant} uses a precision of nanoseconds, whereas {@code Date} + * uses a precision of milliseconds. The conversion will trancate any + * excess precision information as though the amount in nanoseconds was + * subject to integer division by one million. + *

      + * {@code Instant} can store points on the time-line further in the future + * and further in the past than {@code Date}. In this scenario, this method + * will throw an exception. + * + * @param instant the instant to convert + * @return a {@code Date} representing the same point on the time-line as + * the provided instant + * @exception NullPointerException if {@code instant} is null. + * @exception IllegalArgumentException if the instant is too large to + * represent as a {@code Date} + * @since 1.8 + */ + public static Date from(Instant instant) { + try { + return new Date(instant.toEpochMilli()); + } catch (ArithmeticException ex) { + throw new IllegalArgumentException(ex); + } + } + + /** + * Converts this {@code Date} object to an {@code Instant}. + *

      + * The conversion creates an {@code Instant} that represents the same + * point on the time-line as this {@code Date}. + * + * @return an instant representing the same point on the time-line as + * this {@code Date} object + * @since 1.8 + */ + public Instant toInstant() { + return Instant.ofEpochMilli(getTime()); + } } diff --git a/jdk/src/share/classes/java/util/Formatter.java b/jdk/src/share/classes/java/util/Formatter.java index f5f479588c1..c645861521c 100644 --- a/jdk/src/share/classes/java/util/Formatter.java +++ b/jdk/src/share/classes/java/util/Formatter.java @@ -50,7 +50,6 @@ 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; @@ -58,12 +57,6 @@ 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; @@ -351,7 +344,9 @@ import sun.misc.FormattedFloatingDecimal; * {@code 'a'}, {@code 'A'} * floating point * The result is formatted as a hexadecimal floating-point number with - * a significand and an exponent + * a significand and an exponent. This conversion is not supported + * for the {@code BigDecimal} type despite the latter's being in the + * floating point argument category. * * {@code 't'}, {@code 'T'} * date/time diff --git a/jdk/src/share/classes/java/util/GregorianCalendar.java b/jdk/src/share/classes/java/util/GregorianCalendar.java index 0142c518781..4e063ee70ba 100644 --- a/jdk/src/share/classes/java/util/GregorianCalendar.java +++ b/jdk/src/share/classes/java/util/GregorianCalendar.java @@ -40,6 +40,12 @@ package java.util; import java.io.IOException; import java.io.ObjectInputStream; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.chrono.IsoChronology; +import java.time.temporal.ChronoField; +import java.time.temporal.Queries; import sun.util.calendar.BaseCalendar; import sun.util.calendar.CalendarDate; import sun.util.calendar.CalendarSystem; @@ -3200,4 +3206,61 @@ public class GregorianCalendar extends Calendar { } setGregorianChange(gregorianCutover); } + + /** + * Converts this object to a {@code ZonedDateTime} that represents + * the same point on the time-line as this {@code GregorianCalendar}. + *

      + * Since this object supports a Julian-Gregorian cutover date and + * {@code ZonedDateTime} does not, it is possible that the resulting year, + * month and day will have different values. The result will represent the + * correct date in the ISO calendar system, which will also be the same value + * for Modified Julian Days. + * + * @return a zoned date-time representing the same point on the time-line + * as this gregorian calendar + * @since 1.8 + */ + public ZonedDateTime toZonedDateTime() { + return ZonedDateTime.ofInstant(Instant.ofEpochMilli(getTimeInMillis()), + getTimeZone().toZoneId()); + } + + /** + * Obtains an instance of {@code GregorianCalendar} with the default locale + * from a {@code ZonedDateTime} object. + *

      + * Since {@code ZonedDateTime} does not support a Julian-Gregorian cutover + * date and uses ISO calendar system, the return GregorianCalendar is a pure + * Gregorian calendar and uses ISO 8601 standard for week definitions, + * which has {@code MONDAY} as the {@link Calendar#getFirstDayOfWeek() + * FirstDayOfWeek} and {@code 4} as the value of the + * {@link Calendar#getMinimalDaysInFirstWeek() MinimalDaysInFirstWeek}. + *

      + * {@code ZoneDateTime} can store points on the time-line further in the + * future and further in the past than {@code GregorianCalendar}. In this + * scenario, this method will throw an {@code IllegalArgumentException} + * exception. + * + * @param zdt the zoned date-time object to convert + * @return the gregorian calendar representing the same point on the + * time-line as the zoned date-time provided + * @exception NullPointerException if {@code zdt} is null + * @exception IllegalArgumentException if the zoned date-time is too + * large to represent as a {@code GregorianCalendar} + * @since 1.8 + */ + public static GregorianCalendar from(ZonedDateTime zdt) { + GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone(zdt.getZone())); + cal.setGregorianChange(new Date(Long.MIN_VALUE)); + cal.setFirstDayOfWeek(MONDAY); + cal.setMinimalDaysInFirstWeek(4); + try { + cal.setTimeInMillis(Math.addExact(Math.multiplyExact(zdt.toEpochSecond(), 1000), + zdt.get(ChronoField.MILLI_OF_SECOND))); + } catch (ArithmeticException ex) { + throw new IllegalArgumentException(ex); + } + return cal; + } } diff --git a/jdk/src/share/classes/java/util/TimeZone.java b/jdk/src/share/classes/java/util/TimeZone.java index d79e201ce7a..66297c015b9 100644 --- a/jdk/src/share/classes/java/util/TimeZone.java +++ b/jdk/src/share/classes/java/util/TimeZone.java @@ -42,6 +42,7 @@ import java.io.Serializable; import java.lang.ref.SoftReference; import java.security.AccessController; import java.security.PrivilegedAction; +import java.time.ZoneId; import java.util.concurrent.ConcurrentHashMap; import sun.misc.JavaAWTAccess; import sun.misc.SharedSecrets; @@ -530,6 +531,37 @@ abstract public class TimeZone implements Serializable, Cloneable { return getTimeZone(ID, true); } + /** + * Gets the {@code TimeZone} for the given {@code zoneId}. + * + * @param zoneid a {@link ZoneId} from which the time zone ID is obtained + * @return the specified {@code TimeZone}, or the GMT zone if the given ID + * cannot be understood. + * @throws NullPointerException if {@code zoneId} is {@code null} + * @since 1.8 + */ + public static TimeZone getTimeZone(ZoneId zoneId) { + String tzid = zoneId.getId(); // throws an NPE if null + char c = tzid.charAt(0); + if (c == '+' || c == '-') { + tzid = "GMT" + tzid; + } else if (c == 'Z' && tzid.length() == 1) { + tzid = "UTC"; + } + return getTimeZone(tzid, true); + } + + /** + * Converts this {@code TimeZone} object to a {@code ZoneId}. + * + * @return a {@code ZoneId} representing the same time zone as this + * {@code TimeZone} + * @since 1.8 + */ + public ZoneId toZoneId() { + return ZoneId.of(getID(), ZoneId.OLD_IDS_POST_2005); + } + private static TimeZone getTimeZone(String ID, boolean fallback) { TimeZone tz = ZoneInfo.getTimeZone(ID); if (tz == null) { diff --git a/jdk/src/share/classes/java/util/concurrent/locks/LockSupport.java b/jdk/src/share/classes/java/util/concurrent/locks/LockSupport.java index 08bd8878a81..20abfacc3c8 100644 --- a/jdk/src/share/classes/java/util/concurrent/locks/LockSupport.java +++ b/jdk/src/share/classes/java/util/concurrent/locks/LockSupport.java @@ -101,14 +101,14 @@ import sun.misc.Unsafe; * // Block while not first in queue or cannot acquire lock * while (waiters.peek() != current || * !locked.compareAndSet(false, true)) { - * LockSupport.park(this); - * if (Thread.interrupted()) // ignore interrupts while waiting - * wasInterrupted = true; + * LockSupport.park(this); + * if (Thread.interrupted()) // ignore interrupts while waiting + * wasInterrupted = true; * } * * waiters.remove(); * if (wasInterrupted) // reassert interrupt status on exit - * current.interrupt(); + * current.interrupt(); * } * * public void unlock() { @@ -120,20 +120,9 @@ import sun.misc.Unsafe; public class LockSupport { private LockSupport() {} // Cannot be instantiated. - // Hotspot implementation via intrinsics API - private static final Unsafe unsafe = Unsafe.getUnsafe(); - private static final long parkBlockerOffset; - - static { - try { - parkBlockerOffset = unsafe.objectFieldOffset - (java.lang.Thread.class.getDeclaredField("parkBlocker")); - } catch (Exception ex) { throw new Error(ex); } - } - private static void setBlocker(Thread t, Object arg) { // Even though volatile, hotspot doesn't need a write barrier here. - unsafe.putObject(t, parkBlockerOffset, arg); + UNSAFE.putObject(t, parkBlockerOffset, arg); } /** @@ -149,7 +138,7 @@ public class LockSupport { */ public static void unpark(Thread thread) { if (thread != null) - unsafe.unpark(thread); + UNSAFE.unpark(thread); } /** @@ -183,7 +172,7 @@ public class LockSupport { public static void park(Object blocker) { Thread t = Thread.currentThread(); setBlocker(t, blocker); - unsafe.park(false, 0L); + UNSAFE.park(false, 0L); setBlocker(t, null); } @@ -223,7 +212,7 @@ public class LockSupport { if (nanos > 0) { Thread t = Thread.currentThread(); setBlocker(t, blocker); - unsafe.park(false, nanos); + UNSAFE.park(false, nanos); setBlocker(t, null); } } @@ -264,7 +253,7 @@ public class LockSupport { public static void parkUntil(Object blocker, long deadline) { Thread t = Thread.currentThread(); setBlocker(t, blocker); - unsafe.park(true, deadline); + UNSAFE.park(true, deadline); setBlocker(t, null); } @@ -283,7 +272,7 @@ public class LockSupport { public static Object getBlocker(Thread t) { if (t == null) throw new NullPointerException(); - return unsafe.getObjectVolatile(t, parkBlockerOffset); + return UNSAFE.getObjectVolatile(t, parkBlockerOffset); } /** @@ -312,7 +301,7 @@ public class LockSupport { * for example, the interrupt status of the thread upon return. */ public static void park() { - unsafe.park(false, 0L); + UNSAFE.park(false, 0L); } /** @@ -346,7 +335,7 @@ public class LockSupport { */ public static void parkNanos(long nanos) { if (nanos > 0) - unsafe.park(false, nanos); + UNSAFE.park(false, nanos); } /** @@ -380,6 +369,46 @@ public class LockSupport { * to wait until */ public static void parkUntil(long deadline) { - unsafe.park(true, deadline); + UNSAFE.park(true, deadline); } + + /** + * Returns the pseudo-randomly initialized or updated secondary seed. + * Copied from ThreadLocalRandom due to package access restrictions. + */ + static final int nextSecondarySeed() { + int r; + Thread t = Thread.currentThread(); + if ((r = UNSAFE.getInt(t, SECONDARY)) != 0) { + r ^= r << 13; // xorshift + r ^= r >>> 17; + r ^= r << 5; + } + else if ((r = java.util.concurrent.ThreadLocalRandom.current().nextInt()) == 0) + r = 1; // avoid zero + UNSAFE.putInt(t, SECONDARY, r); + return r; + } + + // Hotspot implementation via intrinsics API + private static final sun.misc.Unsafe UNSAFE; + private static final long parkBlockerOffset; + private static final long SEED; + private static final long PROBE; + private static final long SECONDARY; + static { + try { + UNSAFE = sun.misc.Unsafe.getUnsafe(); + Class tk = Thread.class; + parkBlockerOffset = UNSAFE.objectFieldOffset + (tk.getDeclaredField("parkBlocker")); + SEED = UNSAFE.objectFieldOffset + (tk.getDeclaredField("threadLocalRandomSeed")); + PROBE = UNSAFE.objectFieldOffset + (tk.getDeclaredField("threadLocalRandomProbe")); + SECONDARY = UNSAFE.objectFieldOffset + (tk.getDeclaredField("threadLocalRandomSecondarySeed")); + } catch (Exception ex) { throw new Error(ex); } + } + } diff --git a/jdk/src/share/classes/java/util/concurrent/locks/StampedLock.java b/jdk/src/share/classes/java/util/concurrent/locks/StampedLock.java new file mode 100644 index 00000000000..0ca43f630f7 --- /dev/null +++ b/jdk/src/share/classes/java/util/concurrent/locks/StampedLock.java @@ -0,0 +1,1377 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent.locks; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.LockSupport; + +/** + * A capability-based lock with three modes for controlling read/write + * access. The state of a StampedLock consists of a version and mode. + * Lock acquisition methods return a stamp that represents and + * controls access with respect to a lock state; "try" versions of + * these methods may instead return the special value zero to + * represent failure to acquire access. Lock release and conversion + * methods require stamps as arguments, and fail if they do not match + * the state of the lock. The three modes are: + * + *

        + * + *
      • Writing. Method {@link #writeLock} possibly blocks + * waiting for exclusive access, returning a stamp that can be used + * in method {@link #unlockWrite} to release the lock. Untimed and + * timed versions of {@code tryWriteLock} are also provided. When + * the lock is held in write mode, no read locks may be obtained, + * and all optimistic read validations will fail.
      • + * + *
      • Reading. Method {@link #readLock} possibly blocks + * waiting for non-exclusive access, returning a stamp that can be + * used in method {@link #unlockRead} to release the lock. Untimed + * and timed versions of {@code tryReadLock} are also provided.
      • + * + *
      • Optimistic Reading. Method {@link #tryOptimisticRead} + * returns a non-zero stamp only if the lock is not currently held + * in write mode. Method {@link #validate} returns true if the lock + * has not been acquired in write mode since obtaining a given + * stamp. This mode can be thought of as an extremely weak version + * of a read-lock, that can be broken by a writer at any time. The + * use of optimistic mode for short read-only code segments often + * reduces contention and improves throughput. However, its use is + * inherently fragile. Optimistic read sections should only read + * fields and hold them in local variables for later use after + * validation. Fields read while in optimistic mode may be wildly + * inconsistent, so usage applies only when you are familiar enough + * with data representations to check consistency and/or repeatedly + * invoke method {@code validate()}. For example, such steps are + * typically required when first reading an object or array + * reference, and then accessing one of its fields, elements or + * methods.
      • + * + *
      + * + *

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

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

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

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

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

      {@code
      + * class Point {
      + *   private double x, y;
      + *   private final StampedLock sl = new StampedLock();
      + *
      + *   void move(double deltaX, double deltaY) { // an exclusively locked method
      + *     long stamp = sl.writeLock();
      + *     try {
      + *       x += deltaX;
      + *       y += deltaY;
      + *     } finally {
      + *       sl.unlockWrite(stamp);
      + *     }
      + *   }
      + *
      + *   double distanceFromOrigin() { // A read-only method
      + *     long stamp = sl.tryOptimisticRead();
      + *     double currentX = x, currentY = y;
      + *     if (!sl.validate(stamp)) {
      + *        stamp = sl.readLock();
      + *        try {
      + *          currentX = x;
      + *          currentY = y;
      + *        } finally {
      + *           sl.unlockRead(stamp);
      + *        }
      + *     }
      + *     return Math.sqrt(currentX * currentX + currentY * currentY);
      + *   }
      + *
      + *   void moveIfAtOrigin(double newX, double newY) { // upgrade
      + *     // Could instead start with optimistic, not read mode
      + *     long stamp = sl.readLock();
      + *     try {
      + *       while (x == 0.0 && y == 0.0) {
      + *         long ws = sl.tryConvertToWriteLock(stamp);
      + *         if (ws != 0L) {
      + *           stamp = ws;
      + *           x = newX;
      + *           y = newY;
      + *           break;
      + *         }
      + *         else {
      + *           sl.unlockRead(stamp);
      + *           stamp = sl.writeLock();
      + *         }
      + *       }
      + *     } finally {
      + *       sl.unlock(stamp);
      + *     }
      + *   }
      + * }}
      + * + * @since 1.8 + * @author Doug Lea + */ +public class StampedLock implements java.io.Serializable { + /* + * Algorithmic notes: + * + * The design employs elements of Sequence locks + * (as used in linux kernels; see Lameter's + * http://www.lameter.com/gelato2005.pdf + * and elsewhere; see + * Boehm's http://www.hpl.hp.com/techreports/2012/HPL-2012-68.html) + * and Ordered RW locks (see Shirako et al + * http://dl.acm.org/citation.cfm?id=2312015) + * + * Conceptually, the primary state of the lock includes a sequence + * number that is odd when write-locked and even otherwise. + * However, this is offset by a reader count that is non-zero when + * read-locked. The read count is ignored when validating + * "optimistic" seqlock-reader-style stamps. Because we must use + * a small finite number of bits (currently 7) for readers, a + * supplementary reader overflow word is used when the number of + * readers exceeds the count field. We do this by treating the max + * reader count value (RBITS) as a spinlock protecting overflow + * updates. + * + * Waiters use a modified form of CLH lock used in + * AbstractQueuedSynchronizer (see its internal documentation for + * a fuller account), where each node is tagged (field mode) as + * either a reader or writer. Sets of waiting readers are grouped + * (linked) under a common node (field cowait) so act as a single + * node with respect to most CLH mechanics. By virtue of the + * queue structure, wait nodes need not actually carry sequence + * numbers; we know each is greater than its predecessor. This + * simplifies the scheduling policy to a mainly-FIFO scheme that + * incorporates elements of Phase-Fair locks (see Brandenburg & + * Anderson, especially http://www.cs.unc.edu/~bbb/diss/). In + * particular, we use the phase-fair anti-barging rule: If an + * incoming reader arrives while read lock is held but there is a + * queued writer, this incoming reader is queued. (This rule is + * responsible for some of the complexity of method acquireRead, + * but without it, the lock becomes highly unfair.) + * + * These rules apply to threads actually queued. All tryLock forms + * opportunistically try to acquire locks regardless of preference + * rules, and so may "barge" their way in. Randomized spinning is + * used in the acquire methods to reduce (increasingly expensive) + * context switching while also avoiding sustained memory + * thrashing among many threads. We limit spins to the head of + * queue. A thread spin-waits up to SPINS times (where each + * iteration decreases spin count with 50% probability) before + * blocking. If, upon wakening it fails to obtain lock, and is + * still (or becomes) the first waiting thread (which indicates + * that some other thread barged and obtained lock), it escalates + * spins (up to MAX_HEAD_SPINS) to reduce the likelihood of + * continually losing to barging threads. + * + * Nearly all of these mechanics are carried out in methods + * acquireWrite and acquireRead, that, as typical of such code, + * sprawl out because actions and retries rely on consistent sets + * of locally cached reads. + * + * As noted in Boehm's paper (above), sequence validation (mainly + * method validate()) requires stricter ordering rules than apply + * to normal volatile reads (of "state"). To force orderings of + * reads before a validation and the validation itself in those + * cases where this is not already forced, we use + * Unsafe.loadFence. + * + * The memory layout keeps lock state and queue pointers together + * (normally on the same cache line). This usually works well for + * read-mostly loads. In most other cases, the natural tendency of + * adaptive-spin CLH locks to reduce memory contention lessens + * motivation to further spread out contended locations, but might + * be subject to future improvements. + */ + + private static final long serialVersionUID = -6001602636862214147L; + + /** Number of processors, for spin control */ + private static final int NCPU = Runtime.getRuntime().availableProcessors(); + + /** Maximum number of retries before blocking on acquisition */ + private static final int SPINS = (NCPU > 1) ? 1 << 6 : 0; + + /** Maximum number of retries before re-blocking */ + private static final int MAX_HEAD_SPINS = (NCPU > 1) ? 1 << 12 : 0; + + /** The period for yielding when waiting for overflow spinlock */ + private static final int OVERFLOW_YIELD_RATE = 7; // must be power 2 - 1 + + /** The number of bits to use for reader count before overflowing */ + private static final int LG_READERS = 7; + + // Values for lock state and stamp operations + private static final long RUNIT = 1L; + private static final long WBIT = 1L << LG_READERS; + private static final long RBITS = WBIT - 1L; + private static final long RFULL = RBITS - 1L; + private static final long ABITS = RBITS | WBIT; + private static final long SBITS = ~RBITS; // note overlap with ABITS + + // Initial value for lock state; avoid failure value zero + private static final long ORIGIN = WBIT << 1; + + // Special value from cancelled acquire methods so caller can throw IE + private static final long INTERRUPTED = 1L; + + // Values for node status; order matters + private static final int WAITING = -1; + private static final int CANCELLED = 1; + + // Modes for nodes (int not boolean to allow arithmetic) + private static final int RMODE = 0; + private static final int WMODE = 1; + + /** Wait nodes */ + static final class WNode { + volatile WNode prev; + volatile WNode next; + volatile WNode cowait; // list of linked readers + volatile Thread thread; // non-null while possibly parked + volatile int status; // 0, WAITING, or CANCELLED + final int mode; // RMODE or WMODE + WNode(int m, WNode p) { mode = m; prev = p; } + } + + /** Head of CLH queue */ + private transient volatile WNode whead; + /** Tail (last) of CLH queue */ + private transient volatile WNode wtail; + + // views + transient ReadLockView readLockView; + transient WriteLockView writeLockView; + transient ReadWriteLockView readWriteLockView; + + /** Lock sequence/state */ + private transient volatile long state; + /** extra reader count when state read count saturated */ + private transient int readerOverflow; + + /** + * Creates a new lock, initially in unlocked state. + */ + public StampedLock() { + state = ORIGIN; + } + + /** + * Exclusively acquires the lock, blocking if necessary + * until available. + * + * @return a stamp that can be used to unlock or convert mode + */ + public long writeLock() { + long s, next; // bypass acquireWrite in fully unlocked case only + return ((((s = state) & ABITS) == 0L && + U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ? + next : acquireWrite(false, 0L)); + } + + /** + * Exclusively acquires the lock if it is immediately available. + * + * @return a stamp that can be used to unlock or convert mode, + * or zero if the lock is not available + */ + public long tryWriteLock() { + long s, next; + return ((((s = state) & ABITS) == 0L && + U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ? + next : 0L); + } + + /** + * Exclusively acquires the lock if it is available within the + * given time and the current thread has not been interrupted. + * Behavior under timeout and interruption matches that specified + * for method {@link Lock#tryLock(long,TimeUnit)}. + * + * @return a stamp that can be used to unlock or convert mode, + * or zero if the lock is not available + * @throws InterruptedException if the current thread is interrupted + * before acquiring the lock + */ + public long tryWriteLock(long time, TimeUnit unit) + throws InterruptedException { + long nanos = unit.toNanos(time); + if (!Thread.interrupted()) { + long next, deadline; + if ((next = tryWriteLock()) != 0L) + return next; + if (nanos <= 0L) + return 0L; + if ((deadline = System.nanoTime() + nanos) == 0L) + deadline = 1L; + if ((next = acquireWrite(true, deadline)) != INTERRUPTED) + return next; + } + throw new InterruptedException(); + } + + /** + * Exclusively acquires the lock, blocking if necessary + * until available or the current thread is interrupted. + * Behavior under interruption matches that specified + * for method {@link Lock#lockInterruptibly()}. + * + * @return a stamp that can be used to unlock or convert mode + * @throws InterruptedException if the current thread is interrupted + * before acquiring the lock + */ + public long writeLockInterruptibly() throws InterruptedException { + long next; + if (!Thread.interrupted() && + (next = acquireWrite(true, 0L)) != INTERRUPTED) + return next; + throw new InterruptedException(); + } + + /** + * Non-exclusively acquires the lock, blocking if necessary + * until available. + * + * @return a stamp that can be used to unlock or convert mode + */ + public long readLock() { + long s, next; // bypass acquireRead on fully unlocked case only + return ((((s = state) & ABITS) == 0L && + U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) ? + next : acquireRead(false, 0L)); + } + + /** + * Non-exclusively acquires the lock if it is immediately available. + * + * @return a stamp that can be used to unlock or convert mode, + * or zero if the lock is not available + */ + public long tryReadLock() { + for (;;) { + long s, m, next; + if ((m = (s = state) & ABITS) == WBIT) + return 0L; + else if (m < RFULL) { + if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) + return next; + } + else if ((next = tryIncReaderOverflow(s)) != 0L) + return next; + } + } + + /** + * Non-exclusively acquires the lock if it is available within the + * given time and the current thread has not been interrupted. + * Behavior under timeout and interruption matches that specified + * for method {@link Lock#tryLock(long,TimeUnit)}. + * + * @return a stamp that can be used to unlock or convert mode, + * or zero if the lock is not available + * @throws InterruptedException if the current thread is interrupted + * before acquiring the lock + */ + public long tryReadLock(long time, TimeUnit unit) + throws InterruptedException { + long s, m, next, deadline; + long nanos = unit.toNanos(time); + if (!Thread.interrupted()) { + if ((m = (s = state) & ABITS) != WBIT) { + if (m < RFULL) { + if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) + return next; + } + else if ((next = tryIncReaderOverflow(s)) != 0L) + return next; + } + if (nanos <= 0L) + return 0L; + if ((deadline = System.nanoTime() + nanos) == 0L) + deadline = 1L; + if ((next = acquireRead(true, deadline)) != INTERRUPTED) + return next; + } + throw new InterruptedException(); + } + + /** + * Non-exclusively acquires the lock, blocking if necessary + * until available or the current thread is interrupted. + * Behavior under interruption matches that specified + * for method {@link Lock#lockInterruptibly()}. + * + * @return a stamp that can be used to unlock or convert mode + * @throws InterruptedException if the current thread is interrupted + * before acquiring the lock + */ + public long readLockInterruptibly() throws InterruptedException { + long next; + if (!Thread.interrupted() && + (next = acquireRead(true, 0L)) != INTERRUPTED) + return next; + throw new InterruptedException(); + } + + /** + * Returns a stamp that can later be validated, or zero + * if exclusively locked. + * + * @return a stamp, or zero if exclusively locked + */ + public long tryOptimisticRead() { + long s; + return (((s = state) & WBIT) == 0L) ? (s & SBITS) : 0L; + } + + /** + * Returns true if the lock has not been exclusively acquired + * since issuance of the given stamp. Always returns false if the + * stamp is zero. Always returns true if the stamp represents a + * currently held lock. Invoking this method with a value not + * obtained from {@link #tryOptimisticRead} or a locking method + * for this lock has no defined effect or result. + * + * @return true if the lock has not been exclusively acquired + * since issuance of the given stamp; else false + */ + public boolean validate(long stamp) { + U.loadFence(); + return (stamp & SBITS) == (state & SBITS); + } + + /** + * If the lock state matches the given stamp, releases the + * exclusive lock. + * + * @param stamp a stamp returned by a write-lock operation + * @throws IllegalMonitorStateException if the stamp does + * not match the current state of this lock + */ + public void unlockWrite(long stamp) { + WNode h; + if (state != stamp || (stamp & WBIT) == 0L) + throw new IllegalMonitorStateException(); + state = (stamp += WBIT) == 0L ? ORIGIN : stamp; + if ((h = whead) != null && h.status != 0) + release(h); + } + + /** + * If the lock state matches the given stamp, releases the + * non-exclusive lock. + * + * @param stamp a stamp returned by a read-lock operation + * @throws IllegalMonitorStateException if the stamp does + * not match the current state of this lock + */ + public void unlockRead(long stamp) { + long s, m; WNode h; + for (;;) { + if (((s = state) & SBITS) != (stamp & SBITS) || + (stamp & ABITS) == 0L || (m = s & ABITS) == 0L || m == WBIT) + throw new IllegalMonitorStateException(); + if (m < RFULL) { + if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) { + if (m == RUNIT && (h = whead) != null && h.status != 0) + release(h); + break; + } + } + else if (tryDecReaderOverflow(s) != 0L) + break; + } + } + + /** + * If the lock state matches the given stamp, releases the + * corresponding mode of the lock. + * + * @param stamp a stamp returned by a lock operation + * @throws IllegalMonitorStateException if the stamp does + * not match the current state of this lock + */ + public void unlock(long stamp) { + long a = stamp & ABITS, m, s; WNode h; + while (((s = state) & SBITS) == (stamp & SBITS)) { + if ((m = s & ABITS) == 0L) + break; + else if (m == WBIT) { + if (a != m) + break; + state = (s += WBIT) == 0L ? ORIGIN : s; + if ((h = whead) != null && h.status != 0) + release(h); + return; + } + else if (a == 0L || a >= WBIT) + break; + else if (m < RFULL) { + if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) { + if (m == RUNIT && (h = whead) != null && h.status != 0) + release(h); + return; + } + } + else if (tryDecReaderOverflow(s) != 0L) + return; + } + throw new IllegalMonitorStateException(); + } + + /** + * If the lock state matches the given stamp, performs one of + * the following actions. If the stamp represents holding a write + * lock, returns it. Or, if a read lock, if the write lock is + * available, releases the read lock and returns a write stamp. + * Or, if an optimistic read, returns a write stamp only if + * immediately available. This method returns zero in all other + * cases. + * + * @param stamp a stamp + * @return a valid write stamp, or zero on failure + */ + public long tryConvertToWriteLock(long stamp) { + long a = stamp & ABITS, m, s, next; + while (((s = state) & SBITS) == (stamp & SBITS)) { + if ((m = s & ABITS) == 0L) { + if (a != 0L) + break; + if (U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) + return next; + } + else if (m == WBIT) { + if (a != m) + break; + return stamp; + } + else if (m == RUNIT && a != 0L) { + if (U.compareAndSwapLong(this, STATE, s, + next = s - RUNIT + WBIT)) + return next; + } + else + break; + } + return 0L; + } + + /** + * If the lock state matches the given stamp, performs one of + * the following actions. If the stamp represents holding a write + * lock, releases it and obtains a read lock. Or, if a read lock, + * returns it. Or, if an optimistic read, acquires a read lock and + * returns a read stamp only if immediately available. This method + * returns zero in all other cases. + * + * @param stamp a stamp + * @return a valid read stamp, or zero on failure + */ + public long tryConvertToReadLock(long stamp) { + long a = stamp & ABITS, m, s, next; WNode h; + while (((s = state) & SBITS) == (stamp & SBITS)) { + if ((m = s & ABITS) == 0L) { + if (a != 0L) + break; + else if (m < RFULL) { + if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) + return next; + } + else if ((next = tryIncReaderOverflow(s)) != 0L) + return next; + } + else if (m == WBIT) { + if (a != m) + break; + state = next = s + (WBIT + RUNIT); + if ((h = whead) != null && h.status != 0) + release(h); + return next; + } + else if (a != 0L && a < WBIT) + return stamp; + else + break; + } + return 0L; + } + + /** + * If the lock state matches the given stamp then, if the stamp + * represents holding a lock, releases it and returns an + * observation stamp. Or, if an optimistic read, returns it if + * validated. This method returns zero in all other cases, and so + * may be useful as a form of "tryUnlock". + * + * @param stamp a stamp + * @return a valid optimistic read stamp, or zero on failure + */ + public long tryConvertToOptimisticRead(long stamp) { + long a = stamp & ABITS, m, s, next; WNode h; + U.loadFence(); + for (;;) { + if (((s = state) & SBITS) != (stamp & SBITS)) + break; + if ((m = s & ABITS) == 0L) { + if (a != 0L) + break; + return s; + } + else if (m == WBIT) { + if (a != m) + break; + state = next = (s += WBIT) == 0L ? ORIGIN : s; + if ((h = whead) != null && h.status != 0) + release(h); + return next; + } + else if (a == 0L || a >= WBIT) + break; + else if (m < RFULL) { + if (U.compareAndSwapLong(this, STATE, s, next = s - RUNIT)) { + if (m == RUNIT && (h = whead) != null && h.status != 0) + release(h); + return next & SBITS; + } + } + else if ((next = tryDecReaderOverflow(s)) != 0L) + return next & SBITS; + } + return 0L; + } + + /** + * Releases the write lock if it is held, without requiring a + * stamp value. This method may be useful for recovery after + * errors. + * + * @return true if the lock was held, else false + */ + public boolean tryUnlockWrite() { + long s; WNode h; + if (((s = state) & WBIT) != 0L) { + state = (s += WBIT) == 0L ? ORIGIN : s; + if ((h = whead) != null && h.status != 0) + release(h); + return true; + } + return false; + } + + /** + * Releases one hold of the read lock if it is held, without + * requiring a stamp value. This method may be useful for recovery + * after errors. + * + * @return true if the read lock was held, else false + */ + public boolean tryUnlockRead() { + long s, m; WNode h; + while ((m = (s = state) & ABITS) != 0L && m < WBIT) { + if (m < RFULL) { + if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) { + if (m == RUNIT && (h = whead) != null && h.status != 0) + release(h); + return true; + } + } + else if (tryDecReaderOverflow(s) != 0L) + return true; + } + return false; + } + + // status monitoring methods + + /** + * Returns combined state-held and overflow read count for given + * state s. + */ + private int getReadLockCount(long s) { + long readers; + if ((readers = s & RBITS) >= RFULL) + readers = RFULL + readerOverflow; + return (int) readers; + } + + /** + * Returns true if the lock is currently held exclusively. + * + * @return true if the lock is currently held exclusively + */ + public boolean isWriteLocked() { + return (state & WBIT) != 0L; + } + + /** + * Returns true if the lock is currently held non-exclusively. + * + * @return true if the lock is currently held non-exclusively + */ + public boolean isReadLocked() { + return (state & RBITS) != 0L; + } + + /** + * Queries the number of read locks held for this lock. This + * method is designed for use in monitoring system state, not for + * synchronization control. + * @return the number of read locks held + */ + public int getReadLockCount() { + return getReadLockCount(state); + } + + /** + * Returns a string identifying this lock, as well as its lock + * state. The state, in brackets, includes the String {@code + * "Unlocked"} or the String {@code "Write-locked"} or the String + * {@code "Read-locks:"} followed by the current number of + * read-locks held. + * + * @return a string identifying this lock, as well as its lock state + */ + public String toString() { + long s = state; + return super.toString() + + ((s & ABITS) == 0L ? "[Unlocked]" : + (s & WBIT) != 0L ? "[Write-locked]" : + "[Read-locks:" + getReadLockCount(s) + "]"); + } + + // views + + /** + * Returns a plain {@link Lock} view of this StampedLock in which + * the {@link Lock#lock} method is mapped to {@link #readLock}, + * and similarly for other methods. The returned Lock does not + * support a {@link Condition}; method {@link + * Lock#newCondition()} throws {@code + * UnsupportedOperationException}. + * + * @return the lock + */ + public Lock asReadLock() { + ReadLockView v; + return ((v = readLockView) != null ? v : + (readLockView = new ReadLockView())); + } + + /** + * Returns a plain {@link Lock} view of this StampedLock in which + * the {@link Lock#lock} method is mapped to {@link #writeLock}, + * and similarly for other methods. The returned Lock does not + * support a {@link Condition}; method {@link + * Lock#newCondition()} throws {@code + * UnsupportedOperationException}. + * + * @return the lock + */ + public Lock asWriteLock() { + WriteLockView v; + return ((v = writeLockView) != null ? v : + (writeLockView = new WriteLockView())); + } + + /** + * Returns a {@link ReadWriteLock} view of this StampedLock in + * which the {@link ReadWriteLock#readLock()} method is mapped to + * {@link #asReadLock()}, and {@link ReadWriteLock#writeLock()} to + * {@link #asWriteLock()}. + * + * @return the lock + */ + public ReadWriteLock asReadWriteLock() { + ReadWriteLockView v; + return ((v = readWriteLockView) != null ? v : + (readWriteLockView = new ReadWriteLockView())); + } + + // view classes + + final class ReadLockView implements Lock { + public void lock() { readLock(); } + public void lockInterruptibly() throws InterruptedException { + readLockInterruptibly(); + } + public boolean tryLock() { return tryReadLock() != 0L; } + public boolean tryLock(long time, TimeUnit unit) + throws InterruptedException { + return tryReadLock(time, unit) != 0L; + } + public void unlock() { unstampedUnlockRead(); } + public Condition newCondition() { + throw new UnsupportedOperationException(); + } + } + + final class WriteLockView implements Lock { + public void lock() { writeLock(); } + public void lockInterruptibly() throws InterruptedException { + writeLockInterruptibly(); + } + public boolean tryLock() { return tryWriteLock() != 0L; } + public boolean tryLock(long time, TimeUnit unit) + throws InterruptedException { + return tryWriteLock(time, unit) != 0L; + } + public void unlock() { unstampedUnlockWrite(); } + public Condition newCondition() { + throw new UnsupportedOperationException(); + } + } + + final class ReadWriteLockView implements ReadWriteLock { + public Lock readLock() { return asReadLock(); } + public Lock writeLock() { return asWriteLock(); } + } + + // Unlock methods without stamp argument checks for view classes. + // Needed because view-class lock methods throw away stamps. + + final void unstampedUnlockWrite() { + WNode h; long s; + if (((s = state) & WBIT) == 0L) + throw new IllegalMonitorStateException(); + state = (s += WBIT) == 0L ? ORIGIN : s; + if ((h = whead) != null && h.status != 0) + release(h); + } + + final void unstampedUnlockRead() { + for (;;) { + long s, m; WNode h; + if ((m = (s = state) & ABITS) == 0L || m >= WBIT) + throw new IllegalMonitorStateException(); + else if (m < RFULL) { + if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) { + if (m == RUNIT && (h = whead) != null && h.status != 0) + release(h); + break; + } + } + else if (tryDecReaderOverflow(s) != 0L) + break; + } + } + + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + state = ORIGIN; // reset to unlocked state + } + + // internals + + /** + * Tries to increment readerOverflow by first setting state + * access bits value to RBITS, indicating hold of spinlock, + * then updating, then releasing. + * + * @param s a reader overflow stamp: (s & ABITS) >= RFULL + * @return new stamp on success, else zero + */ + private long tryIncReaderOverflow(long s) { + // assert (s & ABITS) >= RFULL; + if ((s & ABITS) == RFULL) { + if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) { + ++readerOverflow; + state = s; + return s; + } + } + else if ((LockSupport.nextSecondarySeed() & + OVERFLOW_YIELD_RATE) == 0) + Thread.yield(); + return 0L; + } + + /** + * Tries to decrement readerOverflow. + * + * @param s a reader overflow stamp: (s & ABITS) >= RFULL + * @return new stamp on success, else zero + */ + private long tryDecReaderOverflow(long s) { + // assert (s & ABITS) >= RFULL; + if ((s & ABITS) == RFULL) { + if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) { + int r; long next; + if ((r = readerOverflow) > 0) { + readerOverflow = r - 1; + next = s; + } + else + next = s - RUNIT; + state = next; + return next; + } + } + else if ((LockSupport.nextSecondarySeed() & + OVERFLOW_YIELD_RATE) == 0) + Thread.yield(); + return 0L; + } + + /** + * Wakes up the successor of h (normally whead). This is normally + * just h.next, but may require traversal from wtail if next + * pointers are lagging. This may fail to wake up an acquiring + * thread when one or more have been cancelled, but the cancel + * methods themselves provide extra safeguards to ensure liveness. + */ + private void release(WNode h) { + if (h != null) { + WNode q; Thread w; + U.compareAndSwapInt(h, WSTATUS, WAITING, 0); + if ((q = h.next) == null || q.status == CANCELLED) { + for (WNode t = wtail; t != null && t != h; t = t.prev) + if (t.status <= 0) + q = t; + } + if (q != null) { + for (WNode r = q;;) { // release co-waiters too + if ((w = r.thread) != null) { + r.thread = null; + U.unpark(w); + } + if ((r = q.cowait) == null) + break; + U.compareAndSwapObject(q, WCOWAIT, r, r.cowait); + } + } + } + } + + /** + * See above for explanation. + * + * @param interruptible true if should check interrupts and if so + * return INTERRUPTED + * @param deadline if nonzero, the System.nanoTime value to timeout + * at (and return zero) + * @return next state, or INTERRUPTED + */ + private long acquireWrite(boolean interruptible, long deadline) { + WNode node = null, p; + for (int spins = -1;;) { // spin while enqueuing + long s, ns; + if (((s = state) & ABITS) == 0L) { + if (U.compareAndSwapLong(this, STATE, s, ns = s + WBIT)) + return ns; + } + else if (spins > 0) { + if (LockSupport.nextSecondarySeed() >= 0) + --spins; + } + else if ((p = wtail) == null) { // initialize queue + WNode h = new WNode(WMODE, null); + if (U.compareAndSwapObject(this, WHEAD, null, h)) + wtail = h; + } + else if (spins < 0) + spins = (p == whead) ? SPINS : 0; + else if (node == null) + node = new WNode(WMODE, p); + else if (node.prev != p) + node.prev = p; + else if (U.compareAndSwapObject(this, WTAIL, p, node)) { + p.next = node; + break; + } + } + + for (int spins = SPINS;;) { + WNode np, pp; int ps; long s, ns; Thread w; + while ((np = node.prev) != p && np != null) + (p = np).next = node; // stale + if (whead == p) { + for (int k = spins;;) { // spin at head + if (((s = state) & ABITS) == 0L) { + if (U.compareAndSwapLong(this, STATE, s, ns = s+WBIT)) { + whead = node; + node.prev = null; + return ns; + } + } + else if (LockSupport.nextSecondarySeed() >= 0 && + --k <= 0) + break; + } + if (spins < MAX_HEAD_SPINS) + spins <<= 1; + } + if ((ps = p.status) == 0) + U.compareAndSwapInt(p, WSTATUS, 0, WAITING); + else if (ps == CANCELLED) { + if ((pp = p.prev) != null) { + node.prev = pp; + pp.next = node; + } + } + else { + long time; // 0 argument to park means no timeout + if (deadline == 0L) + time = 0L; + else if ((time = deadline - System.nanoTime()) <= 0L) + return cancelWaiter(node, node, false); + Thread wt = Thread.currentThread(); + U.putObject(wt, PARKBLOCKER, this); // emulate LockSupport.park + node.thread = wt; + if (node.prev == p && p.status == WAITING && // recheck + (p != whead || (state & ABITS) != 0L)) + U.park(false, time); + node.thread = null; + U.putObject(wt, PARKBLOCKER, null); + if (interruptible && Thread.interrupted()) + return cancelWaiter(node, node, true); + } + } + } + + /** + * See above for explanation. + * + * @param interruptible true if should check interrupts and if so + * return INTERRUPTED + * @param deadline if nonzero, the System.nanoTime value to timeout + * at (and return zero) + * @return next state, or INTERRUPTED + */ + private long acquireRead(boolean interruptible, long deadline) { + WNode node = null, group = null, p; + for (int spins = -1;;) { + for (;;) { + long s, m, ns; WNode h, q; Thread w; // anti-barging guard + if (group == null && (h = whead) != null && + (q = h.next) != null && q.mode != RMODE) + break; + if ((m = (s = state) & ABITS) < RFULL ? + U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) : + (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) { + if (group != null) { // help release others + for (WNode r = group;;) { + if ((w = r.thread) != null) { + r.thread = null; + U.unpark(w); + } + if ((r = group.cowait) == null) + break; + U.compareAndSwapObject(group, WCOWAIT, r, r.cowait); + } + } + return ns; + } + if (m >= WBIT) + break; + } + if (spins > 0) { + if (LockSupport.nextSecondarySeed() >= 0) + --spins; + } + else if ((p = wtail) == null) { + WNode h = new WNode(WMODE, null); + if (U.compareAndSwapObject(this, WHEAD, null, h)) + wtail = h; + } + else if (spins < 0) + spins = (p == whead) ? SPINS : 0; + else if (node == null) + node = new WNode(WMODE, p); + else if (node.prev != p) + node.prev = p; + else if (p.mode == RMODE && p != whead) { + WNode pp = p.prev; // become co-waiter with group p + if (pp != null && p == wtail && + U.compareAndSwapObject(p, WCOWAIT, + node.cowait = p.cowait, node)) { + node.thread = Thread.currentThread(); + for (long time;;) { + if (deadline == 0L) + time = 0L; + else if ((time = deadline - System.nanoTime()) <= 0L) + return cancelWaiter(node, p, false); + if (node.thread == null) + break; + if (p.prev != pp || p.status == CANCELLED || + p == whead || p.prev != pp) { + node.thread = null; + break; + } + Thread wt = Thread.currentThread(); + U.putObject(wt, PARKBLOCKER, this); + if (node.thread == null) // must recheck + break; + U.park(false, time); + U.putObject(wt, PARKBLOCKER, null); + if (interruptible && Thread.interrupted()) + return cancelWaiter(node, p, true); + } + group = p; + } + node = null; // throw away + } + else if (U.compareAndSwapObject(this, WTAIL, p, node)) { + p.next = node; + break; + } + } + + for (int spins = SPINS;;) { + WNode np, pp, r; int ps; long m, s, ns; Thread w; + while ((np = node.prev) != p && np != null) + (p = np).next = node; + if (whead == p) { + for (int k = spins;;) { + if ((m = (s = state) & ABITS) != WBIT) { + if (m < RFULL ? + U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT): + (ns = tryIncReaderOverflow(s)) != 0L) { + whead = node; + node.prev = null; + while ((r = node.cowait) != null) { + if (U.compareAndSwapObject(node, WCOWAIT, + r, r.cowait) && + (w = r.thread) != null) { + r.thread = null; + U.unpark(w); // release co-waiter + } + } + return ns; + } + } + else if (LockSupport.nextSecondarySeed() >= 0 && + --k <= 0) + break; + } + if (spins < MAX_HEAD_SPINS) + spins <<= 1; + } + if ((ps = p.status) == 0) + U.compareAndSwapInt(p, WSTATUS, 0, WAITING); + else if (ps == CANCELLED) { + if ((pp = p.prev) != null) { + node.prev = pp; + pp.next = node; + } + } + else { + long time; + if (deadline == 0L) + time = 0L; + else if ((time = deadline - System.nanoTime()) <= 0L) + return cancelWaiter(node, node, false); + Thread wt = Thread.currentThread(); + U.putObject(wt, PARKBLOCKER, this); + node.thread = wt; + if (node.prev == p && p.status == WAITING && + (p != whead || (state & ABITS) != WBIT)) + U.park(false, time); + node.thread = null; + U.putObject(wt, PARKBLOCKER, null); + if (interruptible && Thread.interrupted()) + return cancelWaiter(node, node, true); + } + } + } + + /** + * If node non-null, forces cancel status and unsplices it from + * queue if possible and wakes up any cowaiters (of the node, or + * group, as applicable), and in any case helps release current + * first waiter if lock is free. (Calling with null arguments + * serves as a conditional form of release, which is not currently + * needed but may be needed under possible future cancellation + * policies). This is a variant of cancellation methods in + * AbstractQueuedSynchronizer (see its detailed explanation in AQS + * internal documentation). + * + * @param node if nonnull, the waiter + * @param group either node or the group node is cowaiting with + * @param interrupted if already interrupted + * @return INTERRUPTED if interrupted or Thread.interrupted, else zero + */ + private long cancelWaiter(WNode node, WNode group, boolean interrupted) { + if (node != null && group != null) { + Thread w; + node.status = CANCELLED; + node.thread = null; + // unsplice cancelled nodes from group + for (WNode p = group, q; (q = p.cowait) != null;) { + if (q.status == CANCELLED) + U.compareAndSwapObject(p, WNEXT, q, q.next); + else + p = q; + } + if (group == node) { + WNode r; // detach and wake up uncancelled co-waiters + while ((r = node.cowait) != null) { + if (U.compareAndSwapObject(node, WCOWAIT, r, r.cowait) && + (w = r.thread) != null) { + r.thread = null; + U.unpark(w); + } + } + for (WNode pred = node.prev; pred != null; ) { // unsplice + WNode succ, pp; // find valid successor + while ((succ = node.next) == null || + succ.status == CANCELLED) { + WNode q = null; // find successor the slow way + for (WNode t = wtail; t != null && t != node; t = t.prev) + if (t.status != CANCELLED) + q = t; // don't link if succ cancelled + if (succ == q || // ensure accurate successor + U.compareAndSwapObject(node, WNEXT, + succ, succ = q)) { + if (succ == null && node == wtail) + U.compareAndSwapObject(this, WTAIL, node, pred); + break; + } + } + if (pred.next == node) // unsplice pred link + U.compareAndSwapObject(pred, WNEXT, node, succ); + if (succ != null && (w = succ.thread) != null) { + succ.thread = null; + U.unpark(w); // wake up succ to observe new pred + } + if (pred.status != CANCELLED || (pp = pred.prev) == null) + break; + node.prev = pp; // repeat if new pred wrong/cancelled + U.compareAndSwapObject(pp, WNEXT, pred, succ); + pred = pp; + } + } + } + WNode h; // Possibly release first waiter + while ((h = whead) != null) { + long s; WNode q; // similar to release() but check eligibility + if ((q = h.next) == null || q.status == CANCELLED) { + for (WNode t = wtail; t != null && t != h; t = t.prev) + if (t.status <= 0) + q = t; + } + if (h == whead) { + if (q != null && h.status == 0 && + ((s = state) & ABITS) != WBIT && // waiter is eligible + (s == 0L || q.mode == RMODE)) + release(h); + break; + } + } + return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L; + } + + // Unsafe mechanics + private static final sun.misc.Unsafe U; + private static final long STATE; + private static final long WHEAD; + private static final long WTAIL; + private static final long WNEXT; + private static final long WSTATUS; + private static final long WCOWAIT; + private static final long PARKBLOCKER; + + static { + try { + U = sun.misc.Unsafe.getUnsafe(); + Class k = StampedLock.class; + Class wk = WNode.class; + STATE = U.objectFieldOffset + (k.getDeclaredField("state")); + WHEAD = U.objectFieldOffset + (k.getDeclaredField("whead")); + WTAIL = U.objectFieldOffset + (k.getDeclaredField("wtail")); + WSTATUS = U.objectFieldOffset + (wk.getDeclaredField("status")); + WNEXT = U.objectFieldOffset + (wk.getDeclaredField("next")); + WCOWAIT = U.objectFieldOffset + (wk.getDeclaredField("cowait")); + Class tk = Thread.class; + PARKBLOCKER = U.objectFieldOffset + (tk.getDeclaredField("parkBlocker")); + + } catch (Exception e) { + throw new Error(e); + } + } +} diff --git a/jdk/src/share/classes/java/util/function/BinaryOperator.java b/jdk/src/share/classes/java/util/function/BinaryOperator.java index 37653b63b37..2e9050e59f2 100644 --- a/jdk/src/share/classes/java/util/function/BinaryOperator.java +++ b/jdk/src/share/classes/java/util/function/BinaryOperator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface BinaryOperator { /** diff --git a/jdk/src/share/classes/java/util/function/Block.java b/jdk/src/share/classes/java/util/function/Block.java index e468396be22..c41e9a45a5a 100644 --- a/jdk/src/share/classes/java/util/function/Block.java +++ b/jdk/src/share/classes/java/util/function/Block.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface Block { /** diff --git a/jdk/src/share/classes/java/util/function/DoubleBinaryOperator.java b/jdk/src/share/classes/java/util/function/DoubleBinaryOperator.java index 07ff741be96..f63403bb37e 100644 --- a/jdk/src/share/classes/java/util/function/DoubleBinaryOperator.java +++ b/jdk/src/share/classes/java/util/function/DoubleBinaryOperator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface DoubleBinaryOperator /* extends BinaryOperator */ { // // @Override diff --git a/jdk/src/share/classes/java/util/function/DoubleBlock.java b/jdk/src/share/classes/java/util/function/DoubleBlock.java index d5abd87b880..ae000841ae1 100644 --- a/jdk/src/share/classes/java/util/function/DoubleBlock.java +++ b/jdk/src/share/classes/java/util/function/DoubleBlock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface DoubleBlock { /** diff --git a/jdk/src/share/classes/java/util/function/DoubleFunction.java b/jdk/src/share/classes/java/util/function/DoubleFunction.java index 06c405e6d8c..d9c522c8e94 100644 --- a/jdk/src/share/classes/java/util/function/DoubleFunction.java +++ b/jdk/src/share/classes/java/util/function/DoubleFunction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface DoubleFunction { /** diff --git a/jdk/src/share/classes/java/util/function/DoubleSupplier.java b/jdk/src/share/classes/java/util/function/DoubleSupplier.java index 7e718a3c141..19d75353045 100644 --- a/jdk/src/share/classes/java/util/function/DoubleSupplier.java +++ b/jdk/src/share/classes/java/util/function/DoubleSupplier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface DoubleSupplier { /** diff --git a/jdk/src/share/classes/java/util/function/DoubleUnaryOperator.java b/jdk/src/share/classes/java/util/function/DoubleUnaryOperator.java index b9ac7f6fda7..3843f8bc7ee 100644 --- a/jdk/src/share/classes/java/util/function/DoubleUnaryOperator.java +++ b/jdk/src/share/classes/java/util/function/DoubleUnaryOperator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface DoubleUnaryOperator { /** diff --git a/jdk/src/share/classes/java/util/function/Function.java b/jdk/src/share/classes/java/util/function/Function.java index ce8ab1ed2e8..82bae01701d 100644 --- a/jdk/src/share/classes/java/util/function/Function.java +++ b/jdk/src/share/classes/java/util/function/Function.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface Function { /** diff --git a/jdk/src/share/classes/java/util/function/IntBinaryOperator.java b/jdk/src/share/classes/java/util/function/IntBinaryOperator.java index 312fb2db046..e25c2ba101f 100644 --- a/jdk/src/share/classes/java/util/function/IntBinaryOperator.java +++ b/jdk/src/share/classes/java/util/function/IntBinaryOperator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface IntBinaryOperator { /** diff --git a/jdk/src/share/classes/java/util/function/IntBlock.java b/jdk/src/share/classes/java/util/function/IntBlock.java index e0163163e1e..33cdbe79f51 100644 --- a/jdk/src/share/classes/java/util/function/IntBlock.java +++ b/jdk/src/share/classes/java/util/function/IntBlock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface IntBlock { /** diff --git a/jdk/src/share/classes/java/util/function/IntFunction.java b/jdk/src/share/classes/java/util/function/IntFunction.java index af8d4486254..6e1418533fe 100644 --- a/jdk/src/share/classes/java/util/function/IntFunction.java +++ b/jdk/src/share/classes/java/util/function/IntFunction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface IntFunction { /** diff --git a/jdk/src/share/classes/java/util/function/IntSupplier.java b/jdk/src/share/classes/java/util/function/IntSupplier.java index e930e0bc407..c73fc84e3be 100644 --- a/jdk/src/share/classes/java/util/function/IntSupplier.java +++ b/jdk/src/share/classes/java/util/function/IntSupplier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface IntSupplier { /** diff --git a/jdk/src/share/classes/java/util/function/IntUnaryOperator.java b/jdk/src/share/classes/java/util/function/IntUnaryOperator.java index 315619dcab1..2c429951c28 100644 --- a/jdk/src/share/classes/java/util/function/IntUnaryOperator.java +++ b/jdk/src/share/classes/java/util/function/IntUnaryOperator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface IntUnaryOperator { /** diff --git a/jdk/src/share/classes/java/util/function/LongBinaryOperator.java b/jdk/src/share/classes/java/util/function/LongBinaryOperator.java index 07056784e34..f767c92a355 100644 --- a/jdk/src/share/classes/java/util/function/LongBinaryOperator.java +++ b/jdk/src/share/classes/java/util/function/LongBinaryOperator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface LongBinaryOperator { /** diff --git a/jdk/src/share/classes/java/util/function/LongBlock.java b/jdk/src/share/classes/java/util/function/LongBlock.java index d9af3660f8b..71606ecf9ed 100644 --- a/jdk/src/share/classes/java/util/function/LongBlock.java +++ b/jdk/src/share/classes/java/util/function/LongBlock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface LongBlock { /** diff --git a/jdk/src/share/classes/java/util/function/LongFunction.java b/jdk/src/share/classes/java/util/function/LongFunction.java index 449543d0764..61c4fbf6475 100644 --- a/jdk/src/share/classes/java/util/function/LongFunction.java +++ b/jdk/src/share/classes/java/util/function/LongFunction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface LongFunction { /** diff --git a/jdk/src/share/classes/java/util/function/LongSupplier.java b/jdk/src/share/classes/java/util/function/LongSupplier.java index fb76068c970..f56ad7df282 100644 --- a/jdk/src/share/classes/java/util/function/LongSupplier.java +++ b/jdk/src/share/classes/java/util/function/LongSupplier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface LongSupplier { /** diff --git a/jdk/src/share/classes/java/util/function/LongUnaryOperator.java b/jdk/src/share/classes/java/util/function/LongUnaryOperator.java index ea2c1fc7338..f27ddf5a81a 100644 --- a/jdk/src/share/classes/java/util/function/LongUnaryOperator.java +++ b/jdk/src/share/classes/java/util/function/LongUnaryOperator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface LongUnaryOperator { /** diff --git a/jdk/src/share/classes/java/util/function/Predicate.java b/jdk/src/share/classes/java/util/function/Predicate.java index f4e6196fbce..9b440787485 100644 --- a/jdk/src/share/classes/java/util/function/Predicate.java +++ b/jdk/src/share/classes/java/util/function/Predicate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface Predicate { /** diff --git a/jdk/src/share/classes/java/util/function/Supplier.java b/jdk/src/share/classes/java/util/function/Supplier.java index 404af55af99..60bc801eb91 100644 --- a/jdk/src/share/classes/java/util/function/Supplier.java +++ b/jdk/src/share/classes/java/util/function/Supplier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface Supplier { /** diff --git a/jdk/src/share/classes/java/util/function/UnaryOperator.java b/jdk/src/share/classes/java/util/function/UnaryOperator.java index 9fa99c8d96a..a8aaa0dcd6b 100644 --- a/jdk/src/share/classes/java/util/function/UnaryOperator.java +++ b/jdk/src/share/classes/java/util/function/UnaryOperator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface UnaryOperator { /** diff --git a/jdk/src/share/classes/java/util/logging/Filter.java b/jdk/src/share/classes/java/util/logging/Filter.java index 73bbad11448..43837073114 100644 --- a/jdk/src/share/classes/java/util/logging/Filter.java +++ b/jdk/src/share/classes/java/util/logging/Filter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ package java.util.logging; * * @since 1.4 */ - +@FunctionalInterface public interface Filter { /** @@ -46,5 +46,4 @@ public interface Filter { * @return true if the log record should be published. */ public boolean isLoggable(LogRecord record); - } diff --git a/jdk/src/share/classes/java/util/prefs/PreferenceChangeListener.java b/jdk/src/share/classes/java/util/prefs/PreferenceChangeListener.java index 2c0c51e867a..0fb96c598cb 100644 --- a/jdk/src/share/classes/java/util/prefs/PreferenceChangeListener.java +++ b/jdk/src/share/classes/java/util/prefs/PreferenceChangeListener.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ package java.util.prefs; * @see NodeChangeListener * @since 1.4 */ +@FunctionalInterface public interface PreferenceChangeListener extends java.util.EventListener { /** * This method gets called when a preference is added, removed or when diff --git a/jdk/src/share/classes/javax/security/auth/kerberos/JavaxSecurityAuthKerberosAccessImpl.java b/jdk/src/share/classes/javax/security/auth/kerberos/JavaxSecurityAuthKerberosAccessImpl.java index 4b20626ec75..fbf74718933 100644 --- a/jdk/src/share/classes/javax/security/auth/kerberos/JavaxSecurityAuthKerberosAccessImpl.java +++ b/jdk/src/share/classes/javax/security/auth/kerberos/JavaxSecurityAuthKerberosAccessImpl.java @@ -31,8 +31,8 @@ import sun.security.krb5.PrincipalName; class JavaxSecurityAuthKerberosAccessImpl implements JavaxSecurityAuthKerberosAccess { - public EncryptionKey[] keyTabGetEncryptionKeys( - KeyTab ktab, PrincipalName principal) { - return ktab.getEncryptionKeys(principal); + public sun.security.krb5.internal.ktab.KeyTab keyTabTakeSnapshot( + KeyTab ktab) { + return ktab.takeSnapshot(); } } diff --git a/jdk/src/share/classes/javax/security/auth/kerberos/KeyTab.java b/jdk/src/share/classes/javax/security/auth/kerberos/KeyTab.java index 3ebce9975a2..32f644b5906 100644 --- a/jdk/src/share/classes/javax/security/auth/kerberos/KeyTab.java +++ b/jdk/src/share/classes/javax/security/auth/kerberos/KeyTab.java @@ -41,6 +41,20 @@ import sun.security.krb5.RealmException; * {@link javax.security.auth.Subject Subject} during the commit phase of the * authentication process. *

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

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

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

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

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

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

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

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

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

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

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

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

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

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

      + * Please note the deprecated constructors create a KeyTab object bound for + * some unknown principal. In this case, this method also returns null. + * User can call {@link #isBound()} to verify this case. + * @return the service principal + * @since 1.8 + */ + public KerberosPrincipal getPrincipal() { + return princ; + } + + /** + * Returns if the keytab is bound to a principal + * @return if the keytab is bound to a principal + * @since 1.8 + */ + public boolean isBound() { + return bound; } } diff --git a/jdk/src/share/classes/javax/swing/JComponent.java b/jdk/src/share/classes/javax/swing/JComponent.java index dbf4b3c3343..dac623a37bd 100644 --- a/jdk/src/share/classes/javax/swing/JComponent.java +++ b/jdk/src/share/classes/javax/swing/JComponent.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 @@ -3643,26 +3643,6 @@ public abstract class JComponent extends Container implements Serializable, } } - /** - * The AccessibleContext associated with this - * JComponent. - */ - protected AccessibleContext accessibleContext = null; - - /** - * Returns the AccessibleContext associated with this - * JComponent. The method implemented by this base - * class returns null. Classes that extend JComponent - * should implement this method to return the - * AccessibleContext associated with the subclass. - * - * @return the AccessibleContext of this - * JComponent - */ - public AccessibleContext getAccessibleContext() { - return accessibleContext; - } - /** * Inner class of JComponent used to provide default support for * accessibility. This class is not meant to be used directly by @@ -3689,7 +3669,18 @@ public abstract class JComponent extends Container implements Serializable, super(); } - protected ContainerListener accessibleContainerHandler = null; + /** + * Number of PropertyChangeListener objects registered. It's used + * to add/remove ContainerListener and FocusListener to track + * target JComponent's state + */ + private volatile transient int propertyListenersCount = 0; + + /** + * This field duplicates the one in java.awt.Component.AccessibleAWTComponent, + * so it has been deprecated. + */ + @Deprecated protected FocusListener accessibleFocusHandler = null; /** @@ -3747,10 +3738,12 @@ public abstract class JComponent extends Container implements Serializable, public void addPropertyChangeListener(PropertyChangeListener listener) { if (accessibleFocusHandler == null) { accessibleFocusHandler = new AccessibleFocusHandler(); - JComponent.this.addFocusListener(accessibleFocusHandler); } if (accessibleContainerHandler == null) { accessibleContainerHandler = new AccessibleContainerHandler(); + } + if (propertyListenersCount++ == 0) { + JComponent.this.addFocusListener(accessibleFocusHandler); JComponent.this.addContainerListener(accessibleContainerHandler); } super.addPropertyChangeListener(listener); @@ -3764,9 +3757,9 @@ public abstract class JComponent extends Container implements Serializable, * @param listener the PropertyChangeListener to be removed */ public void removePropertyChangeListener(PropertyChangeListener listener) { - if (accessibleFocusHandler != null) { + if (--propertyListenersCount == 0) { JComponent.this.removeFocusListener(accessibleFocusHandler); - accessibleFocusHandler = null; + JComponent.this.removeContainerListener(accessibleContainerHandler); } super.removePropertyChangeListener(listener); } diff --git a/jdk/src/share/classes/javax/swing/JMenuBar.java b/jdk/src/share/classes/javax/swing/JMenuBar.java index 0a16c865d15..22dbe6274fe 100644 --- a/jdk/src/share/classes/javax/swing/JMenuBar.java +++ b/jdk/src/share/classes/javax/swing/JMenuBar.java @@ -70,7 +70,14 @@ import javax.accessibility.*; * of all JavaBeansTM * has been added to the java.beans package. * Please see {@link java.beans.XMLEncoder}. - * + *

      + * Warning: + * By default, pressing the Tab key does not transfer focus from a + * JMenuBar which is added to a container together with other Swing + * components, because the focusTraversalKeysEnabled property + * of JMenuBar is set to false. To resolve this, + * you should call the JMenuBar.setFocusTraversalKeysEnabled(true) + * method. * @beaninfo * attribute: isContainer true * description: A container for holding and displaying menus. diff --git a/jdk/src/share/classes/javax/swing/plaf/basic/BasicComboBoxUI.java b/jdk/src/share/classes/javax/swing/plaf/basic/BasicComboBoxUI.java index 269bd34afc3..b31f7606b8e 100644 --- a/jdk/src/share/classes/javax/swing/plaf/basic/BasicComboBoxUI.java +++ b/jdk/src/share/classes/javax/swing/plaf/basic/BasicComboBoxUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1120,7 +1120,9 @@ public class BasicComboBoxUI extends ComboBoxUI { listBox.setSelectedIndex( si + 1 ); listBox.ensureIndexIsVisible( si + 1 ); if ( !isTableCellEditor ) { - comboBox.setSelectedIndex(si+1); + if (!(UIManager.getBoolean("ComboBox.noActionOnKeyNavigation") && comboBox.isPopupVisible())) { + comboBox.setSelectedIndex(si+1); + } } comboBox.repaint(); } @@ -1144,7 +1146,9 @@ public class BasicComboBoxUI extends ComboBoxUI { listBox.setSelectedIndex( si - 1 ); listBox.ensureIndexIsVisible( si - 1 ); if ( !isTableCellEditor ) { - comboBox.setSelectedIndex(si-1); + if (!(UIManager.getBoolean("ComboBox.noActionOnKeyNavigation") && comboBox.isPopupVisible())) { + comboBox.setSelectedIndex(si-1); + } } comboBox.repaint(); } @@ -1490,7 +1494,13 @@ public class BasicComboBoxUI extends ComboBoxUI { key == HOME || key == END) { int index = getNextIndex(comboBox, key); if (index >= 0 && index < comboBox.getItemCount()) { - comboBox.setSelectedIndex(index); + if (UIManager.getBoolean("ComboBox.noActionOnKeyNavigation") && comboBox.isPopupVisible()) { + ui.listBox.setSelectedIndex(index); + ui.listBox.ensureIndexIsVisible(index); + comboBox.repaint(); + } else { + comboBox.setSelectedIndex(index); + } } } else if (key == DOWN) { @@ -1558,22 +1568,33 @@ public class BasicComboBoxUI extends ComboBoxUI { else if (key == ENTER) { if (comboBox.isPopupVisible()) { - // Forces the selection of the list item - boolean isEnterSelectablePopup = - UIManager.getBoolean("ComboBox.isEnterSelectablePopup"); - if (!comboBox.isEditable() || isEnterSelectablePopup - || ui.isTableCellEditor) { + // If ComboBox.noActionOnKeyNavigation is set, + // forse selection of list item + if (UIManager.getBoolean("ComboBox.noActionOnKeyNavigation")) { Object listItem = ui.popup.getList().getSelectedValue(); if (listItem != null) { - // Use the selected value from popup - // to set the selected item in combo box, - // but ensure before that JComboBox.actionPerformed() - // won't use editor's value to set the selected item comboBox.getEditor().setItem(listItem); comboBox.setSelectedItem(listItem); } + comboBox.setPopupVisible(false); + } else { + // Forces the selection of the list item + boolean isEnterSelectablePopup = + UIManager.getBoolean("ComboBox.isEnterSelectablePopup"); + if (!comboBox.isEditable() || isEnterSelectablePopup + || ui.isTableCellEditor) { + Object listItem = ui.popup.getList().getSelectedValue(); + if (listItem != null) { + // Use the selected value from popup + // to set the selected item in combo box, + // but ensure before that JComboBox.actionPerformed() + // won't use editor's value to set the selected item + comboBox.getEditor().setItem(listItem); + comboBox.setSelectedItem(listItem); + } + } + comboBox.setPopupVisible(false); } - comboBox.setPopupVisible(false); } else { // Hide combo box if it is a table cell editor @@ -1604,14 +1625,20 @@ public class BasicComboBoxUI extends ComboBoxUI { } private int getNextIndex(JComboBox comboBox, String key) { + int listHeight = comboBox.getMaximumRowCount(); + + int selectedIndex = comboBox.getSelectedIndex(); + if (UIManager.getBoolean("ComboBox.noActionOnKeyNavigation") + && (comboBox.getUI() instanceof BasicComboBoxUI)) { + selectedIndex = ((BasicComboBoxUI) comboBox.getUI()).listBox.getSelectedIndex(); + } + if (key == PAGE_UP) { - int listHeight = comboBox.getMaximumRowCount(); - int index = comboBox.getSelectedIndex() - listHeight; + int index = selectedIndex - listHeight; return (index < 0 ? 0: index); } else if (key == PAGE_DOWN) { - int listHeight = comboBox.getMaximumRowCount(); - int index = comboBox.getSelectedIndex() + listHeight; + int index = selectedIndex + listHeight; int max = comboBox.getItemCount(); return (index < max ? index: max-1); } diff --git a/jdk/src/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java b/jdk/src/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java index 5a9135844bc..2e808c4b566 100644 --- a/jdk/src/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java +++ b/jdk/src/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -861,6 +861,7 @@ public abstract class BasicLookAndFeel extends LookAndFeel implements Serializab "END", "endPassThrough", "ENTER", "enterPressed" }), + "ComboBox.noActionOnKeyNavigation", Boolean.FALSE, // *** FileChooser diff --git a/jdk/src/share/classes/sun/awt/im/CompositionAreaHandler.java b/jdk/src/share/classes/sun/awt/im/CompositionAreaHandler.java index 6ae4a957ce2..1d661c4b9ba 100644 --- a/jdk/src/share/classes/sun/awt/im/CompositionAreaHandler.java +++ b/jdk/src/share/classes/sun/awt/im/CompositionAreaHandler.java @@ -33,6 +33,7 @@ import java.awt.event.InputMethodListener; import java.awt.font.TextAttribute; import java.awt.font.TextHitInfo; import java.awt.im.InputMethodRequests; +import java.lang.ref.WeakReference; import java.text.AttributedCharacterIterator; import java.text.AttributedCharacterIterator.Attribute; import java.text.AttributedString; @@ -55,7 +56,7 @@ class CompositionAreaHandler implements InputMethodListener, private AttributedCharacterIterator composedText; private TextHitInfo caret = null; - private Component clientComponent = null; + private WeakReference clientComponent = new WeakReference<>(null); private InputMethodContext inputMethodContext; /** @@ -76,8 +77,9 @@ class CompositionAreaHandler implements InputMethodListener, } // If the client component is an active client using below-the-spot style, then // make the composition window undecorated without a title bar. - if(clientComponent!=null){ - InputMethodRequests req = clientComponent.getInputMethodRequests(); + Component client = clientComponent.get(); + if(client != null){ + InputMethodRequests req = client.getInputMethodRequests(); if (req != null && inputMethodContext.useBelowTheSpotInput()) { setCompositionAreaUndecorated(true); } @@ -86,7 +88,7 @@ class CompositionAreaHandler implements InputMethodListener, } void setClientComponent(Component clientComponent) { - this.clientComponent = clientComponent; + this.clientComponent = new WeakReference<>(clientComponent); } /** @@ -256,8 +258,9 @@ class CompositionAreaHandler implements InputMethodListener, * the composed text are forwarded to the client component. */ InputMethodRequests getClientInputMethodRequests() { - if (clientComponent != null) { - return clientComponent.getInputMethodRequests(); + Component client = clientComponent.get(); + if (client != null) { + return client.getInputMethodRequests(); } return null; diff --git a/jdk/src/share/classes/sun/java2d/pipe/PixelToShapeConverter.java b/jdk/src/share/classes/sun/java2d/pipe/PixelToShapeConverter.java index c130068612e..5a01e000790 100644 --- a/jdk/src/share/classes/sun/java2d/pipe/PixelToShapeConverter.java +++ b/jdk/src/share/classes/sun/java2d/pipe/PixelToShapeConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 1998, 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,12 +103,12 @@ public class PixelToShapeConverter GeneralPath gp = new GeneralPath(GeneralPath.WIND_EVEN_ODD); if (nPoints > 0) { gp.moveTo(xPoints[0], yPoints[0]); - } - for (int i = 1; i < nPoints; i++) { - gp.lineTo(xPoints[i], yPoints[i]); - } - if (close) { - gp.closePath(); + for (int i = 1; i < nPoints; i++) { + gp.lineTo(xPoints[i], yPoints[i]); + } + if (close) { + gp.closePath(); + } } return gp; } diff --git a/jdk/src/share/classes/sun/management/Agent.java b/jdk/src/share/classes/sun/management/Agent.java index 19d2dedb5b4..feef02ad6be 100644 --- a/jdk/src/share/classes/sun/management/Agent.java +++ b/jdk/src/share/classes/sun/management/Agent.java @@ -22,7 +22,6 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package sun.management; import java.io.BufferedInputStream; @@ -31,49 +30,55 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; - +import java.lang.management.ManagementFactory; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.lang.management.ManagementFactory; - +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; import java.text.MessageFormat; - import java.util.MissingResourceException; import java.util.Properties; import java.util.ResourceBundle; import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXServiceURL; import static sun.management.AgentConfigurationError.*; import sun.management.jmxremote.ConnectorBootstrap; +import sun.management.jdp.JdpController; +import sun.management.jdp.JdpException; import sun.misc.VMSupport; /** - * This Agent is started by the VM when -Dcom.sun.management.snmp - * or -Dcom.sun.management.jmxremote is set. This class will be - * loaded by the system class loader. Also jmx framework could - * be started by jcmd + * This Agent is started by the VM when -Dcom.sun.management.snmp or + * -Dcom.sun.management.jmxremote is set. This class will be loaded by the + * system class loader. Also jmx framework could be started by jcmd */ public class Agent { // management properties + private static Properties mgmtProps; private static ResourceBundle messageRB; - private static final String CONFIG_FILE = - "com.sun.management.config.file"; + "com.sun.management.config.file"; private static final String SNMP_PORT = - "com.sun.management.snmp.port"; + "com.sun.management.snmp.port"; private static final String JMXREMOTE = - "com.sun.management.jmxremote"; + "com.sun.management.jmxremote"; private static final String JMXREMOTE_PORT = - "com.sun.management.jmxremote.port"; + "com.sun.management.jmxremote.port"; + private static final String RMI_PORT = + "com.sun.management.jmxremote.rmi.port"; private static final String ENABLE_THREAD_CONTENTION_MONITORING = - "com.sun.management.enableThreadContentionMonitoring"; + "com.sun.management.enableThreadContentionMonitoring"; private static final String LOCAL_CONNECTOR_ADDRESS_PROP = - "com.sun.management.jmxremote.localConnectorAddress"; - + "com.sun.management.jmxremote.localConnectorAddress"; private static final String SNMP_ADAPTOR_BOOTSTRAP_CLASS_NAME = - "sun.management.snmp.AdaptorBootstrap"; + "sun.management.snmp.AdaptorBootstrap"; + + private static final String JDP_DEFAULT_ADDRESS = "239.255.255.225"; + private static final int JDP_DEFAULT_PORT = 7095; // The only active agent allowed private static JMXConnectorServer jmxServer = null; @@ -81,26 +86,25 @@ public class Agent { // Parse string com.sun.management.prop=xxx,com.sun.management.prop=yyyy // and return property set if args is null or empty // return empty property set - private static Properties parseString(String args){ + private static Properties parseString(String args) { Properties argProps = new Properties(); if (args != null) { - for (String option : args.split(",")) { - String s[] = option.split("=", 2); - String name = s[0].trim(); - String value = (s.length > 1) ? s[1].trim() : ""; + for (String option : args.split(",")) { + String s[] = option.split("=", 2); + String name = s[0].trim(); + String value = (s.length > 1) ? s[1].trim() : ""; - if (!name.startsWith("com.sun.management.")) { - error(INVALID_OPTION, name); - } + if (!name.startsWith("com.sun.management.")) { + error(INVALID_OPTION, name); + } - argProps.setProperty(name, value); - } + argProps.setProperty(name, value); + } } return argProps; } - // invoked by -javaagent or -Dcom.sun.management.agent.class public static void premain(String args) throws Exception { agentmain(args); @@ -115,18 +119,18 @@ public class Agent { Properties arg_props = parseString(args); // Read properties from the config file - Properties config_props = new Properties(); - String fname = arg_props.getProperty(CONFIG_FILE); - readConfiguration(fname, config_props); + Properties config_props = new Properties(); + String fname = arg_props.getProperty(CONFIG_FILE); + readConfiguration(fname, config_props); - // Arguments override config file - config_props.putAll(arg_props); - startAgent(config_props); + // Arguments override config file + config_props.putAll(arg_props); + startAgent(config_props); } // jcmd ManagementAgent.start_local entry point // Also called due to command-line via startAgent() - private static synchronized void startLocalManagementAgent(){ + private static synchronized void startLocalManagementAgent() { Properties agentProps = VMSupport.getAgentProperties(); // start local connector if not started @@ -156,7 +160,7 @@ public class Agent { throw new RuntimeException(getText(INVALID_STATE, "Agent already started")); } - Properties argProps = parseString(args); + Properties argProps = parseString(args); Properties configProps = new Properties(); // Load the management properties from the config file @@ -169,7 +173,7 @@ public class Agent { // management properties can be overridden by system properties // which take precedence Properties sysProps = System.getProperties(); - synchronized(sysProps){ + synchronized (sysProps) { configProps.putAll(sysProps); } @@ -190,21 +194,26 @@ public class Agent { // can specify this property inside config file, so enable optional // monitoring functionality if this property is set final String enableThreadContentionMonitoring = - configProps.getProperty(ENABLE_THREAD_CONTENTION_MONITORING); + configProps.getProperty(ENABLE_THREAD_CONTENTION_MONITORING); if (enableThreadContentionMonitoring != null) { ManagementFactory.getThreadMXBean(). - setThreadContentionMonitoringEnabled(true); + setThreadContentionMonitoringEnabled(true); } String jmxremotePort = configProps.getProperty(JMXREMOTE_PORT); if (jmxremotePort != null) { jmxServer = ConnectorBootstrap. - startRemoteConnectorServer(jmxremotePort, configProps); + startRemoteConnectorServer(jmxremotePort, configProps); + + startDiscoveryService(configProps); } } private static synchronized void stopRemoteManagementAgent() throws Exception { + + JdpController.stopDiscoveryService(); + if (jmxServer != null) { ConnectorBootstrap.unexportRegistry(); @@ -222,15 +231,15 @@ public class Agent { // Enable optional monitoring functionality if requested final String enableThreadContentionMonitoring = - props.getProperty(ENABLE_THREAD_CONTENTION_MONITORING); + props.getProperty(ENABLE_THREAD_CONTENTION_MONITORING); if (enableThreadContentionMonitoring != null) { ManagementFactory.getThreadMXBean(). - setThreadContentionMonitoringEnabled(true); + setThreadContentionMonitoringEnabled(true); } try { if (snmpPort != null) { - loadSnmpAgent(snmpPort, props); + loadSnmpAgent(snmpPort, props); } /* @@ -242,13 +251,14 @@ public class Agent { * of this "local" server is exported as a counter to the jstat * instrumentation buffer. */ - if (jmxremote != null || jmxremotePort != null) { + if (jmxremote != null || jmxremotePort != null) { if (jmxremotePort != null) { - jmxServer = ConnectorBootstrap. - startRemoteConnectorServer(jmxremotePort, props); + jmxServer = ConnectorBootstrap. + startRemoteConnectorServer(jmxremotePort, props); + startDiscoveryService(props); } startLocalManagementAgent(); - } + } } catch (AgentConfigurationError e) { error(e.getError(), e.getParams()); @@ -257,6 +267,73 @@ public class Agent { } } + private static void startDiscoveryService(Properties props) + throws IOException { + // Start discovery service if requested + String discoveryPort = props.getProperty("com.sun.management.jdp.port"); + String discoveryAddress = props.getProperty("com.sun.management.jdp.address"); + String discoveryShouldStart = props.getProperty("com.sun.management.jmxremote.autodiscovery"); + + // Decide whether we should start autodicovery service. + // To start autodiscovery following conditions should be met: + // autodiscovery==true OR (autodicovery==null AND jdp.port != NULL) + + boolean shouldStart = false; + if (discoveryShouldStart == null){ + shouldStart = (discoveryPort != null); + } + else{ + try{ + shouldStart = Boolean.parseBoolean(discoveryShouldStart); + } catch (NumberFormatException e) { + throw new AgentConfigurationError("Couldn't parse autodiscovery argument"); + } + } + + if (shouldStart) { + // port and address are required arguments and have no default values + InetAddress address; + try { + address = (discoveryAddress == null) ? + InetAddress.getByName(JDP_DEFAULT_ADDRESS) : InetAddress.getByName(discoveryAddress); + } catch (UnknownHostException e) { + throw new AgentConfigurationError("Unable to broadcast to requested address", e); + } + + int port = JDP_DEFAULT_PORT; + if (discoveryPort != null) { + try { + port = Integer.parseInt(discoveryPort); + } catch (NumberFormatException e) { + throw new AgentConfigurationError("Couldn't parse JDP port argument"); + } + } + + // Rebuilding service URL to broadcast it + String jmxremotePort = props.getProperty(JMXREMOTE_PORT); + String rmiPort = props.getProperty(RMI_PORT); + + JMXServiceURL url = jmxServer.getAddress(); + String hostname = url.getHost(); + + String jmxUrlStr = (rmiPort != null) + ? String.format( + "service:jmx:rmi://%s:%s/jndi/rmi://%s:%s/jmxrmi", + hostname, rmiPort, hostname, jmxremotePort) + : String.format( + "service:jmx:rmi:///jndi/rmi://%s:%s/jmxrmi", hostname, jmxremotePort); + + String instanceName = System.getProperty("com.sun.management.jdp.name"); + + try{ + JdpController.startDiscoveryService(address, port, instanceName, jmxUrlStr); + } + catch(JdpException e){ + throw new AgentConfigurationError("Couldn't start JDP service", e); + } + } + } + public static Properties loadManagementProperties() { Properties props = new Properties(); @@ -268,22 +345,22 @@ public class Agent { // management properties can be overridden by system properties // which take precedence Properties sysProps = System.getProperties(); - synchronized(sysProps){ + synchronized (sysProps) { props.putAll(sysProps); } return props; - } + } - public static synchronized Properties getManagementProperties() { + public static synchronized Properties getManagementProperties() { if (mgmtProps == null) { String configFile = System.getProperty(CONFIG_FILE); String snmpPort = System.getProperty(SNMP_PORT); String jmxremote = System.getProperty(JMXREMOTE); String jmxremotePort = System.getProperty(JMXREMOTE_PORT); - if (configFile == null && snmpPort == null && - jmxremote == null && jmxremotePort == null) { + if (configFile == null && snmpPort == null + && jmxremote == null && jmxremotePort == null) { // return if out-of-the-management option is not specified return null; } @@ -297,22 +374,23 @@ public class Agent { // invoke the following through reflection: // AdaptorBootstrap.initialize(snmpPort, props); final Class adaptorClass = - Class.forName(SNMP_ADAPTOR_BOOTSTRAP_CLASS_NAME,true,null); + Class.forName(SNMP_ADAPTOR_BOOTSTRAP_CLASS_NAME, true, null); final Method initializeMethod = adaptorClass.getMethod("initialize", - String.class, Properties.class); - initializeMethod.invoke(null,snmpPort,props); + String.class, Properties.class); + initializeMethod.invoke(null, snmpPort, props); } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException x) { // snmp runtime doesn't exist - initialization fails - throw new UnsupportedOperationException("Unsupported management property: " + SNMP_PORT,x); + throw new UnsupportedOperationException("Unsupported management property: " + SNMP_PORT, x); } catch (InvocationTargetException x) { final Throwable cause = x.getCause(); - if (cause instanceof RuntimeException) + if (cause instanceof RuntimeException) { throw (RuntimeException) cause; - else if (cause instanceof Error) + } else if (cause instanceof Error) { throw (Error) cause; + } // should not happen... - throw new UnsupportedOperationException("Unsupported management property: " + SNMP_PORT,cause); + throw new UnsupportedOperationException("Unsupported management property: " + SNMP_PORT, cause); } } @@ -353,8 +431,8 @@ public class Agent { } catch (IOException e) { error(CONFIG_FILE_CLOSE_FAILED, fname); } - } - } + } + } } public static void startAgent() throws Exception { @@ -389,9 +467,9 @@ public class Agent { // invoke the premain(String args) method Class clz = ClassLoader.getSystemClassLoader().loadClass(cname); Method premain = clz.getMethod("premain", - new Class[] { String.class }); + new Class[]{String.class}); premain.invoke(null, /* static */ - new Object[] { args }); + new Object[]{args}); } catch (ClassNotFoundException ex) { error(AGENT_CLASS_NOT_FOUND, "\"" + cname + "\""); } catch (NoSuchMethodException ex) { @@ -400,8 +478,8 @@ public class Agent { error(AGENT_CLASS_ACCESS_DENIED); } catch (Exception ex) { String msg = (ex.getCause() == null - ? ex.getMessage() - : ex.getCause().getMessage()); + ? ex.getMessage() + : ex.getCause().getMessage()); error(AGENT_CLASS_FAILED, msg); } } @@ -425,7 +503,6 @@ public class Agent { } } - public static void error(String key, String message) { String keyText = getText(key); System.err.print(getText("agent.err.error") + ": " + keyText); @@ -447,7 +524,7 @@ public class Agent { private static void initResource() { try { messageRB = - ResourceBundle.getBundle("sun.management.resources.agent"); + ResourceBundle.getBundle("sun.management.resources.agent"); } catch (MissingResourceException e) { throw new Error("Fatal: Resource for management agent is missing"); } @@ -470,10 +547,9 @@ public class Agent { } String format = messageRB.getString(key); if (format == null) { - format = "missing resource key: key = \"" + key + "\", " + - "arguments = \"{0}\", \"{1}\", \"{2}\""; + format = "missing resource key: key = \"" + key + "\", " + + "arguments = \"{0}\", \"{1}\", \"{2}\""; } return MessageFormat.format(format, (Object[]) args); } - } diff --git a/jdk/src/share/classes/sun/management/jdp/JdpBroadcaster.java b/jdk/src/share/classes/sun/management/jdp/JdpBroadcaster.java new file mode 100644 index 00000000000..b1766e6f7f6 --- /dev/null +++ b/jdk/src/share/classes/sun/management/jdp/JdpBroadcaster.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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.management.jdp; + +import java.io.IOException; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.NetworkInterface; +import java.net.ProtocolFamily; +import java.net.StandardProtocolFamily; +import java.net.StandardSocketOptions; +import java.nio.ByteBuffer; +import java.nio.channels.DatagramChannel; +import java.nio.channels.UnsupportedAddressTypeException; + +/** + * JdpBroadcaster is responsible for sending pre-built JDP packet across a Net + * + *

      Multicast group address, port number and ttl have to be chosen on upper + * level and passed to broadcaster constructor. Also it's possible to specify + * source address to broadcast from.

      + * + *

      JdpBradcaster doesn't perform any validation on a supplied {@code port} and {@code ttl} because + * the allowed values depend on an operating system setup

      + * + */ +public final class JdpBroadcaster { + + private final InetAddress addr; + private final int port; + private final DatagramChannel channel; + + /** + * Create a new broadcaster + * + * @param address - multicast group address + * @param srcAddress - address of interface we should use to broadcast. + * @param port - udp port to use + * @param ttl - packet ttl + * @throws IOException + */ + public JdpBroadcaster(InetAddress address, InetAddress srcAddress, int port, int ttl) + throws IOException, JdpException { + this.addr = address; + this.port = port; + + ProtocolFamily family = (address instanceof Inet6Address) + ? StandardProtocolFamily.INET6 : StandardProtocolFamily.INET; + + channel = DatagramChannel.open(family); + channel.setOption(StandardSocketOptions.SO_REUSEADDR, true); + channel.setOption(StandardSocketOptions.IP_MULTICAST_TTL, ttl); + + // with srcAddress equal to null, this constructor do exactly the same as + // if srcAddress is not passed + if (srcAddress != null) { + // User requests particular interface to bind to + NetworkInterface interf = NetworkInterface.getByInetAddress(srcAddress); + try { + channel.bind(new InetSocketAddress(srcAddress, 0)); + } catch (UnsupportedAddressTypeException ex) { + throw new JdpException("Unable to bind to source address"); + } + channel.setOption(StandardSocketOptions.IP_MULTICAST_IF, interf); + } + } + + /** + * Create a new broadcaster + * + * @param address - multicast group address + * @param port - udp port to use + * @param ttl - packet ttl + * @throws IOException + */ + public JdpBroadcaster(InetAddress address, int port, int ttl) + throws IOException, JdpException { + this(address, null, port, ttl); + } + + /** + * Broadcast pre-built packet + * + * @param packet - instance of JdpPacket + * @throws IOException + */ + public void sendPacket(JdpPacket packet) + throws IOException { + byte[] data = packet.getPacketData(); + // Unlike allocate/put wrap don't need a flip afterward + ByteBuffer b = ByteBuffer.wrap(data); + channel.send(b, new InetSocketAddress(addr, port)); + } + + /** + * Shutdown broadcaster and close underlying socket channel + * + * @throws IOException + */ + public void shutdown() throws IOException { + channel.close(); + } +} diff --git a/jdk/src/share/classes/sun/management/jdp/JdpController.java b/jdk/src/share/classes/sun/management/jdp/JdpController.java new file mode 100644 index 00000000000..3083c972cac --- /dev/null +++ b/jdk/src/share/classes/sun/management/jdp/JdpController.java @@ -0,0 +1,198 @@ +/* + * 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.management.jdp; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.UUID; + +/** + * JdpController is responsible to create and manage a broadcast loop + * + *

      Other part of code has no access to broadcast loop and have to use + * provided static methods + * {@link #startDiscoveryService(InetAddress,int,String,String) startDiscoveryService} + * and {@link #stopDiscoveryService() stopDiscoveryService}

      + *

      {@link #startDiscoveryService(InetAddress,int,String,String) startDiscoveryService} could be called multiple + * times as it stops the running service if it is necessary. Call to {@link #stopDiscoveryService() stopDiscoveryService} + * ignored if service isn't run

      + * + * + *

      + * + *

      System properties below could be used to control broadcast loop behavior. + * Property below have to be set explicitly in command line. It's not possible to + * set it in management.config file. Careless changes of these properties could + * lead to security or network issues. + *

        + *
      • com.sun.management.jdp.ttl - set ttl for broadcast packet
      • + *
      • com.sun.management.jdp.pause - set broadcast interval in seconds
      • + *
      • com.sun.management.jdp.source_addr - an address of interface to use for broadcast
      • + *
      +

      + *

      null parameters values are filtered out on {@link JdpPacketWriter} level and + * corresponding keys are not placed to packet.

      + */ +public final class JdpController { + + private static class JDPControllerRunner implements Runnable { + + private final JdpJmxPacket packet; + private final JdpBroadcaster bcast; + private final int pause; + private volatile boolean shutdown = false; + + private JDPControllerRunner(JdpBroadcaster bcast, JdpJmxPacket packet, int pause) { + this.bcast = bcast; + this.packet = packet; + this.pause = pause; + } + + @Override + public void run() { + try { + while (!shutdown) { + bcast.sendPacket(packet); + try { + Thread.sleep(this.pause); + } catch (InterruptedException e) { + // pass + } + } + + } catch (IOException e) { + // pass; + } + + // It's not possible to re-use controller, + // nevertheless reset shutdown variable + try { + stop(); + bcast.shutdown(); + } catch (IOException ex) { + // pass - ignore IOException during shutdown + } + } + + public void stop() { + shutdown = true; + } + } + private static JDPControllerRunner controller = null; + + private JdpController(){ + // Don't allow to instantiate this class. + } + + // Utility to handle optional system properties + // Parse an integer from string or return default if provided string is null + private static int getInteger(String val, int dflt, String msg) throws JdpException { + try { + return (val == null) ? dflt : Integer.parseInt(val); + } catch (NumberFormatException ex) { + throw new JdpException(msg); + } + } + + // Parse an inet address from string or return default if provided string is null + private static InetAddress getInetAddress(String val, InetAddress dflt, String msg) throws JdpException { + try { + return (val == null) ? dflt : InetAddress.getByName(val); + } catch (UnknownHostException ex) { + throw new JdpException(msg); + } + } + + /** + * Starts discovery service + * + * @param address - multicast group address + * @param port - udp port to use + * @param instanceName - name of running JVM instance + * @param url - JMX service url + * @throws IOException + */ + public static synchronized void startDiscoveryService(InetAddress address, int port, String instanceName, String url) + throws IOException, JdpException { + + // Limit packet to local subnet by default + int ttl = getInteger( + System.getProperty("com.sun.management.jdp.ttl"), 1, + "Invalid jdp packet ttl"); + + // Broadcast once a 5 seconds by default + int pause = getInteger( + System.getProperty("com.sun.management.jdp.pause"), 5, + "Invalid jdp pause"); + + // Converting seconds to milliseconds + pause = pause * 1000; + + // Allow OS to choose broadcast source + InetAddress sourceAddress = getInetAddress( + System.getProperty("com.sun.management.jdp.source_addr"), null, + "Invalid source address provided"); + + // Generate session id + UUID id = UUID.randomUUID(); + + JdpJmxPacket packet = new JdpJmxPacket(id, url); + + // Don't broadcast whole command line for security reason. + // Strip everything after first space + String javaCommand = System.getProperty("sun.java.command"); + if (javaCommand != null) { + String[] arr = javaCommand.split(" ", 2); + packet.setMainClass(arr[0]); + } + + // Put optional explicit java instance name to packet, if user doesn't specify + // it the key is skipped. PacketWriter is responsible to skip keys having null value. + packet.setInstanceName(instanceName); + + JdpBroadcaster bcast = new JdpBroadcaster(address, sourceAddress, port, ttl); + + // Stop discovery service if it's already running + stopDiscoveryService(); + + controller = new JDPControllerRunner(bcast, packet, pause); + + Thread t = new Thread(controller, "JDP broadcaster"); + t.setDaemon(true); + t.start(); + } + + /** + * Stop running discovery service, + * it's safe to attempt to stop not started service + */ + public static synchronized void stopDiscoveryService() { + if ( controller != null ){ + controller.stop(); + controller = null; + } + } +} diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/EventDispatchAccess.java b/jdk/src/share/classes/sun/management/jdp/JdpException.java similarity index 65% rename from jdk/src/macosx/classes/sun/lwawt/macosx/EventDispatchAccess.java rename to jdk/src/share/classes/sun/management/jdp/JdpException.java index 1124d123757..7c312d45db7 100644 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/EventDispatchAccess.java +++ b/jdk/src/share/classes/sun/management/jdp/JdpException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 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 @@ -22,18 +22,21 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +package sun.management.jdp; -package sun.lwawt.macosx; +/** + * An Exception thrown if a JDP implementation encounters a problem. + */ +public final class JdpException extends Exception { -// This exists strictly to work around the fact that java.awt.Conditional isn't a public class. -// It uses java reflection to get the EventDispatchThread class and call a MacOSX only -// method on it. -// -// NOTE: This uses reflection in its implementation, so it is not for performance critical code. -// -// See java.awt.EventDispatchThread and apple.awt.CPrintJob for more. -// -public abstract class EventDispatchAccess { - public native void pumpEventsAndWait(); - public abstract boolean evaluate(); + private static final long serialVersionUID = 1L; + + /** + * Construct a new JDP exception with a meaningful message + * + * @param msg - message + */ + public JdpException(String msg) { + super(msg); + } } diff --git a/jdk/src/share/classes/sun/management/jdp/JdpGenericPacket.java b/jdk/src/share/classes/sun/management/jdp/JdpGenericPacket.java new file mode 100644 index 00000000000..74b8a589568 --- /dev/null +++ b/jdk/src/share/classes/sun/management/jdp/JdpGenericPacket.java @@ -0,0 +1,97 @@ +/* + * 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.management.jdp; + +/** + * JdpGenericPacket responsible to provide fields + * common for all Jdp packets + */ +public abstract class JdpGenericPacket implements JdpPacket { + + /** + * JDP protocol magic. Magic allows a reader to quickly select + * JDP packets from a bunch of broadcast packets addressed to the same port + * and broadcast group. Any packet intended to be parsed by JDP client + * has to start from this magic. + */ + private static final int MAGIC = 0xC0FFEE42; + + /** + * Current version of protocol. Any implementation of this protocol has to + * conform with the packet structure and the flow described in JEP-168 + */ + private static final short PROTOCOL_VERSION = 1; + + /** + * Default do-nothing constructor + */ + protected JdpGenericPacket(){ + // do nothing + } + + + /** + * Validate protocol header magic field + * + * @param magic - value to validate + * @throws JdpException + */ + public static void checkMagic(int magic) + throws JdpException { + if (magic != MAGIC) { + throw new JdpException("Invalid JDP magic header: " + magic); + } + } + + /** + * Validate protocol header version field + * + * @param version - value to validate + * @throws JdpException + */ + public static void checkVersion(short version) + throws JdpException { + + if (version > PROTOCOL_VERSION) { + throw new JdpException("Unsupported protocol version: " + version); + } + } + + /** + * + * @return protocol magic + */ + public static int getMagic() { + return MAGIC; + } + + /** + * + * @return current protocol version + */ + public static short getVersion() { + return PROTOCOL_VERSION; + } +} diff --git a/jdk/src/share/classes/sun/management/jdp/JdpJmxPacket.java b/jdk/src/share/classes/sun/management/jdp/JdpJmxPacket.java new file mode 100644 index 00000000000..60aea2bd40f --- /dev/null +++ b/jdk/src/share/classes/sun/management/jdp/JdpJmxPacket.java @@ -0,0 +1,198 @@ +/* + * 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.management.jdp; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; + +/** + * A packet to broadcasts JMX URL + * + * Fields: + * + *
        + *
      • UUID - broadcast session ID, changed every time when we start/stop + * discovery service
      • + *
      • JMX_URL - URL to connect to JMX service
      • + *
      • MAIN_CLASS - optional name of main class, filled from sun.java.command stripped for + * security reason to first space
      • + *
      • INSTANCE_NAME - optional custom name of particular instance as provided by customer
      • + *
      + */ +public final class JdpJmxPacket + extends JdpGenericPacket + implements JdpPacket { + + /** + * Session ID + */ + public final static String UUID_KEY = "DISCOVERABLE_SESSION_UUID"; + /** + * Name of main class + */ + public final static String MAIN_CLASS_KEY = "MAIN_CLASS"; + /** + * JMX service URL + */ + public final static String JMX_SERVICE_URL_KEY = "JMX_SERVICE_URL"; + /** + * Name of Java instance + */ + public final static String INSTANCE_NAME_KEY = "INSTANCE_NAME"; + + private UUID id; + private String mainClass; + private String jmxServiceUrl; + private String instanceName; + + /** + * Create new instance from user provided data. Set mandatory fields + * + * @param id - java instance id + * @param jmxServiceUrl - JMX service url + */ + public JdpJmxPacket(UUID id, String jmxServiceUrl) { + this.id = id; + this.jmxServiceUrl = jmxServiceUrl; + } + + /** + * Create new instance from network data Parse packet and set fields. + * + * @param data - raw packet data as it came from a Net + * @throws JdpException + */ + public JdpJmxPacket(byte[] data) + throws JdpException { + JdpPacketReader reader; + + reader = new JdpPacketReader(data); + Map p = reader.getDiscoveryDataAsMap(); + + String sId = p.get(UUID_KEY); + this.id = (sId == null) ? null : UUID.fromString(sId); + this.jmxServiceUrl = p.get(JMX_SERVICE_URL_KEY); + this.mainClass = p.get(MAIN_CLASS_KEY); + this.instanceName = p.get(INSTANCE_NAME_KEY); + } + + /** + * Set main class field + * + * @param mainClass - main class of running app + */ + public void setMainClass(String mainClass) { + this.mainClass = mainClass; + } + + /** + * Set instance name field + * + * @param instanceName - name of instance as provided by customer + */ + public void setInstanceName(String instanceName) { + this.instanceName = instanceName; + } + + /** + * @return id of discovery session + */ + public UUID getId() { + return id; + } + + /** + * + * @return main class field + */ + public String getMainClass() { + return mainClass; + } + + /** + * + * @return JMX service URL + */ + public String getJmxServiceUrl() { + return jmxServiceUrl; + } + + /** + * + * @return instance name + */ + public String getInstanceName() { + return instanceName; + } + + /** + * + * @return assembled packet ready to be sent across a Net + * @throws IOException + */ + @Override + public byte[] getPacketData() throws IOException { + // Assemble packet from fields to byte array + JdpPacketWriter writer; + writer = new JdpPacketWriter(); + writer.addEntry(UUID_KEY, (id == null) ? null : id.toString()); + writer.addEntry(MAIN_CLASS_KEY, mainClass); + writer.addEntry(JMX_SERVICE_URL_KEY, jmxServiceUrl); + writer.addEntry(INSTANCE_NAME_KEY, instanceName); + return writer.getPacketBytes(); + } + + /** + * + * @return packet hash code + */ + @Override + public int hashCode() { + int hash = 1; + hash = hash * 31 + id.hashCode(); + hash = hash * 31 + jmxServiceUrl.hashCode(); + return hash; + } + + /** + * Compare two packets + * + * @param o - packet to compare + * @return either packet equals or not + */ + @Override + public boolean equals(Object o) { + + if (o == null || ! (o instanceof JdpJmxPacket) ){ + return false; + } + + JdpJmxPacket p = (JdpJmxPacket) o; + return Objects.equals(id, p.getId()) && Objects.equals(jmxServiceUrl, p.getJmxServiceUrl()); + } +} diff --git a/jdk/src/share/classes/sun/management/jdp/JdpPacket.java b/jdk/src/share/classes/sun/management/jdp/JdpPacket.java new file mode 100644 index 00000000000..9260112a52f --- /dev/null +++ b/jdk/src/share/classes/sun/management/jdp/JdpPacket.java @@ -0,0 +1,64 @@ +/* + * 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.management.jdp; + +import java.io.IOException; + +/** + * Packet to broadcast + * + *

      Each packet have to contain MAGIC and PROTOCOL_VERSION in order to be + * recognized as a valid JDP packet.

      + * + *

      Default implementation build packet as a set of UTF-8 encoded Key/Value pairs + * are stored as an ordered list of values, and are sent to the server + * in that order.

      + * + *

      + * Packet structure: + * + * 4 bytes JDP magic (0xC0FFE42) + * 2 bytes JDP protocol version (01) + * + * 2 bytes size of key + * x bytes key (UTF-8 encoded) + * 2 bytes size of value + * x bytes value (UTF-8 encoded) + * + * repeat as many times as necessary ... + *

      + */ +public interface JdpPacket { + + /** + * This method responsible to assemble packet and return a byte array + * ready to be sent across a Net. + * + * @return assembled packet as an array of bytes + * @throws IOException + */ + public byte[] getPacketData() throws IOException; + +} diff --git a/jdk/src/share/classes/sun/management/jdp/JdpPacketReader.java b/jdk/src/share/classes/sun/management/jdp/JdpPacketReader.java new file mode 100644 index 00000000000..f69c07d6c0c --- /dev/null +++ b/jdk/src/share/classes/sun/management/jdp/JdpPacketReader.java @@ -0,0 +1,141 @@ +/* + * 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.management.jdp; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * JdpPacketReader responsible for reading a packet

      This class gets a byte + * array as it came from a Net, validates it and breaks a part

      + */ +public final class JdpPacketReader { + + private final DataInputStream pkt; + private Map pmap = null; + + /** + * Create packet reader, extract and check magic and version + * + * @param packet - packet received from a Net + * @throws JdpException + */ + public JdpPacketReader(byte[] packet) + throws JdpException { + ByteArrayInputStream bais = new ByteArrayInputStream(packet); + pkt = new DataInputStream(bais); + + try { + int magic = pkt.readInt(); + JdpGenericPacket.checkMagic(magic); + } catch (IOException e) { + throw new JdpException("Invalid JDP packet received, bad magic"); + } + + try { + short version = pkt.readShort(); + JdpGenericPacket.checkVersion(version); + } catch (IOException e) { + throw new JdpException("Invalid JDP packet received, bad protocol version"); + } + } + + /** + * Get next entry from packet + * + * @return the entry + * @throws EOFException + * @throws JdpException + */ + public String getEntry() + throws EOFException, JdpException { + + try { + short len = pkt.readShort(); + // Artificial setting the "len" field to Short.MAX_VALUE may cause a reader to allocate + // to much memory. Prevent this possible DOS attack. + if (len < 1 && len > pkt.available()) { + throw new JdpException("Broken JDP packet. Invalid entry length field."); + } + + byte[] b = new byte[len]; + if (pkt.read(b) != len) { + throw new JdpException("Broken JDP packet. Unable to read entry."); + } + return new String(b, "UTF-8"); + + } catch (EOFException e) { + throw e; + } catch (UnsupportedEncodingException ex) { + throw new JdpException("Broken JDP packet. Unable to decode entry."); + } catch (IOException e) { + throw new JdpException("Broken JDP packet. Unable to read entry."); + } + + + } + + /** + * return packet content as a key/value map + * + * @return map containing packet entries pair of entries treated as + * key,value + * @throws IOException + * @throws JdpException + */ + public Map getDiscoveryDataAsMap() + throws JdpException { + // return cached map if possible + if (pmap != null) { + return pmap; + } + + String key = null, value = null; + + final Map tmpMap = new HashMap<>(); + try { + while (true) { + key = getEntry(); + value = getEntry(); + tmpMap.put(key, value); + } + } catch (EOFException e) { + // EOF reached on reading value, report broken packet + // otherwise ignore it. + if (value == null) { + throw new JdpException("Broken JDP packet. Key without value." + key); + } + } + + pmap = Collections.unmodifiableMap(tmpMap); + return pmap; + } +} diff --git a/jdk/src/share/classes/sun/management/jdp/JdpPacketWriter.java b/jdk/src/share/classes/sun/management/jdp/JdpPacketWriter.java new file mode 100644 index 00000000000..2af2fdc0100 --- /dev/null +++ b/jdk/src/share/classes/sun/management/jdp/JdpPacketWriter.java @@ -0,0 +1,95 @@ +/* + * 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.management.jdp; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * JdpPacketWriter responsible for writing a packet + *

      This class assembles a set of key/value pairs to valid JDP packet, + * ready to be sent across a Net

      + */ +public final class JdpPacketWriter { + + private final ByteArrayOutputStream baos; + private final DataOutputStream pkt; + + /** + * Create a JDP packet, add mandatory magic and version headers + * + * @throws IOException + */ + public JdpPacketWriter() + throws IOException { + baos = new ByteArrayOutputStream(); + pkt = new DataOutputStream(baos); + + pkt.writeInt(JdpGenericPacket.getMagic()); + pkt.writeShort(JdpGenericPacket.getVersion()); + } + + /** + * Put string entry to packet + * + * @param entry - string to put (utf-8 encoded) + * @throws IOException + */ + public void addEntry(String entry) + throws IOException { + pkt.writeShort(entry.length()); + byte[] b = entry.getBytes("UTF-8"); + pkt.write(b); + } + + /** + * Put key/value pair to packet + * + * @param key - key to put (utf-8 encoded) + * @param val - value to put (utf-8 encoded) + * @throws IOException + */ + public void addEntry(String key, String val) + throws IOException { + /* Silently skip key if value is null. + * We don't need to distinguish between key missing + * and key has no value cases + */ + if (val != null) { + addEntry(key); + addEntry(val); + } + } + + /** + * Return assembled packet as a byte array + * + * @return packet bytes + */ + public byte[] getPacketBytes() { + return baos.toByteArray(); + } +} diff --git a/jdk/src/share/classes/sun/management/jdp/package-info.java b/jdk/src/share/classes/sun/management/jdp/package-info.java new file mode 100644 index 00000000000..4a0d169efa7 --- /dev/null +++ b/jdk/src/share/classes/sun/management/jdp/package-info.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/** + * Summary + * ------- + * + * Define a lightweight network protocol for discovering running and + * manageable Java processes within a network subnet. + * + * + * Description + * ----------- + * + * The protocol is lightweight multicast based, and works like a beacon, + * broadcasting the JMXService URL needed to connect to the external JMX + * agent if an application is started with appropriate parameters. + * + * The payload is structured like this: + * + * 4 bytes JDP magic (0xC0FFEE42) + * 2 bytes JDP protocol version (1) + * 2 bytes size of the next entry + * x bytes next entry (UTF-8 encoded) + * 2 bytes size of next entry + * ... Rinse and repeat... + * + * The payload will be parsed as even entries being keys, odd entries being + * values. + * + * The standard JDP packet contains four entries: + * + * - `DISCOVERABLE_SESSION_UUID` -- Unique id of the instance; this id changes every time + * the discovery protocol starts and stops + * + * - `MAIN_CLASS` -- The value of the `sun.java.command` property + * + * - `JMX_SERVICE_URL` -- The URL to connect to the JMX agent + * + * - `INSTANCE_NAME` -- The user-provided name of the running instance + * + * The protocol sends packets to 239.255.255.225:7095 by default. + * + * The protocol uses system properties to control it's behaviour: + * - `com.sun.management.jdp.port` -- override default port + * + * - `com.sun.management.jdp.address` -- override default address + * + * - `com.sun.management.jmxremote.autodiscovery` -- whether we should start autodiscovery or + * not. Autodiscovery starts if and only if following conditions are met: (autodiscovery is + * true OR (autodiscovery is not set AND jdp.port is set)) + * + * - `com.sun.management.jdp.ttl` -- set ttl for broadcast packet, default is 1 + * - `com.sun.management.jdp.pause` -- set broadcast interval in seconds default is 5 + * - `com.sun.management.jdp.source_addr` -- an address of interface to use for broadcast + */ + +package sun.management.jdp; diff --git a/jdk/src/share/classes/sun/misc/JavaLangAccess.java b/jdk/src/share/classes/sun/misc/JavaLangAccess.java index 9506194c707..db8d8213179 100644 --- a/jdk/src/share/classes/sun/misc/JavaLangAccess.java +++ b/jdk/src/share/classes/sun/misc/JavaLangAccess.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 @@ -26,6 +26,7 @@ package sun.misc; import java.lang.annotation.Annotation; +import java.lang.reflect.Executable; import sun.reflect.ConstantPool; import sun.reflect.annotation.AnnotationType; import sun.nio.ch.Interruptible; @@ -46,6 +47,18 @@ public interface JavaLangAccess { */ AnnotationType getAnnotationType(Class klass); + /** + * Get the array of bytes that is the class-file representation + * of this Class' type annotations. + */ + byte[] getRawClassTypeAnnotations(Class klass); + + /** + * Get the array of bytes that is the class-file representation + * of this Executable's type annotations. + */ + byte[] getRawExecutableTypeAnnotations(Executable executable); + /** * Returns the elements of an enum class or null if the * Class object does not represent an enum type; @@ -84,9 +97,4 @@ public interface JavaLangAccess { * Returns the ith StackTraceElement for the given throwable. */ StackTraceElement getStackTraceElement(Throwable t, int i); - - /** - * Returns a directly present annotation. - */ - public A getDirectDeclaredAnnotation(Class klass, Class anno); } diff --git a/jdk/src/share/classes/sun/reflect/LangReflectAccess.java b/jdk/src/share/classes/sun/reflect/LangReflectAccess.java index fba1d318086..3c3b2757410 100644 --- a/jdk/src/share/classes/sun/reflect/LangReflectAccess.java +++ b/jdk/src/share/classes/sun/reflect/LangReflectAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2004, 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 @@ -81,6 +81,9 @@ public interface LangReflectAccess { public void setConstructorAccessor(Constructor c, ConstructorAccessor accessor); + /** Gets the byte[] that encodes TypeAnnotations on an Executable. */ + public byte[] getExecutableTypeAnnotationBytes(Executable ex); + /** Gets the "slot" field from a Constructor (used for serialization) */ public int getConstructorSlot(Constructor c); diff --git a/jdk/src/share/classes/sun/reflect/ReflectionFactory.java b/jdk/src/share/classes/sun/reflect/ReflectionFactory.java index ea5323b8b9a..de97dfc7001 100644 --- a/jdk/src/share/classes/sun/reflect/ReflectionFactory.java +++ b/jdk/src/share/classes/sun/reflect/ReflectionFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, 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 @@ -26,6 +26,7 @@ package sun.reflect; import java.lang.reflect.Field; +import java.lang.reflect.Executable; import java.lang.reflect.Method; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; @@ -314,6 +315,12 @@ public class ReflectionFactory { return langReflectAccess().copyConstructor(arg); } + /** Gets the byte[] that encodes TypeAnnotations on an executable. + */ + public byte[] getExecutableTypeAnnotationBytes(Executable ex) { + return langReflectAccess().getExecutableTypeAnnotationBytes(ex); + } + //-------------------------------------------------------------------------- // // Routines used by serialization diff --git a/jdk/src/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java b/jdk/src/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java new file mode 100644 index 00000000000..e9f3f957c09 --- /dev/null +++ b/jdk/src/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java @@ -0,0 +1,315 @@ +/* + * 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.reflect.annotation; + +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import static sun.reflect.annotation.TypeAnnotation.*; + +public class AnnotatedTypeFactory { + /** + * Create an AnnotatedType. + * + * @param type the type this AnnotatedType corresponds to + * @param currentLoc the location this AnnotatedType corresponds to + * @param actualTypeAnnos the type annotations this AnnotatedType has + * @param allOnSameTarget all type annotation on the same TypeAnnotationTarget + * as the AnnotatedType being built + * @param decl the declaration having the type use this AnnotatedType + * corresponds to + */ + public static AnnotatedType buildAnnotatedType(Type type, + LocationInfo currentLoc, + TypeAnnotation[] actualTypeAnnos, + TypeAnnotation[] allOnSameTarget, + AnnotatedElement decl) { + if (type == null) { + return EMPTY_ANNOTATED_TYPE; + } + if (isArray(type)) + return new AnnotatedArrayTypeImpl(type, + currentLoc, + actualTypeAnnos, + allOnSameTarget, + decl); + if (type instanceof Class) { + return new AnnotatedTypeBaseImpl(type, + addNesting(type, currentLoc), + actualTypeAnnos, + allOnSameTarget, + decl); + } else if (type instanceof TypeVariable) { + return new AnnotatedTypeVariableImpl((TypeVariable)type, + currentLoc, + actualTypeAnnos, + allOnSameTarget, + decl); + } else if (type instanceof ParameterizedType) { + return new AnnotatedParameterizedTypeImpl((ParameterizedType)type, + addNesting(type, currentLoc), + actualTypeAnnos, + allOnSameTarget, + decl); + } else if (type instanceof WildcardType) { + return new AnnotatedWildcardTypeImpl((WildcardType) type, + currentLoc, + actualTypeAnnos, + allOnSameTarget, + decl); + } + throw new AssertionError("Unknown instance of Type: " + type + "\nThis should not happen."); + } + + private static LocationInfo addNesting(Type type, LocationInfo addTo) { + if (isArray(type)) + return addTo; + if (type instanceof Class) { + Class clz = (Class)type; + if (clz.getEnclosingClass() == null) + return addTo; + return addNesting(clz.getEnclosingClass(), addTo.pushInner()); + } else if (type instanceof ParameterizedType) { + ParameterizedType t = (ParameterizedType)type; + if (t.getOwnerType() == null) + return addTo; + return addNesting(t.getOwnerType(), addTo.pushInner()); + } + return addTo; + } + + private static boolean isArray(Type t) { + if (t instanceof Class) { + Class c = (Class)t; + if (c.isArray()) + return true; + } else if (t instanceof GenericArrayType) { + return true; + } + return false; + } + + static final AnnotatedType EMPTY_ANNOTATED_TYPE = new AnnotatedTypeBaseImpl(null, LocationInfo.BASE_LOCATION, + new TypeAnnotation[0], new TypeAnnotation[0], null); + + private static class AnnotatedTypeBaseImpl implements AnnotatedType { + private final Type type; + private final AnnotatedElement decl; + private final LocationInfo location; + private final TypeAnnotation[] allOnSameTargetTypeAnnotations; + private final Map, Annotation> annotations; + + AnnotatedTypeBaseImpl(Type type, LocationInfo location, + TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations, + AnnotatedElement decl) { + this.type = type; + this.decl = decl; + this.location = location; + this.allOnSameTargetTypeAnnotations = allOnSameTargetTypeAnnotations; + this.annotations = TypeAnnotationParser.mapTypeAnnotations(location.filter(actualTypeAnnotations)); + } + + // AnnotatedElement + @Override + public final Annotation[] getAnnotations() { + return getDeclaredAnnotations(); + } + + @Override + public final T getAnnotation(Class annotation) { + return getDeclaredAnnotation(annotation); + } + + @Override + public final T[] getAnnotationsByType(Class annotation) { + return getDeclaredAnnotationsByType(annotation); + } + + @Override + public Annotation[] getDeclaredAnnotations() { + return annotations.values().toArray(new Annotation[0]); + } + + @Override + @SuppressWarnings("unchecked") + public T getDeclaredAnnotation(Class annotation) { + return (T)annotations.get(annotation); + } + + @Override + public T[] getDeclaredAnnotationsByType(Class annotation) { + return AnnotationSupport.getMultipleAnnotations(annotations, annotation); + } + + // AnnotatedType + @Override + public Type getType() { + return type; + } + + // Implementation details + LocationInfo getLocation() { + return location; + } + TypeAnnotation[] getTypeAnnotations() { + return allOnSameTargetTypeAnnotations; + } + AnnotatedElement getDecl() { + return decl; + } + } + + private static class AnnotatedArrayTypeImpl extends AnnotatedTypeBaseImpl implements AnnotatedArrayType { + AnnotatedArrayTypeImpl(Type type, LocationInfo location, + TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations, + AnnotatedElement decl) { + super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl); + } + + @Override + public AnnotatedType getAnnotatedGenericComponentType() { + return AnnotatedTypeFactory.buildAnnotatedType(getComponentType(), + getLocation().pushArray(), + getTypeAnnotations(), + getTypeAnnotations(), + getDecl()); + } + + private Type getComponentType() { + Type t = getType(); + if (t instanceof Class) { + Class c = (Class)t; + return c.getComponentType(); + } + return ((GenericArrayType)t).getGenericComponentType(); + } + } + + private static class AnnotatedTypeVariableImpl extends AnnotatedTypeBaseImpl implements AnnotatedTypeVariable { + AnnotatedTypeVariableImpl(TypeVariable type, LocationInfo location, + TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations, + AnnotatedElement decl) { + super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl); + } + + @Override + public AnnotatedType[] getAnnotatedBounds() { + return getTypeVariable().getAnnotatedBounds(); + } + + private TypeVariable getTypeVariable() { + return (TypeVariable)getType(); + } + } + + private static class AnnotatedParameterizedTypeImpl extends AnnotatedTypeBaseImpl implements AnnotatedParameterizedType { + AnnotatedParameterizedTypeImpl(ParameterizedType type, LocationInfo location, + TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations, + AnnotatedElement decl) { + super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl); + } + + @Override + public AnnotatedType[] getAnnotatedActualTypeArguments() { + Type[] arguments = getParameterizedType().getActualTypeArguments(); + AnnotatedType[] res = new AnnotatedType[arguments.length]; + Arrays.fill(res, EMPTY_ANNOTATED_TYPE); + int initialCapacity = getTypeAnnotations().length; + for (int i = 0; i < res.length; i++) { + List l = new ArrayList<>(initialCapacity); + LocationInfo newLoc = getLocation().pushTypeArg((byte)i); + for (TypeAnnotation t : getTypeAnnotations()) + if (t.getLocationInfo().isSameLocationInfo(newLoc)) + l.add(t); + res[i] = buildAnnotatedType(arguments[i], + newLoc, + l.toArray(new TypeAnnotation[0]), + getTypeAnnotations(), + getDecl()); + } + return res; + } + + private ParameterizedType getParameterizedType() { + return (ParameterizedType)getType(); + } + } + + private static class AnnotatedWildcardTypeImpl extends AnnotatedTypeBaseImpl implements AnnotatedWildcardType { + private final boolean hasUpperBounds; + AnnotatedWildcardTypeImpl(WildcardType type, LocationInfo location, + TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations, + AnnotatedElement decl) { + super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl); + hasUpperBounds = (type.getLowerBounds().length == 0); + } + + @Override + public AnnotatedType[] getAnnotatedUpperBounds() { + if (!hasUpperBounds()) + return new AnnotatedType[0]; + return getAnnotatedBounds(getWildcardType().getUpperBounds()); + } + + @Override + public AnnotatedType[] getAnnotatedLowerBounds() { + if (hasUpperBounds) + return new AnnotatedType[0]; + return getAnnotatedBounds(getWildcardType().getLowerBounds()); + } + + private AnnotatedType[] getAnnotatedBounds(Type[] bounds) { + AnnotatedType[] res = new AnnotatedType[bounds.length]; + Arrays.fill(res, EMPTY_ANNOTATED_TYPE); + LocationInfo newLoc = getLocation().pushWildcard(); + int initialCapacity = getTypeAnnotations().length; + for (int i = 0; i < res.length; i++) { + List l = new ArrayList<>(initialCapacity); + for (TypeAnnotation t : getTypeAnnotations()) + if (t.getLocationInfo().isSameLocationInfo(newLoc)) + l.add(t); + res[i] = buildAnnotatedType(bounds[i], + newLoc, + l.toArray(new TypeAnnotation[0]), + getTypeAnnotations(), + getDecl()); + } + return res; + } + + private WildcardType getWildcardType() { + return (WildcardType)getType(); + } + + private boolean hasUpperBounds() { + return hasUpperBounds; + } + } +} diff --git a/jdk/src/share/classes/sun/reflect/annotation/AnnotationParser.java b/jdk/src/share/classes/sun/reflect/annotation/AnnotationParser.java index 6f26ec368b7..a980a9126ef 100644 --- a/jdk/src/share/classes/sun/reflect/annotation/AnnotationParser.java +++ b/jdk/src/share/classes/sun/reflect/annotation/AnnotationParser.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 @@ -188,7 +188,7 @@ public class AnnotationParser { * available at runtime */ @SuppressWarnings("unchecked") - private static Annotation parseAnnotation(ByteBuffer buf, + static Annotation parseAnnotation(ByteBuffer buf, ConstantPool constPool, Class container, boolean exceptionOnMissingAnnotationClass) { diff --git a/jdk/src/share/classes/sun/reflect/annotation/AnnotationSupport.java b/jdk/src/share/classes/sun/reflect/annotation/AnnotationSupport.java index 3046792b161..5ca88f90202 100644 --- a/jdk/src/share/classes/sun/reflect/annotation/AnnotationSupport.java +++ b/jdk/src/share/classes/sun/reflect/annotation/AnnotationSupport.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 @@ -27,63 +27,29 @@ package sun.reflect.annotation; import java.lang.annotation.*; import java.lang.reflect.*; -import java.util.Arrays; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Objects; -import sun.reflect.Reflection; -import sun.misc.JavaLangAccess; public final class AnnotationSupport { - private static final JavaLangAccess javaLangAccess = sun.misc.SharedSecrets.getJavaLangAccess(); - - /** - * Finds and returns _one_ annotation of the type indicated by - * {@code annotationClass} from the {@code Map} {@code - * annotationMap}. Looks into containers of the {@code - * annotationClass} (as specified by an the {@code - * annotationClass} type being meta-annotated with an {@code - * ContainedBy} annotation). - * - * @param annotationMap the {@code Map} used to store annotations and indexed by their type - * @param annotationClass the type of annotation to search for - * - * @return in instance of {@code annotationClass} or {@code null} if none were found - */ - public static A getOneAnnotation(final Map, Annotation> annotationMap, - final Class annotationClass) { - @SuppressWarnings("unchecked") - final A candidate = (A)annotationMap.get(annotationClass); - if (candidate != null) { - return candidate; - } - - final Class containerClass = getContainer(annotationClass); - if (containerClass != null) { - return unpackOne(annotationMap.get(containerClass), annotationClass); - } - - return null; // found none - } - /** * Finds and returns all annotation of the type indicated by * {@code annotationClass} from the {@code Map} {@code * annotationMap}. Looks into containers of the {@code * annotationClass} (as specified by an the {@code * annotationClass} type being meta-annotated with an {@code - * ContainedBy} annotation). + * Repeatable} annotation). * * @param annotationMap the {@code Map} used to store annotations indexed by their type * @param annotationClass the type of annotation to search for * * @return an array of instances of {@code annotationClass} or an empty array if none were found */ - public static A[] getMultipleAnnotations(final Map, Annotation> annotationMap, - final Class annotationClass) { - final ArrayList res = new ArrayList(); + public static A[] getMultipleAnnotations( + final Map, Annotation> annotationMap, + final Class annotationClass) { + final List res = new ArrayList(); @SuppressWarnings("unchecked") final A candidate = (A)annotationMap.get(annotationClass); @@ -101,49 +67,10 @@ public final class AnnotationSupport { return res.isEmpty() ? emptyTemplateArray : res.toArray(emptyTemplateArray); } - /** - * Unpacks the {@code annotationMap} parameter into an array of - * {@code Annotation}s. This method will unpack all repeating - * annotations containers (once). An annotation type is marked as a - * container by meta-annotating it the with the {@code - * ContainerFor} annotation. - * - * @param annotationMap the {@code Map} from where the annotations are unpacked - * - * @return an array of Annotation - */ - public static Annotation[] unpackToArray(Map, Annotation> annotationMap) { - List res = new ArrayList<>(); - for (Map.Entry, Annotation> e : annotationMap.entrySet()) { - Class annotationClass = e.getKey(); - Annotation annotationInstance = e.getValue(); - Class containee = getContainee(e.getKey()); - boolean isContainer = javaLangAccess.getDirectDeclaredAnnotation(annotationClass, ContainerFor.class) != null; - - if (isContainer) { - res.addAll(unpackAll(annotationInstance, containee)); - } else { - res.add(annotationInstance); - } - } - - return res.isEmpty() - ? AnnotationParser.getEmptyAnnotationArray() - : res.toArray(AnnotationParser.getEmptyAnnotationArray()); - } - /** Helper to get the container, or null if none, of an annotation. */ private static Class getContainer(Class annotationClass) { - ContainedBy containerAnnotation = - javaLangAccess.getDirectDeclaredAnnotation(annotationClass, ContainedBy.class); - return (containerAnnotation == null) ? null : containerAnnotation.value(); - } - - /** Helper to get the containee, or null if this isn't a container, of a possible container annotation. */ - private static Class getContainee(Class annotationClass) { - ContainerFor containerAnnotation = - javaLangAccess.getDirectDeclaredAnnotation(annotationClass, ContainerFor.class); - return (containerAnnotation == null) ? null : containerAnnotation.value(); + Repeatable containingAnnotation = annotationClass.getDeclaredAnnotation(Repeatable.class); + return (containingAnnotation == null) ? null : containingAnnotation.value(); } /** Reflectively look up and get the returned array from the the @@ -156,14 +83,15 @@ public final class AnnotationSupport { // value element. Get the AnnotationType, get the "value" element // and invoke it to get the contents. - Class containerClass = containerInstance.annotationType(); - AnnotationType annoType = javaLangAccess.getAnnotationType(containerClass); + Class containerClass = containerInstance.annotationType(); + AnnotationType annoType = AnnotationType.getInstance(containerClass); if (annoType == null) throw new InvalidContainerAnnotationError(containerInstance + " is an invalid container for repeating annotations"); Method m = annoType.members().get("value"); if (m == null) - throw new InvalidContainerAnnotationError(containerInstance + " is an invalid container for repeating annotations"); + throw new InvalidContainerAnnotationError(containerInstance + + " is an invalid container for repeating annotations"); m.setAccessible(true); @SuppressWarnings("unchecked") // not provably safe, but we catch the ClassCastException @@ -175,32 +103,11 @@ public final class AnnotationSupport { IllegalArgumentException | // parameters doesn't match InvocationTargetException | // the value method threw an exception ClassCastException e) { // well, a cast failed ... - throw new InvalidContainerAnnotationError(containerInstance + " is an invalid container for repeating annotations", - e, - containerInstance, - null); - } - } - - /* Sanity check type of and return the first annotation instance - * of type {@code annotationClass} from {@code - * containerInstance}. - */ - private static A unpackOne(Annotation containerInstance, Class annotationClass) { - if (containerInstance == null) { - return null; - } - - try { - return annotationClass.cast(getValueArray(containerInstance)[0]); - } catch (ArrayIndexOutOfBoundsException | // empty array - ClassCastException | // well, a cast failed ... - NullPointerException e) { // can this NP? for good meassure - throw new InvalidContainerAnnotationError(String.format("%s is an invalid container for repeating annotations of type: %s", - containerInstance, annotationClass), - e, - containerInstance, - annotationClass); + throw new InvalidContainerAnnotationError( + containerInstance + " is an invalid container for repeating annotations", + e, + containerInstance, + null); } } @@ -208,24 +115,26 @@ public final class AnnotationSupport { * instances of type {@code annotationClass} from {@code * containerInstance}. */ - private static List unpackAll(Annotation containerInstance, Class annotationClass) { + private static List unpackAll(Annotation containerInstance, + Class annotationClass) { if (containerInstance == null) { return Collections.emptyList(); // container not present } try { A[] a = getValueArray(containerInstance); - ArrayList l = new ArrayList<>(a.length); + List l = new ArrayList<>(a.length); for (int i = 0; i < a.length; i++) l.add(annotationClass.cast(a[i])); return l; } catch (ClassCastException | NullPointerException e) { - throw new InvalidContainerAnnotationError(String.format("%s is an invalid container for repeating annotations of type: %s", - containerInstance, annotationClass), - e, - containerInstance, - annotationClass); + throw new InvalidContainerAnnotationError( + String.format("%s is an invalid container for repeating annotations of type: %s", + containerInstance, annotationClass), + e, + containerInstance, + annotationClass); } } } diff --git a/jdk/src/share/classes/sun/reflect/annotation/TypeAnnotation.java b/jdk/src/share/classes/sun/reflect/annotation/TypeAnnotation.java new file mode 100644 index 00000000000..c5399725e8b --- /dev/null +++ b/jdk/src/share/classes/sun/reflect/annotation/TypeAnnotation.java @@ -0,0 +1,227 @@ +/* + * 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.reflect.annotation; + +import java.lang.annotation.Annotation; +import java.lang.annotation.AnnotationFormatError; +import java.lang.reflect.AnnotatedElement; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +/** + * A TypeAnnotation contains all the information needed to transform type + * annotations on declarations in the class file to actual Annotations in + * AnnotatedType instances. + * + * TypeAnnotaions contain a base Annotation, location info (which lets you + * distinguish between '@A Inner.@B Outer' in for example nested types), + * target info and the declaration the TypeAnnotaiton was parsed from. + */ +public class TypeAnnotation { + private final TypeAnnotationTargetInfo targetInfo; + private final LocationInfo loc; + private final Annotation annotation; + private final AnnotatedElement baseDeclaration; + + public TypeAnnotation(TypeAnnotationTargetInfo targetInfo, + LocationInfo loc, + Annotation annotation, + AnnotatedElement baseDeclaration) { + this.targetInfo = targetInfo; + this.loc = loc; + this.annotation = annotation; + this.baseDeclaration = baseDeclaration; + } + + public TypeAnnotationTargetInfo getTargetInfo() { + return targetInfo; + } + public Annotation getAnnotation() { + return annotation; + } + public AnnotatedElement getBaseDeclaration() { + return baseDeclaration; + } + public LocationInfo getLocationInfo() { + return loc; + } + + public static List filter(TypeAnnotation[] typeAnnotations, + TypeAnnotationTarget predicate) { + ArrayList typeAnnos = new ArrayList<>(typeAnnotations.length); + for (TypeAnnotation t : typeAnnotations) + if (t.getTargetInfo().getTarget() == predicate) + typeAnnos.add(t); + typeAnnos.trimToSize(); + return typeAnnos; + } + + public static enum TypeAnnotationTarget { + CLASS_TYPE_PARAMETER, + METHOD_TYPE_PARAMETER, + CLASS_EXTENDS, + CLASS_IMPLEMENTS, + CLASS_PARAMETER_BOUND, + METHOD_PARAMETER_BOUND, + METHOD_RETURN_TYPE, + METHOD_RECEIVER_TYPE, + FIELD_TYPE, + THROWS; + } + public static class TypeAnnotationTargetInfo { + private final TypeAnnotationTarget target; + private final int count; + private final int secondaryIndex; + private static final int UNUSED_INDEX = -2; // this is not a valid index in the 308 spec + + public TypeAnnotationTargetInfo(TypeAnnotationTarget target) { + this(target, UNUSED_INDEX, UNUSED_INDEX); + } + + public TypeAnnotationTargetInfo(TypeAnnotationTarget target, + int count) { + this(target, count, UNUSED_INDEX); + } + + public TypeAnnotationTargetInfo(TypeAnnotationTarget target, + int count, + int secondaryIndex) { + this.target = target; + this.count = count; + this.secondaryIndex = secondaryIndex; + } + + public TypeAnnotationTarget getTarget() { + return target; + } + public int getCount() { + return count; + } + public int getSecondaryIndex() { + return secondaryIndex; + } + + @Override + public String toString() { + return "" + target + ": " + count + ", " + secondaryIndex; + } + } + + public static class LocationInfo { + private final int depth; + private final Location[] locations; + + private LocationInfo() { + this(0, new Location[0]); + } + private LocationInfo(int depth, Location[] locations) { + this.depth = depth; + this.locations = locations; + } + + public static final LocationInfo BASE_LOCATION = new LocationInfo(); + + public static LocationInfo parseLocationInfo(ByteBuffer buf) { + int depth = buf.get(); + if (depth == 0) + return BASE_LOCATION; + Location[] locations = new Location[depth]; + for (int i = 0; i < depth; i++) { + byte tag = buf.get(); + byte index = buf.get(); + if (!(tag == 0 || tag == 1 | tag == 2 || tag == 3)) + throw new AnnotationFormatError("Bad Location encoding in Type Annotation"); + if (tag != 3 && index != 0) + throw new AnnotationFormatError("Bad Location encoding in Type Annotation"); + locations[i] = new Location(tag, index); + } + return new LocationInfo(depth, locations); + } + + public LocationInfo pushArray() { + return pushLocation((byte)0, (byte)0); + } + + public LocationInfo pushInner() { + return pushLocation((byte)1, (byte)0); + } + + public LocationInfo pushWildcard() { + return pushLocation((byte) 2, (byte) 0); + } + + public LocationInfo pushTypeArg(byte index) { + return pushLocation((byte) 3, index); + } + + public LocationInfo pushLocation(byte tag, byte index) { + int newDepth = this.depth + 1; + Location[] res = new Location[newDepth]; + System.arraycopy(this.locations, 0, res, 0, depth); + res[newDepth - 1] = new Location(tag, index); + return new LocationInfo(newDepth, res); + } + + public TypeAnnotation[] filter(TypeAnnotation[] ta) { + ArrayList l = new ArrayList<>(ta.length); + for (TypeAnnotation t : ta) { + if (isSameLocationInfo(t.getLocationInfo())) + l.add(t); + } + return l.toArray(new TypeAnnotation[0]); + } + + boolean isSameLocationInfo(LocationInfo other) { + if (depth != other.depth) + return false; + for (int i = 0; i < depth; i++) + if (!locations[i].isSameLocation(other.locations[i])) + return false; + return true; + } + + public static class Location { + public final byte tag; + public final byte index; + + boolean isSameLocation(Location other) { + return tag == other.tag && index == other.index; + } + + public Location(byte tag, byte index) { + this.tag = tag; + this.index = index; + } + } + } + + @Override + public String toString() { + return annotation.toString() + " with Targetnfo: " + + targetInfo.toString() + " on base declaration: " + + baseDeclaration.toString(); + } +} diff --git a/jdk/src/share/classes/sun/reflect/annotation/TypeAnnotationParser.java b/jdk/src/share/classes/sun/reflect/annotation/TypeAnnotationParser.java new file mode 100644 index 00000000000..12abe28b4d5 --- /dev/null +++ b/jdk/src/share/classes/sun/reflect/annotation/TypeAnnotationParser.java @@ -0,0 +1,491 @@ +/* + * 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.reflect.annotation; + +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.nio.ByteBuffer; +import java.nio.BufferUnderflowException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import sun.misc.JavaLangAccess; +import sun.reflect.ConstantPool; +import static sun.reflect.annotation.TypeAnnotation.*; + +/** + * TypeAnnotationParser implements the logic needed to parse + * TypeAnnotations from an array of bytes. + */ +public class TypeAnnotationParser { + private static final TypeAnnotation[] EMPTY_TYPE_ANNOTATION_ARRAY = new TypeAnnotation[0]; + + /** + * Build an AnnotatedType from the parameters supplied. + * + * This method and {@code buildAnnotatedTypes} are probably + * the entry points you are looking for. + * + * @param rawAnnotations the byte[] encoding of all type annotations on this declaration + * @param cp the ConstantPool needed to parse the embedded Annotation + * @param decl the dclaration this type annotation is on + * @param container the Class this type annotation is on (may be the same as decl) + * @param type the type the AnnotatedType corresponds to + * @param filter the type annotation targets included in this AnnotatedType + */ + public static AnnotatedType buildAnnotatedType(byte[] rawAnnotations, + ConstantPool cp, + AnnotatedElement decl, + Class container, + Type type, + TypeAnnotationTarget filter) { + TypeAnnotation[] tas = parseTypeAnnotations(rawAnnotations, + cp, + decl, + container); + List l = new ArrayList<>(tas.length); + for (TypeAnnotation t : tas) { + TypeAnnotationTargetInfo ti = t.getTargetInfo(); + if (ti.getTarget() == filter) + l.add(t); + } + TypeAnnotation[] typeAnnotations = l.toArray(new TypeAnnotation[0]); + return AnnotatedTypeFactory.buildAnnotatedType(type, + LocationInfo.BASE_LOCATION, + typeAnnotations, + typeAnnotations, + decl); + } + + /** + * Build an array of AnnotatedTypes from the parameters supplied. + * + * This method and {@code buildAnnotatedType} are probably + * the entry points you are looking for. + * + * @param rawAnnotations the byte[] encoding of all type annotations on this declaration + * @param cp the ConstantPool needed to parse the embedded Annotation + * @param decl the declaration this type annotation is on + * @param container the Class this type annotation is on (may be the same as decl) + * @param types the Types the AnnotatedTypes corresponds to + * @param filter the type annotation targets that included in this AnnotatedType + */ + public static AnnotatedType[] buildAnnotatedTypes(byte[] rawAnnotations, + ConstantPool cp, + AnnotatedElement decl, + Class container, + Type[] types, + TypeAnnotationTarget filter) { + int size = types.length; + AnnotatedType[] result = new AnnotatedType[size]; + Arrays.fill(result, AnnotatedTypeFactory.EMPTY_ANNOTATED_TYPE); + @SuppressWarnings("rawtypes") + ArrayList[] l = new ArrayList[size]; // array of ArrayList + + TypeAnnotation[] tas = parseTypeAnnotations(rawAnnotations, + cp, + decl, + container); + for (TypeAnnotation t : tas) { + TypeAnnotationTargetInfo ti = t.getTargetInfo(); + if (ti.getTarget() == filter) { + int pos = ti.getCount(); + if (l[pos] == null) { + ArrayList tmp = new ArrayList<>(tas.length); + l[pos] = tmp; + } + @SuppressWarnings("unchecked") + ArrayList tmp = l[pos]; + tmp.add(t); + } + } + for (int i = 0; i < size; i++) { + @SuppressWarnings("unchecked") + ArrayList list = l[i]; + if (list != null) { + TypeAnnotation[] typeAnnotations = list.toArray(new TypeAnnotation[0]); + result[i] = AnnotatedTypeFactory.buildAnnotatedType(types[i], + LocationInfo.BASE_LOCATION, + typeAnnotations, + typeAnnotations, + decl); + } + } + return result; + } + + // Class helpers + + /** + * Build an AnnotatedType for the class decl's supertype. + * + * @param rawAnnotations the byte[] encoding of all type annotations on this declaration + * @param cp the ConstantPool needed to parse the embedded Annotation + * @param decl the Class which annotated supertype is being built + */ + public static AnnotatedType buildAnnotatedSuperclass(byte[] rawAnnotations, + ConstantPool cp, + Class decl) { + Type supertype = decl.getGenericSuperclass(); + if (supertype == null) + return AnnotatedTypeFactory.EMPTY_ANNOTATED_TYPE; + return buildAnnotatedType(rawAnnotations, + cp, + decl, + decl, + supertype, + TypeAnnotationTarget.CLASS_EXTENDS); + } + + /** + * Build an array of AnnotatedTypes for the class decl's implemented + * interfaces. + * + * @param rawAnnotations the byte[] encoding of all type annotations on this declaration + * @param cp the ConstantPool needed to parse the embedded Annotation + * @param decl the Class whose annotated implemented interfaces is being built + */ + public static AnnotatedType[] buildAnnotatedInterfaces(byte[] rawAnnotations, + ConstantPool cp, + Class decl) { + return buildAnnotatedTypes(rawAnnotations, + cp, + decl, + decl, + decl.getGenericInterfaces(), + TypeAnnotationTarget.CLASS_IMPLEMENTS); + } + + // TypeVariable helpers + + /** + * Parse regular annotations on a TypeVariable declared on genericDecl. + * + * Regular Annotations on TypeVariables are stored in the type + * annotation byte[] in the class file. + * + * @param genericsDecl the declaration declaring the type variable + * @param typeVarIndex the 0-based index of this type variable in the declaration + */ + public static Annotation[] parseTypeVariableAnnotations(D genericDecl, + int typeVarIndex) { + AnnotatedElement decl; + TypeAnnotationTarget predicate; + if (genericDecl instanceof Class) { + decl = (Class)genericDecl; + predicate = TypeAnnotationTarget.CLASS_TYPE_PARAMETER; + } else if (genericDecl instanceof Executable) { + decl = (Executable)genericDecl; + predicate = TypeAnnotationTarget.METHOD_TYPE_PARAMETER; + } else { + throw new AssertionError("Unknown GenericDeclaration " + genericDecl + "\nthis should not happen."); + } + List typeVarAnnos = TypeAnnotation.filter(parseAllTypeAnnotations(decl), + predicate); + List res = new ArrayList<>(typeVarAnnos.size()); + for (TypeAnnotation t : typeVarAnnos) + if (t.getTargetInfo().getCount() == typeVarIndex) + res.add(t.getAnnotation()); + return res.toArray(new Annotation[0]); + } + + /** + * Build an array of AnnotatedTypes for the declaration decl's bounds. + * + * @param bounds the bounds corresponding to the annotated bounds + * @param decl the declaration whose annotated bounds is being built + * @param typeVarIndex the index of this type variable on the decl + */ + public static AnnotatedType[] parseAnnotatedBounds(Type[] bounds, + D decl, + int typeVarIndex) { + return parseAnnotatedBounds(bounds, decl, typeVarIndex, LocationInfo.BASE_LOCATION); + } + //helper for above + static AnnotatedType[] parseAnnotatedBounds(Type[] bounds, + D decl, + int typeVarIndex, + LocationInfo loc) { + List candidates = fetchBounds(decl); + if (bounds != null) { + int startIndex = 0; + AnnotatedType[] res = new AnnotatedType[bounds.length]; + Arrays.fill(res, AnnotatedTypeFactory.EMPTY_ANNOTATED_TYPE); + + // Adjust bounds index + // + // Figure out if the type annotations for this bound starts with 0 + // or 1. The spec says within a bound the 0:th type annotation will + // always be on an bound of a Class type (not Interface type). So + // if the programmer starts with an Interface type for the first + // (and following) bound(s) the implicit Object bound is considered + // the first (that is 0:th) bound and type annotations start on + // index 1. + if (bounds.length > 0) { + Type b0 = bounds[0]; + if (!(b0 instanceof Class)) { + startIndex = 1; + } else { + Class c = (Class)b0; + if (c.isInterface()) { + startIndex = 1; + } + } + } + + for (int i = 0; i < bounds.length; i++) { + List l = new ArrayList<>(candidates.size()); + for (TypeAnnotation t : candidates) { + TypeAnnotationTargetInfo tInfo = t.getTargetInfo(); + if (tInfo.getSecondaryIndex() == i + startIndex && + tInfo.getCount() == typeVarIndex) { + l.add(t); + } + res[i] = AnnotatedTypeFactory.buildAnnotatedType(bounds[i], + loc, + l.toArray(new TypeAnnotation[0]), + candidates.toArray(new TypeAnnotation[0]), + (AnnotatedElement)decl); + } + } + return res; + } + return new AnnotatedType[0]; + } + private static List fetchBounds(D decl) { + AnnotatedElement boundsDecl; + TypeAnnotationTarget target; + if (decl instanceof Class) { + target = TypeAnnotationTarget.CLASS_PARAMETER_BOUND; + boundsDecl = (Class)decl; + } else { + target = TypeAnnotationTarget.METHOD_PARAMETER_BOUND; + boundsDecl = (Executable)decl; + } + return TypeAnnotation.filter(TypeAnnotationParser.parseAllTypeAnnotations(boundsDecl), target); + } + + /* + * Parse all type annotations on the declaration supplied. This is needed + * when you go from for example an annotated return type on a method that + * is a type variable declared on the class. In this case you need to + * 'jump' to the decl of the class and parse all type annotations there to + * find the ones that are applicable to the type variable. + */ + static TypeAnnotation[] parseAllTypeAnnotations(AnnotatedElement decl) { + Class container; + byte[] rawBytes; + JavaLangAccess javaLangAccess = sun.misc.SharedSecrets.getJavaLangAccess(); + if (decl instanceof Class) { + container = (Class)decl; + rawBytes = javaLangAccess.getRawClassTypeAnnotations(container); + } else if (decl instanceof Executable) { + container = ((Executable)decl).getDeclaringClass(); + rawBytes = javaLangAccess.getRawExecutableTypeAnnotations((Executable)decl); + } else { + // Should not reach here. Assert? + return EMPTY_TYPE_ANNOTATION_ARRAY; + } + return parseTypeAnnotations(rawBytes, javaLangAccess.getConstantPool(container), + decl, container); + } + + /* Parse type annotations encoded as an array of bytes */ + private static TypeAnnotation[] parseTypeAnnotations(byte[] rawAnnotations, + ConstantPool cp, + AnnotatedElement baseDecl, + Class container) { + if (rawAnnotations == null) + return EMPTY_TYPE_ANNOTATION_ARRAY; + + ByteBuffer buf = ByteBuffer.wrap(rawAnnotations); + int annotationCount = buf.getShort() & 0xFFFF; + List typeAnnotations = new ArrayList<>(annotationCount); + + // Parse each TypeAnnotation + for (int i = 0; i < annotationCount; i++) { + TypeAnnotation ta = parseTypeAnnotation(buf, cp, baseDecl, container); + if (ta != null) + typeAnnotations.add(ta); + } + + return typeAnnotations.toArray(EMPTY_TYPE_ANNOTATION_ARRAY); + } + + + // Helper + static Map, Annotation> mapTypeAnnotations(TypeAnnotation[] typeAnnos) { + Map, Annotation> result = + new LinkedHashMap<>(); + for (TypeAnnotation t : typeAnnos) { + Annotation a = t.getAnnotation(); + Class klass = a.annotationType(); + AnnotationType type = AnnotationType.getInstance(klass); + if (type.retention() == RetentionPolicy.RUNTIME) + if (result.put(klass, a) != null) + throw new AnnotationFormatError("Duplicate annotation for class: "+klass+": " + a); + } + return result; + } + + // Position codes + // Regular type parameter annotations + private static final byte CLASS_TYPE_PARAMETER = 0x00; + private static final byte METHOD_TYPE_PARAMETER = 0x01; + // Type Annotations outside method bodies + private static final byte CLASS_EXTENDS = 0x10; + private static final byte CLASS_TYPE_PARAMETER_BOUND = 0x11; + private static final byte METHOD_TYPE_PARAMETER_BOUND = 0x12; + private static final byte FIELD = 0x13; + private static final byte METHOD_RETURN = 0x14; + private static final byte METHOD_RECEIVER = 0x15; + private static final byte METHOD_FORMAL_PARAMETER = 0x16; + private static final byte THROWS = 0x17; + // Type Annotations inside method bodies + private static final byte LOCAL_VARIABLE = (byte)0x40; + private static final byte RESOURCE_VARIABLE = (byte)0x41; + private static final byte EXCEPTION_PARAMETER = (byte)0x42; + private static final byte CAST = (byte)0x43; + private static final byte INSTANCEOF = (byte)0x44; + private static final byte NEW = (byte)0x45; + private static final byte CONSTRUCTOR_REFERENCE_RECEIVER = (byte)0x46; + private static final byte METHOD_REFERENCE_RECEIVER = (byte)0x47; + private static final byte LAMBDA_FORMAL_PARAMETER = (byte)0x48; + private static final byte METHOD_REFERENCE = (byte)0x49; + private static final byte METHOD_REFERENCE_TYPE_ARGUMENT = (byte)0x50; + + private static TypeAnnotation parseTypeAnnotation(ByteBuffer buf, + ConstantPool cp, + AnnotatedElement baseDecl, + Class container) { + TypeAnnotationTargetInfo ti = parseTargetInfo(buf); + LocationInfo locationInfo = LocationInfo.parseLocationInfo(buf); + Annotation a = AnnotationParser.parseAnnotation(buf, cp, container, false); + if (ti == null) // Inside a method for example + return null; + return new TypeAnnotation(ti, locationInfo, a, baseDecl); + } + + private static TypeAnnotationTargetInfo parseTargetInfo(ByteBuffer buf) { + byte posCode = buf.get(); + switch(posCode) { + case CLASS_TYPE_PARAMETER: + case METHOD_TYPE_PARAMETER: { + byte index = buf.get(); + TypeAnnotationTargetInfo res; + if (posCode == CLASS_TYPE_PARAMETER) + res = new TypeAnnotationTargetInfo(TypeAnnotationTarget.CLASS_TYPE_PARAMETER, + index); + else + res = new TypeAnnotationTargetInfo(TypeAnnotationTarget.METHOD_TYPE_PARAMETER, + index); + return res; + } // unreachable break; + case CLASS_EXTENDS: { + short index = buf.getShort(); + if (index == -1) { + return new TypeAnnotationTargetInfo(TypeAnnotationTarget.CLASS_EXTENDS); + } else if (index >= 0) { + TypeAnnotationTargetInfo res = new TypeAnnotationTargetInfo(TypeAnnotationTarget.CLASS_IMPLEMENTS, + index); + return res; + }} break; + case CLASS_TYPE_PARAMETER_BOUND: + return parse2ByteTarget(TypeAnnotationTarget.CLASS_PARAMETER_BOUND, buf); + case METHOD_TYPE_PARAMETER_BOUND: + return parse2ByteTarget(TypeAnnotationTarget.METHOD_PARAMETER_BOUND, buf); + case FIELD: + return new TypeAnnotationTargetInfo(TypeAnnotationTarget.FIELD_TYPE); + case METHOD_RETURN: + return new TypeAnnotationTargetInfo(TypeAnnotationTarget.METHOD_RETURN_TYPE); + case METHOD_RECEIVER: + return new TypeAnnotationTargetInfo(TypeAnnotationTarget.METHOD_RECEIVER_TYPE); + case METHOD_FORMAL_PARAMETER: { + // Todo + byte index = buf.get(); + } break; + case THROWS: + return parseShortTarget(TypeAnnotationTarget.THROWS, buf); + + /* + * The ones below are inside method bodies, we don't care about them for core reflection + * other than adjusting for them in the byte stream. + */ + case LOCAL_VARIABLE: + case RESOURCE_VARIABLE: + short length = buf.getShort(); + for (int i = 0; i < length; ++i) { + short offset = buf.getShort(); + short varLength = buf.getShort(); + short index = buf.getShort(); + } + break; + case EXCEPTION_PARAMETER: { + byte index = buf.get(); + } break; + case CAST: + case INSTANCEOF: + case NEW: { + short offset = buf.getShort(); + } break; + case CONSTRUCTOR_REFERENCE_RECEIVER: + case METHOD_REFERENCE_RECEIVER: { + short offset = buf.getShort(); + byte index = buf.get(); + } break; + case LAMBDA_FORMAL_PARAMETER: { + byte index = buf.get(); + } break; + case METHOD_REFERENCE: + // This one isn't in the spec yet + break; + case METHOD_REFERENCE_TYPE_ARGUMENT: { + short offset = buf.getShort(); + byte index = buf.get(); + } break; + + default: + // will throw error below + break; + } + throw new AnnotationFormatError("Could not parse bytes for type annotations"); + } + + private static TypeAnnotationTargetInfo parseShortTarget(TypeAnnotationTarget target, ByteBuffer buf) { + short index = buf.getShort(); + return new TypeAnnotationTargetInfo(target, index); + } + private static TypeAnnotationTargetInfo parse2ByteTarget(TypeAnnotationTarget target, ByteBuffer buf) { + byte count = buf.get(); + byte secondaryIndex = buf.get(); + return new TypeAnnotationTargetInfo(target, + count, + secondaryIndex); + } +} diff --git a/jdk/src/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java b/jdk/src/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java index 021b84891f1..0b1a13ee74e 100644 --- a/jdk/src/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java +++ b/jdk/src/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.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 @@ -25,13 +25,18 @@ package sun.reflect.generics.reflectiveObjects; -import java.lang.annotation.Annotation; +import java.lang.annotation.*; +import java.lang.reflect.AnnotatedType; import java.lang.reflect.Array; import java.lang.reflect.GenericDeclaration; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; +import java.util.LinkedHashMap; +import java.util.Map; import java.util.Objects; - +import sun.reflect.annotation.AnnotationSupport; +import sun.reflect.annotation.TypeAnnotationParser; +import sun.reflect.annotation.AnnotationType; import sun.reflect.generics.factory.GenericsFactory; import sun.reflect.generics.tree.FieldTypeSignature; import sun.reflect.generics.visitor.Reifier; @@ -182,45 +187,72 @@ public class TypeVariableImpl return genericDeclaration.hashCode() ^ name.hashCode(); } - // Currently vacuous implementations of AnnotatedElement methods. - public boolean isAnnotationPresent(Class annotationClass) { - Objects.requireNonNull(annotationClass); - return false; - } - + // Implementations of AnnotatedElement methods. + @SuppressWarnings("unchecked") public T getAnnotation(Class annotationClass) { Objects.requireNonNull(annotationClass); - return null; + // T is an Annotation type, the return value of get will be an annotation + return (T)mapAnnotations(getAnnotations()).get(annotationClass); } public T getDeclaredAnnotation(Class annotationClass) { Objects.requireNonNull(annotationClass); - return null; + return getAnnotation(annotationClass); } - @SuppressWarnings("unchecked") - public T[] getAnnotations(Class annotationClass) { + @Override + public T[] getAnnotationsByType(Class annotationClass) { Objects.requireNonNull(annotationClass); - // safe because annotationClass is the class for T - return (T[])Array.newInstance(annotationClass, 0); + return AnnotationSupport.getMultipleAnnotations(mapAnnotations(getAnnotations()), annotationClass); } - @SuppressWarnings("unchecked") - public T[] getDeclaredAnnotations(Class annotationClass) { + @Override + public T[] getDeclaredAnnotationsByType(Class annotationClass) { Objects.requireNonNull(annotationClass); - // safe because annotationClass is the class for T - return (T[])Array.newInstance(annotationClass, 0); + return getAnnotationsByType(annotationClass); } public Annotation[] getAnnotations() { - // Since zero-length, don't need defensive clone - return EMPTY_ANNOTATION_ARRAY; + int myIndex = typeVarIndex(); + if (myIndex < 0) + throw new AssertionError("Index must be non-negative."); + return TypeAnnotationParser.parseTypeVariableAnnotations(getGenericDeclaration(), myIndex); } public Annotation[] getDeclaredAnnotations() { - // Since zero-length, don't need defensive clone - return EMPTY_ANNOTATION_ARRAY; + return getAnnotations(); + } + + public AnnotatedType[] getAnnotatedBounds() { + return TypeAnnotationParser.parseAnnotatedBounds(getBounds(), + getGenericDeclaration(), + typeVarIndex()); } private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0]; + + // Helpers for annotation methods + private int typeVarIndex() { + TypeVariable[] tVars = getGenericDeclaration().getTypeParameters(); + int i = -1; + for (TypeVariable v : tVars) { + i++; + if (equals(v)) + return i; + } + return -1; + } + + private static Map, Annotation> mapAnnotations(Annotation[] annos) { + Map, Annotation> result = + new LinkedHashMap<>(); + for (Annotation a : annos) { + Class klass = a.annotationType(); + AnnotationType type = AnnotationType.getInstance(klass); + if (type.retention() == RetentionPolicy.RUNTIME) + if (result.put(klass, a) != null) + throw new AnnotationFormatError("Duplicate annotation for class: "+klass+": " + a); + } + return result; + } } diff --git a/jdk/src/share/classes/sun/security/jgss/LoginConfigImpl.java b/jdk/src/share/classes/sun/security/jgss/LoginConfigImpl.java index 41a783afef3..52e2fa4728d 100644 --- a/jdk/src/share/classes/sun/security/jgss/LoginConfigImpl.java +++ b/jdk/src/share/classes/sun/security/jgss/LoginConfigImpl.java @@ -175,6 +175,7 @@ public class LoginConfigImpl extends Configuration { options.put("useKeyTab", "true"); options.put("storeKey", "true"); options.put("doNotPrompt", "true"); + options.put("principal", "*"); options.put("isInitiator", "false"); } else { options.put("useTicketCache", "true"); diff --git a/jdk/src/share/classes/sun/security/jgss/krb5/Krb5Util.java b/jdk/src/share/classes/sun/security/jgss/krb5/Krb5Util.java index f0495eef872..0d5a314ffd7 100644 --- a/jdk/src/share/classes/sun/security/jgss/krb5/Krb5Util.java +++ b/jdk/src/share/classes/sun/security/jgss/krb5/Krb5Util.java @@ -242,15 +242,25 @@ public class Krb5Util { kerbTicket.getClientAddresses()); } + /** + * A helper method to get a sun..KeyTab from a javax..KeyTab + * @param ktab the javax..KeyTab object + * @return the sun..KeyTab object + */ + public static sun.security.krb5.internal.ktab.KeyTab + snapshotFromJavaxKeyTab(KeyTab ktab) { + return KerberosSecrets.getJavaxSecurityAuthKerberosAccess() + .keyTabTakeSnapshot(ktab); + } + /** * A helper method to get EncryptionKeys from a javax..KeyTab - * @param ktab the javax..KeyTab class + * @param ktab the javax..KeyTab object * @param cname the PrincipalName * @return the EKeys, never null, might be empty */ public static EncryptionKey[] keysFromJavaxKeyTab( KeyTab ktab, PrincipalName cname) { - return KerberosSecrets.getJavaxSecurityAuthKerberosAccess(). - keyTabGetEncryptionKeys(ktab, cname); + return snapshotFromJavaxKeyTab(ktab).readServiceKeys(cname); } } diff --git a/jdk/src/share/classes/sun/security/jgss/krb5/ServiceCreds.java b/jdk/src/share/classes/sun/security/jgss/krb5/ServiceCreds.java index 21b8f57b229..824724bf34e 100644 --- a/jdk/src/share/classes/sun/security/jgss/krb5/ServiceCreds.java +++ b/jdk/src/share/classes/sun/security/jgss/krb5/ServiceCreds.java @@ -101,9 +101,22 @@ public final class ServiceCreds { if (serverPrincipal != null) { // A named principal sc.kp = new KerberosPrincipal(serverPrincipal); } else { - if (sc.allPrincs.size() == 1) { // choose the only one - sc.kp = sc.allPrincs.iterator().next(); - serverPrincipal = sc.kp.getName(); + // For compatibility reason, we set the name of default principal + // to the "only possible" name it can take, which means there is + // only one KerberosPrincipal and there is no unbound keytabs + if (sc.allPrincs.size() == 1) { + boolean hasUnbound = false; + for (KeyTab ktab: SubjectComber.findMany( + subj, null, null, KeyTab.class)) { + if (!ktab.isBound()) { + hasUnbound = true; + break; + } + } + if (!hasUnbound) { + sc.kp = sc.allPrincs.iterator().next(); + serverPrincipal = sc.kp.getName(); + } } } @@ -131,20 +144,35 @@ public final class ServiceCreds { } /** - * Gets keys for someone unknown. - * Used by TLS or as a fallback in getEKeys(). Can still return an - * empty array. + * Gets keys for "someone". Used in 2 cases: + * 1. By TLS because it needs to get keys before client comes in. + * 2. As a fallback in getEKeys() below. + * This method can still return an empty array. */ public KerberosKey[] getKKeys() { if (destroyed) { throw new IllegalStateException("This object is destroyed"); } - if (kp != null) { - return getKKeys(kp); - } else if (!allPrincs.isEmpty()) { - return getKKeys(allPrincs.iterator().next()); + KerberosPrincipal one = kp; // named principal + if (one == null && !allPrincs.isEmpty()) { // or, a known principal + one = allPrincs.iterator().next(); + } + if (one == null) { // Or, some random one + for (KeyTab ktab: ktabs) { + // Must be unbound keytab, otherwise, allPrincs is not empty + PrincipalName pn = + Krb5Util.snapshotFromJavaxKeyTab(ktab).getOneName(); + if (pn != null) { + one = new KerberosPrincipal(pn.getName()); + break; + } + } + } + if (one != null) { + return getKKeys(one); + } else { + return new KerberosKey[0]; } - return new KerberosKey[0]; } /** @@ -152,15 +180,13 @@ public final class ServiceCreds { * @param princ the target name initiator requests. Not null. * @return keys for the princ, never null, might be empty */ - private KerberosKey[] getKKeys(KerberosPrincipal princ) { - ArrayList keys = new ArrayList<>(); - if (kp != null && !princ.equals(kp)) { - return new KerberosKey[0]; // Not me + public KerberosKey[] getKKeys(KerberosPrincipal princ) { + if (destroyed) { + throw new IllegalStateException("This object is destroyed"); } - if (!allPrincs.contains(princ)) { - return new KerberosKey[0]; // Not someone I know, This check - // is necessary but a KeyTab has - // no principal name recorded. + ArrayList keys = new ArrayList<>(); + if (kp != null && !princ.equals(kp)) { // named principal + return new KerberosKey[0]; } for (KerberosKey k: kk) { if (k.getPrincipal().equals(princ)) { @@ -168,6 +194,13 @@ public final class ServiceCreds { } } for (KeyTab ktab: ktabs) { + if (ktab.getPrincipal() == null && ktab.isBound()) { + // legacy bound keytab. although we don't know who + // the bound principal is, it must be in allPrincs + if (!allPrincs.contains(princ)) { + continue; // skip this legacy bound keytab + } + } for (KerberosKey k: ktab.getKeys(princ)) { keys.add(k); } @@ -186,12 +219,12 @@ public final class ServiceCreds { } KerberosKey[] kkeys = getKKeys(new KerberosPrincipal(princ.getName())); if (kkeys.length == 0) { - // Note: old JDK does not perform real name checking. If the - // acceptor starts by name A but initiator requests for B, - // as long as their keys match (i.e. A's keys can decrypt B's - // service ticket), the authentication is OK. There are real - // customers depending on this to use different names for a - // single service. + // Fallback: old JDK does not perform real name checking. If the + // acceptor has host.sun.com but initiator requests for host, + // as long as their keys match (i.e. keys for one can decrypt + // the other's service ticket), the authentication is OK. + // There are real customers depending on this to use different + // names for a single service. kkeys = getKKeys(); } EncryptionKey[] ekeys = new EncryptionKey[kkeys.length]; diff --git a/jdk/src/share/classes/sun/security/jgss/krb5/SubjectComber.java b/jdk/src/share/classes/sun/security/jgss/krb5/SubjectComber.java index d267dbd4b21..ad1723fe09e 100644 --- a/jdk/src/share/classes/sun/security/jgss/krb5/SubjectComber.java +++ b/jdk/src/share/classes/sun/security/jgss/krb5/SubjectComber.java @@ -86,36 +86,39 @@ class SubjectComber { List answer = (oneOnly ? null : new ArrayList()); if (credClass == KeyTab.class) { - // TODO: There is currently no good way to filter out keytabs - // not for serverPrincipal. We can only check the principal - // set. If the server is not there, we can be sure none of the - // keytabs should be used, otherwise, use all for safety. - boolean useAll = false; - if (serverPrincipal != null) { - for (KerberosPrincipal princ: - subject.getPrincipals(KerberosPrincipal.class)) { - if (princ.getName().equals(serverPrincipal)) { - useAll = true; - break; + Iterator iterator = + subject.getPrivateCredentials(KeyTab.class).iterator(); + while (iterator.hasNext()) { + KeyTab t = iterator.next(); + if (serverPrincipal != null && t.isBound()) { + KerberosPrincipal name = t.getPrincipal(); + if (name != null) { + if (!serverPrincipal.equals(name.getName())) { + continue; + } + } else { + // legacy bound keytab. although we don't know who + // the bound principal is, it must be in allPrincs + boolean found = false; + for (KerberosPrincipal princ: + subject.getPrincipals(KerberosPrincipal.class)) { + if (princ.getName().equals(serverPrincipal)) { + found = true; + break; + } + } + if (!found) continue; } } - } else { - useAll = true; - } - if (useAll) { - Iterator iterator = - subject.getPrivateCredentials(KeyTab.class).iterator(); - while (iterator.hasNext()) { - KeyTab t = iterator.next(); - if (DEBUG) { - System.out.println("Found " + credClass.getSimpleName() - + " " + t); - } - if (oneOnly) { - return t; - } else { - answer.add(credClass.cast(t)); - } + // Check passed, we can add now + if (DEBUG) { + System.out.println("Found " + credClass.getSimpleName() + + " " + t); + } + if (oneOnly) { + return t; + } else { + answer.add(credClass.cast(t)); } } } else if (credClass == KerberosKey.class) { diff --git a/jdk/src/share/classes/sun/security/krb5/JavaxSecurityAuthKerberosAccess.java b/jdk/src/share/classes/sun/security/krb5/JavaxSecurityAuthKerberosAccess.java index 3992e487108..ae3dc3d0b04 100644 --- a/jdk/src/share/classes/sun/security/krb5/JavaxSecurityAuthKerberosAccess.java +++ b/jdk/src/share/classes/sun/security/krb5/JavaxSecurityAuthKerberosAccess.java @@ -35,9 +35,8 @@ import sun.security.krb5.PrincipalName; */ public interface JavaxSecurityAuthKerberosAccess { /** - * Returns keys for a principal in a keytab. - * @return the keys, never null, can be empty. + * Returns a snapshot to the backing keytab */ - public EncryptionKey[] keyTabGetEncryptionKeys( - KeyTab ktab, PrincipalName principal); + public sun.security.krb5.internal.ktab.KeyTab keyTabTakeSnapshot( + KeyTab ktab); } diff --git a/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java b/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java index d1023de9de3..b556c90524c 100644 --- a/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java +++ b/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java @@ -46,6 +46,7 @@ import java.util.HashMap; import java.util.Map; import java.util.StringTokenizer; import java.util.Vector; +import sun.security.jgss.krb5.ServiceCreds; /** * This class represents key table. The key table functions deal with storing @@ -267,6 +268,15 @@ public class KeyTab implements KeyTabConstants { } } + /** + * Returns a principal name in this keytab. Used by + * {@link ServiceCreds#getKKeys()}. + */ + public PrincipalName getOneName() { + int size = entries.size(); + return size > 0 ? entries.elementAt(size-1).service : null; + } + /** * Reads all keys for a service from the keytab file that have * etypes that have been configured for use. If there are multiple diff --git a/jdk/src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java b/jdk/src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java index eefdbff811f..32f1da53afa 100644 --- a/jdk/src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java +++ b/jdk/src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java @@ -326,7 +326,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi { DerValue val = new DerValue(encrInfo.getAlgorithm().encode()); DerInputStream in = val.toDerInputStream(); algOid = in.getOID(); - algParams = parseAlgParameters(in); + algParams = parseAlgParameters(algOid, in); } catch (IOException ioe) { UnrecoverableKeyException uke = @@ -342,7 +342,8 @@ public final class PKCS12KeyStore extends KeyStoreSpi { try { // Use JCE SecretKey skey = getPBEKey(password); - Cipher cipher = Cipher.getInstance(algOid.toString()); + Cipher cipher = Cipher.getInstance( + mapPBEParamsToAlgorithm(algOid, algParams)); cipher.init(Cipher.DECRYPT_MODE, skey, algParams); keyInfo = cipher.doFinal(encryptedKey); break; @@ -759,8 +760,8 @@ public final class PKCS12KeyStore extends KeyStoreSpi { /* * parse Algorithm Parameters */ - private AlgorithmParameters parseAlgParameters(DerInputStream in) - throws IOException + private AlgorithmParameters parseAlgParameters(ObjectIdentifier algorithm, + DerInputStream in) throws IOException { AlgorithmParameters algParams = null; try { @@ -774,7 +775,11 @@ public final class PKCS12KeyStore extends KeyStoreSpi { } } if (params != null) { - algParams = AlgorithmParameters.getInstance("PBE"); + if (algorithm.equals(pbes2_OID)) { + algParams = AlgorithmParameters.getInstance("PBES2"); + } else { + algParams = AlgorithmParameters.getInstance("PBE"); + } algParams.init(params.toByteArray()); } } catch (Exception e) { @@ -834,13 +839,6 @@ public final class PKCS12KeyStore extends KeyStoreSpi { } else { algParams = getAlgorithmParameters(algorithm); } - ObjectIdentifier pbeOID = mapPBEAlgorithmToOID(algorithm); - if (pbeOID != null) { - algid = new AlgorithmId(pbeOID, algParams); - } else { - throw new IOException("PBE algorithm '" + algorithm + - " 'is not supported for key entry protection"); - } } else { // Check default key protection algorithm for PKCS12 keystores algorithm = AccessController.doPrivileged( @@ -856,12 +854,16 @@ public final class PKCS12KeyStore extends KeyStoreSpi { return prop; } }); - if (algorithm == null) { + if (algorithm == null || algorithm.isEmpty()) { algorithm = "PBEWithSHA1AndDESede"; } algParams = getAlgorithmParameters(algorithm); - algid = new AlgorithmId(pbeWithSHAAnd3KeyTripleDESCBC_OID, - algParams); + } + + ObjectIdentifier pbeOID = mapPBEAlgorithmToOID(algorithm); + if (pbeOID == null) { + throw new IOException("PBE algorithm '" + algorithm + + " 'is not supported for key entry protection"); } // Use JCE @@ -869,6 +871,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi { Cipher cipher = Cipher.getInstance(algorithm); cipher.init(Cipher.ENCRYPT_MODE, skey, algParams); byte[] encryptedKey = cipher.doFinal(data); + algid = new AlgorithmId(pbeOID, cipher.getParameters()); if (debug != null) { debug.println(" (Cipher algorithm: " + cipher.getAlgorithm() + @@ -894,7 +897,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi { /* * Map a PBE algorithm name onto its object identifier */ - private ObjectIdentifier mapPBEAlgorithmToOID(String algorithm) + private static ObjectIdentifier mapPBEAlgorithmToOID(String algorithm) throws NoSuchAlgorithmException { // Check for PBES2 algorithms if (algorithm.toLowerCase().startsWith("pbewithhmacsha")) { @@ -903,6 +906,18 @@ public final class PKCS12KeyStore extends KeyStoreSpi { return AlgorithmId.get(algorithm).getOID(); } + /* + * Map a PBE algorithm parameters onto its algorithm name + */ + private static String mapPBEParamsToAlgorithm(ObjectIdentifier algorithm, + AlgorithmParameters algParams) throws NoSuchAlgorithmException { + // Check for PBES2 algorithms + if (algorithm.equals(pbes2_OID) && algParams != null) { + return algParams.toString(); + } + return algorithm.toString(); + } + /** * Assigns the given certificate to the given alias. * @@ -1116,7 +1131,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi { if (privateKeyCount > 0 || secretKeyCount > 0) { if (debug != null) { - debug.println("Storing " + privateKeyCount + + debug.println("Storing " + (privateKeyCount + secretKeyCount) + " protected key(s) in a PKCS#7 data content-type"); } @@ -1933,7 +1948,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi { // parse Algorithm parameters DerInputStream in = seq[1].toDerInputStream(); ObjectIdentifier algOid = in.getOID(); - AlgorithmParameters algParams = parseAlgParameters(in); + AlgorithmParameters algParams = parseAlgParameters(algOid, in); while (true) { try { @@ -2122,6 +2137,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi { SecretKeyEntry kEntry = new SecretKeyEntry(); kEntry.protectedSecretKey = secretValue.getOctetString(); bagItem = kEntry; + secretKeyCount++; } else { if (debug != null) { @@ -2220,6 +2236,10 @@ public final class PKCS12KeyStore extends KeyStoreSpi { if (bagItem instanceof PrivateKeyEntry) { keyList.add((PrivateKeyEntry) entry); } + if (entry.attributes == null) { + entry.attributes = new HashSet<>(); + } + entry.attributes.addAll(attributes); if (alias == null) { alias = getUnfriendlyName(); } diff --git a/jdk/src/share/classes/sun/security/provider/ConfigSpiFile.java b/jdk/src/share/classes/sun/security/provider/ConfigSpiFile.java index 3a9ca47677a..03cdc5712d0 100644 --- a/jdk/src/share/classes/sun/security/provider/ConfigSpiFile.java +++ b/jdk/src/share/classes/sun/security/provider/ConfigSpiFile.java @@ -404,6 +404,7 @@ public final class ConfigSpiFile extends ConfigurationSpi { st.wordChars('$', '$'); st.wordChars('_', '_'); st.wordChars('-', '-'); + st.wordChars('*', '*'); st.lowerCaseMode(false); st.slashSlashComments(true); st.slashStarComments(true); diff --git a/jdk/src/share/classes/sun/security/provider/DomainKeyStore.java b/jdk/src/share/classes/sun/security/provider/DomainKeyStore.java new file mode 100644 index 00000000000..ae0dbfb067c --- /dev/null +++ b/jdk/src/share/classes/sun/security/provider/DomainKeyStore.java @@ -0,0 +1,900 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.provider; + +import java.io.*; +import java.net.*; +import java.security.*; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.security.cert.CertificateException; +import java.util.*; + +import sun.misc.IOUtils; +import sun.security.pkcs.EncryptedPrivateKeyInfo; +import sun.security.util.PolicyUtil; + +/** + * This class provides the domain keystore type identified as "DKS". + * DKS presents a collection of separate keystores as a single logical keystore. + * The collection of keystores is specified in a domain configuration file which + * is passed to DKS in a {@link KeyStore.DomainLoadStoreParameter}. + *

      + * The following properties are supported: + *

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

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

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

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

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

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

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

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

      If a password is given, it is used to check the integrity of the + * keystore data. Otherwise, the integrity of the keystore is not checked. + * + * @param stream the input stream from which the keystore is loaded + * @param password the (optional) password used to check the integrity of + * the keystore. + * + * @exception IOException if there is an I/O or format problem with the + * keystore data + * @exception NoSuchAlgorithmException if the algorithm used to check + * the integrity of the keystore cannot be found + * @exception CertificateException if any of the certificates in the + * keystore could not be loaded + */ + public void engineLoad(InputStream stream, char[] password) + throws IOException, NoSuchAlgorithmException, CertificateException + { + // Support loading from a stream only for a JKS or default type keystore + try { + KeyStore keystore = null; + + try { + keystore = KeyStore.getInstance("JKS"); + keystore.load(stream, password); + + } catch (Exception e) { + // Retry + if (!"JKS".equalsIgnoreCase(DEFAULT_KEYSTORE_TYPE)) { + keystore = KeyStore.getInstance(DEFAULT_KEYSTORE_TYPE); + keystore.load(stream, password); + } else { + throw e; + } + } + String keystoreName = DEFAULT_STREAM_PREFIX + streamCounter++; + keystores.put(keystoreName, keystore); + + } catch (Exception e) { + throw new UnsupportedOperationException( + "This keystore must be loaded using a " + + "KeyStore.DomainLoadStoreParameter"); + } + } + + @Override + public void engineLoad(KeyStore.LoadStoreParameter param) + throws IOException, NoSuchAlgorithmException, CertificateException + { + if (param instanceof KeyStore.DomainLoadStoreParameter) { + KeyStore.DomainLoadStoreParameter domainParameter = + (KeyStore.DomainLoadStoreParameter) param; + List builders = getBuilders( + domainParameter.getConfiguration(), + domainParameter.getProtectionParams()); + + for (KeyStoreBuilderComponents builder : builders) { + + try { + // Load the keystores (file-based and non-file-based) + if (builder.file != null) { + keystores.put(builder.name, + KeyStore.Builder.newInstance(builder.type, + builder.provider, builder.file, + builder.protection) + .getKeyStore()); + } else { + keystores.put(builder.name, + KeyStore.Builder.newInstance(builder.type, + builder.provider, builder.protection) + .getKeyStore()); + } + } catch (KeyStoreException e) { + throw new IOException(e); + } + } + } else { + throw new UnsupportedOperationException( + "This keystore must be loaded using a " + + "KeyStore.DomainLoadStoreParameter"); + } + } + + /* + * Parse a keystore domain configuration file and associated collection + * of keystore passwords to create a collection of KeyStore.Builder. + */ + private List getBuilders(URI configuration, + Map passwords) + throws IOException { + + PolicyParser parser = new PolicyParser(true); // expand properties + Collection domains = null; + List builders = new ArrayList<>(); + String uriDomain = configuration.getFragment(); + + try (InputStreamReader configurationReader = + new InputStreamReader( + PolicyUtil.getInputStream(configuration.toURL()), "UTF-8")) { + parser.read(configurationReader); + domains = parser.getDomainEntries(); + + } catch (MalformedURLException mue) { + throw new IOException(mue); + + } catch (PolicyParser.ParsingException pe) { + throw new IOException(pe); + } + + for (PolicyParser.DomainEntry domain : domains) { + Map domainProperties = domain.getProperties(); + + if (uriDomain != null && + (!uriDomain.equalsIgnoreCase(domain.getName()))) { + continue; // skip this domain + } + + if (domainProperties.containsKey(ENTRY_NAME_SEPARATOR)) { + this.entryNameSeparator = + domainProperties.get(ENTRY_NAME_SEPARATOR); + // escape any regex meta characters + char ch = 0; + StringBuilder s = new StringBuilder(); + for (int i = 0; i < this.entryNameSeparator.length(); i++) { + ch = this.entryNameSeparator.charAt(i); + if (REGEX_META.indexOf(ch) != -1) { + s.append('\\'); + } + s.append(ch); + } + this.entryNameSeparatorRegEx = s.toString(); + } + + Collection keystores = + domain.getEntries(); + for (PolicyParser.KeyStoreEntry keystore : keystores) { + String keystoreName = keystore.getName(); + Map properties = + new HashMap<>(domainProperties); + properties.putAll(keystore.getProperties()); + + String keystoreType = DEFAULT_KEYSTORE_TYPE; + if (properties.containsKey(KEYSTORE_TYPE)) { + keystoreType = properties.get(KEYSTORE_TYPE); + } + + Provider keystoreProvider = null; + if (properties.containsKey(KEYSTORE_PROVIDER_NAME)) { + String keystoreProviderName = + properties.get(KEYSTORE_PROVIDER_NAME); + keystoreProvider = + Security.getProvider(keystoreProviderName); + if (keystoreProvider == null) { + throw new IOException("Error locating JCE provider: " + + keystoreProviderName); + } + } + + File keystoreFile = null; + if (properties.containsKey(KEYSTORE_URI)) { + String uri = properties.get(KEYSTORE_URI); + + try { + if (uri.startsWith("file://")) { + keystoreFile = new File(new URI(uri)); + } else { + keystoreFile = new File(uri); + } + + } catch (URISyntaxException | IllegalArgumentException e) { + throw new IOException( + "Error processing keystore property: " + + "keystoreURI=\"" + uri + "\"", e); + } + } + + KeyStore.ProtectionParameter keystoreProtection = null; + if (passwords.containsKey(keystoreName)) { + keystoreProtection = passwords.get(keystoreName); + + } else if (properties.containsKey(KEYSTORE_PASSWORD_ENV)) { + String env = properties.get(KEYSTORE_PASSWORD_ENV); + String pwd = System.getenv(env); + if (pwd != null) { + keystoreProtection = + new KeyStore.PasswordProtection(pwd.toCharArray()); + } else { + throw new IOException( + "Error processing keystore property: " + + "keystorePasswordEnv=\"" + env + "\""); + } + } else { + keystoreProtection = new KeyStore.PasswordProtection(null); + } + + builders.add(new KeyStoreBuilderComponents(keystoreName, + keystoreType, keystoreProvider, keystoreFile, + keystoreProtection)); + } + break; // skip other domains + } + if (builders.isEmpty()) { + throw new IOException("Error locating domain configuration data " + + "for: " + configuration); + } + + return builders; + } + +/* + * Utility class that holds the components used to construct a KeyStore.Builder + */ +class KeyStoreBuilderComponents { + String name; + String type; + Provider provider; + File file; + KeyStore.ProtectionParameter protection; + + KeyStoreBuilderComponents(String name, String type, Provider provider, + File file, KeyStore.ProtectionParameter protection) { + this.name = name; + this.type = type; + this.provider = provider; + this.file = file; + this.protection = protection; + } +} +} diff --git a/jdk/src/share/classes/sun/security/provider/PolicyParser.java b/jdk/src/share/classes/sun/security/provider/PolicyParser.java index b5247c76f9a..b13345f7c55 100644 --- a/jdk/src/share/classes/sun/security/provider/PolicyParser.java +++ b/jdk/src/share/classes/sun/security/provider/PolicyParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,12 +32,7 @@ import java.net.URL; import java.security.GeneralSecurityException; import java.security.Principal; import java.text.MessageFormat; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.Vector; -import java.util.StringTokenizer; +import java.util.*; import javax.security.auth.x500.X500Principal; import sun.security.util.Debug; @@ -97,6 +92,7 @@ public class PolicyParser { private Vector grantEntries; + private Map domainEntries; // Convenience variables for parsing private static final Debug debug = Debug.getInstance("parser", @@ -195,9 +191,10 @@ public class PolicyParser { */ lookahead = st.nextToken(); + GrantEntry ge = null; while (lookahead != StreamTokenizer.TT_EOF) { if (peek("grant")) { - GrantEntry ge = parseGrantEntry(); + ge = parseGrantEntry(); // could be null if we couldn't expand a property if (ge != null) add(ge); @@ -209,6 +206,24 @@ public class PolicyParser { // only one keystore passwordURL per policy file, others will be // ignored parseStorePassURL(); + } else if (ge == null && keyStoreUrlString == null && + storePassURL == null && peek("domain")) { + if (domainEntries == null) { + domainEntries = new TreeMap<>(); + } + DomainEntry de = parseDomainEntry(); + if (de != null) { + String domainName = de.getName(); + if (!domainEntries.containsKey(domainName)) { + domainEntries.put(domainName, de); + } else { + MessageFormat form = + new MessageFormat(ResourcesMgr.getString( + "duplicate.keystore.domain.name")); + Object[] source = {domainName}; + throw new ParsingException(form.format(source)); + } + } } else { // error? } @@ -304,6 +319,10 @@ public class PolicyParser { return grantEntries.elements(); } + public Collection getDomainEntries() { + return domainEntries.values(); + } + /** * write out the policy */ @@ -633,6 +652,67 @@ public class PolicyParser { return e; } + /** + * parse a domain entry + */ + private DomainEntry parseDomainEntry() + throws ParsingException, IOException + { + boolean ignoreEntry = false; + DomainEntry domainEntry; + String name = null; + Map properties = new HashMap<>(); + + match("domain"); + name = match("domain name"); + + while(!peek("{")) { + // get the domain properties + properties = parseProperties("{"); + } + match("{"); + domainEntry = new DomainEntry(name, properties); + + while(!peek("}")) { + + match("keystore"); + name = match("keystore name"); + // get the keystore properties + if (!peek("}")) { + properties = parseProperties(";"); + } + match(";"); + domainEntry.add(new KeyStoreEntry(name, properties)); + } + match("}"); + + return (ignoreEntry == true) ? null : domainEntry; + } + + /* + * Return a collection of domain properties or keystore properties. + */ + private Map parseProperties(String terminator) + throws ParsingException, IOException { + + Map properties = new HashMap<>(); + String key; + String value; + while (!peek(terminator)) { + key = match("property name"); + match("="); + + try { + value = expand(match("quoted string")); + } catch (PropertyExpander.ExpandException peee) { + throw new IOException(peee.getLocalizedMessage()); + } + properties.put(key.toLowerCase(), value); + } + + return properties; + } + // package-private: used by PolicyFile for static policy static String[] parseExtDirs(String codebase, int start) { @@ -708,6 +788,10 @@ public class PolicyParser { if (expect.equalsIgnoreCase("*")) found = true; break; + case ';': + if (expect.equalsIgnoreCase(";")) + found = true; + break; default: } @@ -739,6 +823,11 @@ public class PolicyParser { } else if (expect.equalsIgnoreCase("principal type")) { value = st.sval; lookahead = st.nextToken(); + } else if (expect.equalsIgnoreCase("domain name") || + expect.equalsIgnoreCase("keystore name") || + expect.equalsIgnoreCase("property name")) { + value = st.sval; + lookahead = st.nextToken(); } else { throw new ParsingException(st.lineno(), expect, st.sval); @@ -788,6 +877,12 @@ public class PolicyParser { else throw new ParsingException(st.lineno(), expect, "*"); break; + case '=': + if (expect.equalsIgnoreCase("=")) + lookahead = st.nextToken(); + else + throw new ParsingException(st.lineno(), expect, "="); + break; default: throw new ParsingException(st.lineno(), expect, new String(new char[] {(char)lookahead})); @@ -1185,6 +1280,108 @@ public class PolicyParser { } } + /** + * Each domain entry in the keystore domain configuration file is + * represented by a DomainEntry object. + */ + static class DomainEntry { + private final String name; + private final Map properties; + private final Map entries; + + DomainEntry(String name, Map properties) { + this.name = name; + this.properties = properties; + entries = new HashMap<>(); + } + + String getName() { + return name; + } + + Map getProperties() { + return properties; + } + + Collection getEntries() { + return entries.values(); + } + + void add(KeyStoreEntry entry) throws ParsingException { + String keystoreName = entry.getName(); + if (!entries.containsKey(keystoreName)) { + entries.put(keystoreName, entry); + } else { + MessageFormat form = new MessageFormat(ResourcesMgr.getString( + "duplicate.keystore.name")); + Object[] source = {keystoreName}; + throw new ParsingException(form.format(source)); + } + } + + @Override + public String toString() { + StringBuilder s = + new StringBuilder("\ndomain ").append(name); + + if (properties != null) { + for (Map.Entry property : + properties.entrySet()) { + s.append("\n ").append(property.getKey()).append('=') + .append(property.getValue()); + } + } + s.append(" {\n"); + + if (entries != null) { + for (KeyStoreEntry entry : entries.values()) { + s.append(entry).append("\n"); + } + } + s.append("}"); + + return s.toString(); + } + } + + /** + * Each keystore entry in the keystore domain configuration file is + * represented by a KeyStoreEntry object. + */ + + static class KeyStoreEntry { + private final String name; + private final Map properties; + + KeyStoreEntry(String name, Map properties) { + this.name = name; + this.properties = properties; + } + + String getName() { + return name; + } + + Map getProperties() { + return properties; + } + + @Override + public String toString() { + StringBuilder s = new StringBuilder("\n keystore ").append(name); + if (properties != null) { + for (Map.Entry property : + properties.entrySet()) { + s.append("\n ").append(property.getKey()).append('=') + .append(property.getValue()); + } + } + s.append(";"); + + return s.toString(); + } + } + public static class ParsingException extends GeneralSecurityException { private static final long serialVersionUID = -4330692689482574072L; diff --git a/jdk/src/share/classes/sun/security/provider/Sun.java b/jdk/src/share/classes/sun/security/provider/Sun.java index 20edc86b275..4af2be50864 100644 --- a/jdk/src/share/classes/sun/security/provider/Sun.java +++ b/jdk/src/share/classes/sun/security/provider/Sun.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,13 +40,14 @@ public final class Sun extends Provider { private static final String INFO = "SUN " + "(DSA key/parameter generation; DSA signing; SHA-1, MD5 digests; " + - "SecureRandom; X.509 certificates; JKS keystore; PKIX CertPathValidator; " + + "SecureRandom; X.509 certificates; JKS & DKS keystores; " + + "PKIX CertPathValidator; " + "PKIX CertPathBuilder; LDAP, Collection CertStores, JavaPolicy Policy; " + "JavaLoginConfig Configuration)"; public Sun() { /* We are the SUN provider */ - super("SUN", 1.7, INFO); + super("SUN", 1.8, INFO); // if there is no security manager installed, put directly into // the provider. Otherwise, create a temporary map and use a diff --git a/jdk/src/share/classes/sun/security/provider/SunEntries.java b/jdk/src/share/classes/sun/security/provider/SunEntries.java index 3876acbf3be..daa4e96760c 100644 --- a/jdk/src/share/classes/sun/security/provider/SunEntries.java +++ b/jdk/src/share/classes/sun/security/provider/SunEntries.java @@ -208,6 +208,7 @@ final class SunEntries { map.put("KeyStore.JKS", "sun.security.provider.JavaKeyStore$JKS"); map.put("KeyStore.CaseExactJKS", "sun.security.provider.JavaKeyStore$CaseExactJKS"); + map.put("KeyStore.DKS", "sun.security.provider.DomainKeyStore$DKS"); /* * Policy diff --git a/jdk/src/share/classes/sun/security/util/Resources.java b/jdk/src/share/classes/sun/security/util/Resources.java index ef073b0a1fd..50028264d14 100644 --- a/jdk/src/share/classes/sun/security/util/Resources.java +++ b/jdk/src/share/classes/sun/security/util/Resources.java @@ -127,6 +127,8 @@ public class Resources extends java.util.ListResourceBundle { {"multiple.Codebase.expressions", "multiple Codebase expressions"}, {"multiple.SignedBy.expressions","multiple SignedBy expressions"}, + {"duplicate.keystore.domain.name","duplicate keystore domain name: {0}"}, + {"duplicate.keystore.name","duplicate keystore name: {0}"}, {"SignedBy.has.empty.alias","SignedBy has empty alias"}, {"can.not.specify.Principal.with.a.wildcard.class.without.a.wildcard.name", "can not specify Principal with a wildcard class without a wildcard name"}, diff --git a/jdk/src/share/classes/sun/text/resources/FormatData.java b/jdk/src/share/classes/sun/text/resources/FormatData.java index f31a1d34d09..76576336846 100644 --- a/jdk/src/share/classes/sun/text/resources/FormatData.java +++ b/jdk/src/share/classes/sun/text/resources/FormatData.java @@ -85,14 +85,22 @@ public class FormatData extends ListResourceBundle { /** * Overrides ListResourceBundle */ + @Override protected final Object[][] getContents() { - final String[] buddhistEras = new String[] { // Thai Buddhist calendar era strings + // Julian calendar era strings + final String[] julianEras = { + "BC", + "AD" + }; + + // Thai Buddhist calendar era strings + final String[] buddhistEras = { "BC", // BC "B.E." // Buddhist Era }; // Japanese imperial calendar era abbreviations - final String[] japaneseEraAbbrs = new String[] { + final String[] japaneseEraAbbrs = { "", "M", "T", @@ -100,6 +108,21 @@ public class FormatData extends ListResourceBundle { "H", }; + // Japanese imperial calendar era strings + final String[] japaneseEras = { + "", + "Meiji", + "Taisho", + "Showa", + "Heisei", + }; + + // Minguo era strings + final String[] rocEras ={ + "Before R.O.C.", + "R.O.C.", + }; + return new Object[][] { { "MonthNames", new String[] { @@ -181,11 +204,15 @@ public class FormatData extends ListResourceBundle { } }, { "Eras", - new String[] { // era strings for GregorianCalendar - "BC", - "AD" + julianEras }, + { "cldr.long.Eras", + new String[] { + "Before Christ", + "Anno Domini" } }, + { "cldr.short.Eras", + julianEras }, { "narrow.Eras", new String[] { "B", @@ -202,19 +229,16 @@ public class FormatData extends ListResourceBundle { buddhistEras }, { "japanese.Eras", - new String[] { // Japanese imperial calendar era strings - "", - "Meiji", - "Taisho", - "Showa", - "Heisei", - } - }, + japaneseEras }, + { "cldr.japanese.long.Eras", + japaneseEras }, + { "cldr.japanese.short.Eras", + japaneseEras }, { "japanese.short.Eras", - japaneseEraAbbrs + japaneseEraAbbrs }, { "japanese.narrow.Eras", - japaneseEraAbbrs + japaneseEraAbbrs }, { "japanese.FirstYear", new String[] { // Japanese imperial calendar year name @@ -848,12 +872,8 @@ public class FormatData extends ListResourceBundle { "{1} {0}" // date-time pattern } }, - { "roc.Eras", - new String[] { - "Before R.O.C.", - "R.O.C.", - } - }, + { "roc.Eras", rocEras }, + { "roc.short.Eras", rocEras }, { "cldr.roc.DatePatterns", new String[] { "EEEE, G y MMMM dd", 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 127c03a5dab..b50abe12538 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 @@ -85,7 +85,12 @@ public class FormatData_ar extends ListResourceBundle { /** * Overrides ListResourceBundle */ + @Override protected final Object[][] getContents() { + final String[] rocEras = { + "Before R.O.C.", + "\u062c\u0645\u0647\u0648\u0631\u064a\u0629 \u0627\u0644\u0635\u064a", + }; return new Object[][] { { "MonthNames", new String[] { @@ -211,12 +216,8 @@ public class FormatData_ar extends ListResourceBundle { "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", - } - }, + { "roc.Eras", rocEras }, + { "roc.short.Eras", rocEras }, { "cldr.roc.DatePatterns", new String[] { "EEEE\u060c d MMMM\u060c y G", 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 608ae6d25f2..398bbdd8e51 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 @@ -85,7 +85,12 @@ public class FormatData_el extends ListResourceBundle { /** * Overrides ListResourceBundle */ + @Override protected final Object[][] getContents() { + final String[] rocEras = { + "\u03a0\u03c1\u03b9\u03bd R.O.C.", + "R.O.C.", + }; return new Object[][] { { "MonthNames", new String[] { @@ -230,12 +235,8 @@ public class FormatData_el extends ListResourceBundle { "d/M/yy", } }, - { "roc.Eras", - new String[] { - "\u03a0\u03c1\u03b9\u03bd R.O.C.", - "R.O.C.", - } - }, + { "roc.Eras", rocEras }, + { "roc.short.Eras", rocEras }, { "cldr.roc.DatePatterns", new String[] { "EEEE, d MMMM, y G", 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 ff37b50bfa6..8d3a64d5c0c 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 @@ -82,7 +82,12 @@ public class FormatData_hr extends ListResourceBundle { /** * Overrides ListResourceBundle */ + @Override protected final Object[][] getContents() { + final String[] rocEras ={ + "prije R.O.C.", + "R.O.C.", + }; return new Object[][] { { "MonthNames", new String[] { @@ -266,12 +271,8 @@ public class FormatData_hr extends ListResourceBundle { "d.M.y. G", } }, - { "roc.Eras", - new String[] { - "prije R.O.C.", - "R.O.C.", - } - }, + { "roc.Eras", rocEras }, + { "roc.short.Eras", rocEras }, { "cldr.roc.DatePatterns", new String[] { "EEEE, d. MMMM y. G", 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 cbff2411926..53eba9df55d 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 @@ -82,7 +82,20 @@ public class FormatData_ja extends ListResourceBundle { /** * Overrides ListResourceBundle */ + @Override protected final Object[][] getContents() { + // era strings for Japanese imperial calendar + final String[] japaneseEras = { + "\u897f\u66a6", // Seireki (Gregorian) + "\u660e\u6cbb", // Meiji + "\u5927\u6b63", // Taisho + "\u662d\u548c", // Showa + "\u5e73\u6210", // Heisei + }; + final String[] rocEras = { + "\u6c11\u56fd\u524d", + "\u6c11\u56fd", + }; return new Object[][] { { "MonthNames", new String[] { @@ -177,15 +190,8 @@ public class FormatData_ja extends ListResourceBundle { "Gy/MM/dd", } }, - { "japanese.Eras", - new String[] { // era strings for Japanese imperial calendar - "\u897f\u66a6", // Seireki (Gregorian) - "\u660e\u6cbb", // Meiji - "\u5927\u6b63", // Taisho - "\u662d\u548c", // Showa - "\u5e73\u6210", // Heisei - } - }, + { "japanese.Eras", japaneseEras }, + { "cldr.japanese.short.Eras", japaneseEras }, { "japanese.FirstYear", new String[] { // first year name "\u5143", // "Gan"-nen @@ -257,12 +263,8 @@ public class FormatData_ja extends ListResourceBundle { } }, { "DateTimePatternChars", "GyMdkHmsSEDFwWahKzZ" }, - { "roc.Eras", - new String[] { - "\u6c11\u56fd\u524d", - "\u6c11\u56fd", - } - }, + { "roc.Eras", rocEras }, + { "roc.short.Eras", rocEras }, { "cldr.roc.DatePatterns", new String[] { "Gy\u5e74M\u6708d\u65e5EEEE", 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 6e1b3fba3f3..15872b2ede5 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 @@ -82,7 +82,12 @@ public class FormatData_ko extends ListResourceBundle { /** * Overrides ListResourceBundle */ + @Override protected final Object[][] getContents() { + final String[] rocEras = { + "\uc911\ud654\ubbfc\uad6d\uc804", + "\uc911\ud654\ubbfc\uad6d", + }; return new Object[][] { { "MonthNames", new String[] { @@ -195,12 +200,8 @@ public class FormatData_ko extends ListResourceBundle { "G y. M. d", } }, - { "roc.Eras", - new String[] { - "\uc911\ud654\ubbfc\uad6d\uc804", - "\uc911\ud654\ubbfc\uad6d", - } - }, + { "roc.Eras", rocEras }, + { "roc.short.Eras", rocEras }, { "cldr.roc.DatePatterns", new String[] { "G y\ub144 M\uc6d4 d\uc77c EEEE", 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 a190e09ac2a..793b00b2609 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 @@ -43,7 +43,12 @@ package sun.text.resources.sr; import java.util.ListResourceBundle; public class FormatData_sr extends ListResourceBundle { + @Override protected final Object[][] getContents() { + final String[] rocEras = { + "\u041f\u0440\u0435 \u0420\u041a", + "\u0420\u041a", + }; return new Object[][] { { "MonthNames", new String[] { @@ -182,12 +187,8 @@ public class FormatData_sr extends ListResourceBundle { "M/d/yy G", } }, - { "roc.Eras", - new String[] { - "\u041f\u0440\u0435 \u0420\u041a", - "\u0420\u041a", - } - }, + { "roc.Eras", rocEras }, + { "roc.short.Eras", rocEras }, { "islamic.MonthNames", new String[] { "\u041c\u0443\u0440\u0430\u0445\u0430\u043c", 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 1d555e486da..b7ee4e78d57 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 @@ -82,7 +82,12 @@ public class FormatData_sv extends ListResourceBundle { /** * Overrides ListResourceBundle */ + @Override protected final Object[][] getContents() { + final String[] rocEras = { + "f\u00f6re R.K.", + "R.K.", + }; return new Object[][] { { "MonthNames", new String[] { @@ -250,12 +255,8 @@ public class FormatData_sv extends ListResourceBundle { "G y-MM-dd", } }, - { "roc.Eras", - new String[] { - "f\u00f6re R.K.", - "R.K.", - } - }, + { "roc.Eras", rocEras }, + { "roc.short.Eras", rocEras }, { "cldr.roc.DatePatterns", new String[] { "EEEE d MMMM y G", 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 8e7da48f655..83e0d7871ef 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 @@ -82,7 +82,12 @@ public class FormatData_zh extends ListResourceBundle { /** * Overrides ListResourceBundle */ + @Override protected final Object[][] getContents() { + final String[] rocEras = { + "\u6c11\u56fd\u524d", + "\u6c11\u56fd", + }; return new Object[][] { { "MonthNames", new String[] { @@ -217,12 +222,8 @@ public class FormatData_zh extends ListResourceBundle { "Gyy-MM-dd", } }, - { "roc.Eras", - new String[] { - "\u6c11\u56fd\u524d", - "\u6c11\u56fd", - } - }, + { "roc.Eras", rocEras }, + { "roc.short.Eras", rocEras }, { "cldr.roc.DatePatterns", new String[] { "Gy\u5e74M\u6708d\u65e5EEEE", 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 c7fef5e8265..7171bd9b166 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 @@ -82,7 +82,12 @@ public class FormatData_zh_TW extends ListResourceBundle { /** * Overrides ListResourceBundle */ + @Override protected final Object[][] getContents() { + final String[] rocEras = { + "\u6c11\u570b\u524d", + "\u6c11\u570b", + }; return new Object[][] { { "Eras", new String[] { // era strings @@ -135,12 +140,8 @@ public class FormatData_zh_TW extends ListResourceBundle { "Gy/M/d", } }, - { "roc.Eras", - new String[] { - "\u6c11\u570b\u524d", - "\u6c11\u570b", - } - }, + { "roc.Eras", rocEras }, + { "roc.short.Eras", rocEras }, { "cldr.roc.DatePatterns", new String[] { "Gy\u5e74M\u6708d\u65e5EEEE", diff --git a/jdk/src/share/classes/sun/util/calendar/CalendarSystem.java b/jdk/src/share/classes/sun/util/calendar/CalendarSystem.java index fdbdcb07099..589f552eb95 100644 --- a/jdk/src/share/classes/sun/util/calendar/CalendarSystem.java +++ b/jdk/src/share/classes/sun/util/calendar/CalendarSystem.java @@ -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 @@ -25,6 +25,13 @@ package sun.util.calendar; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.Properties; import java.util.TimeZone; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -170,6 +177,44 @@ public abstract class CalendarSystem { return (cs == null) ? cal : cs; } + /** + * Returns a {@link Properties} loaded from lib/calendars.properties. + * + * @return a {@link Properties} loaded from lib/calendars.properties + * @throws IOException if an error occurred when reading from the input stream + * @throws IllegalArgumentException if the input stream contains any malformed + * Unicode escape sequences + */ + public static Properties getCalendarProperties() throws IOException { + Properties calendarProps = null; + try { + String homeDir = AccessController.doPrivileged( + new sun.security.action.GetPropertyAction("java.home")); + final String fname = homeDir + File.separator + "lib" + File.separator + + "calendars.properties"; + calendarProps = AccessController.doPrivileged(new PrivilegedExceptionAction() { + @Override + public Properties run() throws IOException { + Properties props = new Properties(); + try (FileInputStream fis = new FileInputStream(fname)) { + props.load(fis); + } + return props; + } + }); + } catch (PrivilegedActionException e) { + Throwable cause = e.getCause(); + if (cause instanceof IOException) { + throw (IOException) cause; + } else if (cause instanceof IllegalArgumentException) { + throw (IllegalArgumentException) cause; + } + // Should not happen + throw new InternalError(cause); + } + return calendarProps; + } + //////////////////////////////// Calendar API ////////////////////////////////// /** diff --git a/jdk/src/share/classes/sun/util/calendar/LocalGregorianCalendar.java b/jdk/src/share/classes/sun/util/calendar/LocalGregorianCalendar.java index d107a004d63..aa0a73b76a7 100644 --- a/jdk/src/share/classes/sun/util/calendar/LocalGregorianCalendar.java +++ b/jdk/src/share/classes/sun/util/calendar/LocalGregorianCalendar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, 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 @@ -25,12 +25,7 @@ package sun.util.calendar; -import java.io.File; -import java.io.FileInputStream; import java.io.IOException; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; import java.util.ArrayList; import java.util.List; import java.util.Properties; @@ -59,6 +54,7 @@ public class LocalGregorianCalendar extends BaseCalendar { private int gregorianYear = FIELD_UNDEFINED; + @Override public Date setEra(Era era) { if (getEra() != era) { super.setEra(era); @@ -67,12 +63,14 @@ public class LocalGregorianCalendar extends BaseCalendar { return this; } + @Override public Date addYear(int localYear) { super.addYear(localYear); gregorianYear += localYear; return this; } + @Override public Date setYear(int localYear) { if (getYear() != localYear) { super.setYear(localYear); @@ -81,10 +79,12 @@ public class LocalGregorianCalendar extends BaseCalendar { return this; } + @Override public int getNormalizedYear() { return gregorianYear; } + @Override public void setNormalizedYear(int normalizedYear) { this.gregorianYear = normalizedYear; } @@ -97,6 +97,7 @@ public class LocalGregorianCalendar extends BaseCalendar { super.setYear(year); } + @Override public String toString() { String time = super.toString(); time = time.substring(time.indexOf('T')); @@ -117,25 +118,12 @@ public class LocalGregorianCalendar extends BaseCalendar { } static LocalGregorianCalendar getLocalGregorianCalendar(String name) { - Properties calendarProps = null; + Properties calendarProps; try { - String homeDir = AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("java.home")); - final String fname = homeDir + File.separator + "lib" + File.separator - + "calendars.properties"; - calendarProps = AccessController.doPrivileged(new PrivilegedExceptionAction() { - public Properties run() throws IOException { - Properties props = new Properties(); - try (FileInputStream fis = new FileInputStream(fname)) { - props.load(fis); - } - return props; - } - }); - } catch (PrivilegedActionException e) { - throw new RuntimeException(e.getException()); + calendarProps = CalendarSystem.getCalendarProperties(); + } catch (IOException | IllegalArgumentException e) { + throw new InternalError(e); } - // Parse calendar.*.eras String props = calendarProps.getProperty("calendar." + name + ".eras"); if (props == null) { @@ -190,22 +178,27 @@ public class LocalGregorianCalendar extends BaseCalendar { setEras(eras); } + @Override public String getName() { return name; } + @Override public Date getCalendarDate() { return getCalendarDate(System.currentTimeMillis(), newCalendarDate()); } + @Override public Date getCalendarDate(long millis) { return getCalendarDate(millis, newCalendarDate()); } + @Override public Date getCalendarDate(long millis, TimeZone zone) { return getCalendarDate(millis, newCalendarDate(zone)); } + @Override public Date getCalendarDate(long millis, CalendarDate date) { Date ldate = (Date) super.getCalendarDate(millis, date); return adjustYear(ldate, millis, ldate.getZoneOffset()); @@ -234,14 +227,17 @@ public class LocalGregorianCalendar extends BaseCalendar { return ldate; } + @Override public Date newCalendarDate() { return new Date(); } + @Override public Date newCalendarDate(TimeZone zone) { return new Date(zone); } + @Override public boolean validate(CalendarDate date) { Date ldate = (Date) date; Era era = ldate.getEra(); @@ -249,7 +245,16 @@ public class LocalGregorianCalendar extends BaseCalendar { if (!validateEra(era)) { return false; } - ldate.setNormalizedYear(era.getSinceDate().getYear() + ldate.getYear()); + ldate.setNormalizedYear(era.getSinceDate().getYear() + ldate.getYear() - 1); + // If it's not the last Era, validate the date. + if (era != eras[eras.length - 1]) { + Date tmp = newCalendarDate(date.getZone()); + tmp.setEra(era).setDate(date.getYear(), date.getMonth(), date.getDayOfMonth()); + normalize(tmp); + if (tmp.getEra() != era) { + return false; + } + } } else { ldate.setNormalizedYear(ldate.getYear()); } @@ -266,6 +271,7 @@ public class LocalGregorianCalendar extends BaseCalendar { return false; } + @Override public boolean normalize(CalendarDate date) { if (date.isNormalized()) { return true; @@ -339,6 +345,7 @@ public class LocalGregorianCalendar extends BaseCalendar { return true; } + @Override void normalizeMonth(CalendarDate date) { normalizeYear(date); super.normalizeMonth(date); @@ -360,6 +367,7 @@ public class LocalGregorianCalendar extends BaseCalendar { * Returns whether the specified Gregorian year is a leap year. * @see #isLeapYear(Era, int) */ + @Override public boolean isLeapYear(int gregorianYear) { return CalendarUtils.isGregorianLeapYear(gregorianYear); } @@ -372,6 +380,7 @@ public class LocalGregorianCalendar extends BaseCalendar { return isLeapYear(gyear); } + @Override public void getCalendarDateFromFixedDate(CalendarDate date, long fixedDate) { Date ldate = (Date) date; super.getCalendarDateFromFixedDate(ldate, fixedDate); diff --git a/jdk/src/share/classes/sun/util/calendar/ZoneInfo.java b/jdk/src/share/classes/sun/util/calendar/ZoneInfo.java index 2838be44603..995ec45fcc7 100644 --- a/jdk/src/share/classes/sun/util/calendar/ZoneInfo.java +++ b/jdk/src/share/classes/sun/util/calendar/ZoneInfo.java @@ -30,10 +30,12 @@ import java.io.ObjectInputStream; import java.lang.ref.SoftReference; import java.security.AccessController; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Set; import java.util.SimpleTimeZone; import java.util.TimeZone; @@ -78,19 +80,6 @@ public class ZoneInfo extends TimeZone { private static final long ABBR_MASK = 0xf00L; private static final int TRANSITION_NSHIFT = 12; - // Flag for supporting JDK backward compatible IDs, such as "EST". - static final boolean USE_OLDMAPPING; - static { - String oldmapping = AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("sun.timezone.ids.oldmapping", "false")).toLowerCase(Locale.ROOT); - USE_OLDMAPPING = (oldmapping.equals("yes") || oldmapping.equals("true")); - } - - // IDs having conflicting data between Olson and JDK 1.1 - static final String[] conflictingIDs = { - "EST", "MST", "HST" - }; - private static final CalendarSystem gcal = CalendarSystem.getGregorianCalendar(); /** @@ -521,7 +510,7 @@ public class ZoneInfo extends TimeZone { SimpleTimeZone tz = getLastRule(); if (tz != null) { return tz.inDaylightTime(date); - } + } return false; } @@ -572,17 +561,8 @@ public class ZoneInfo extends TimeZone { * @return an array of time zone IDs. */ public static String[] getAvailableIDs() { - List idList = ZoneInfoFile.getZoneIDs(); - List excluded = ZoneInfoFile.getExcludedZones(); - if (excluded != null) { - // List all zones from the idList and excluded lists - List list = new ArrayList<>(idList.size() + excluded.size()); - list.addAll(idList); - list.addAll(excluded); - idList = list; - } - String[] ids = new String[idList.size()]; - return idList.toArray(ids); + Set idSet = ZoneInfoFile.getZoneIds(); + return idSet.toArray(new String[idSet.size()]); } /** @@ -595,45 +575,7 @@ public class ZoneInfo extends TimeZone { * @return an array of time zone IDs. */ public static String[] getAvailableIDs(int rawOffset) { - String[] result; - List matched = new ArrayList<>(); - List IDs = ZoneInfoFile.getZoneIDs(); - int[] rawOffsets = ZoneInfoFile.getRawOffsets(); - - loop: - for (int index = 0; index < rawOffsets.length; index++) { - if (rawOffsets[index] == rawOffset) { - byte[] indices = ZoneInfoFile.getRawOffsetIndices(); - for (int i = 0; i < indices.length; i++) { - if (indices[i] == index) { - matched.add(IDs.get(i++)); - while (i < indices.length && indices[i] == index) { - matched.add(IDs.get(i++)); - } - break loop; - } - } - } - } - - // We need to add any zones from the excluded zone list that - // currently have the same GMT offset as the specified - // rawOffset. The zones returned by this method may not be - // correct as of return to the caller if any GMT offset - // transition is happening during this GMT offset checking... - List excluded = ZoneInfoFile.getExcludedZones(); - if (excluded != null) { - for (String id : excluded) { - TimeZone zi = getTimeZone(id); - if (zi != null && zi.getRawOffset() == rawOffset) { - matched.add(id); - } - } - } - - result = new String[matched.size()]; - matched.toArray(result); - return result; + return ZoneInfoFile.getZoneIds(rawOffset); } /** @@ -645,44 +587,7 @@ public class ZoneInfo extends TimeZone { * time zone of the ID. */ public static TimeZone getTimeZone(String ID) { - String givenID = null; - - /* - * If old JDK compatibility is specified, get the old alias - * name. - */ - if (USE_OLDMAPPING) { - String compatibleID = TzIDOldMapping.MAP.get(ID); - if (compatibleID != null) { - givenID = ID; - ID = compatibleID; - } - } - - ZoneInfo zi = ZoneInfoFile.getZoneInfo(ID); - if (zi == null) { - // if we can't create an object for the ID, try aliases. - try { - Map map = getAliasTable(); - String alias = ID; - while ((alias = map.get(alias)) != null) { - zi = ZoneInfoFile.getZoneInfo(alias); - if (zi != null) { - zi.setID(ID); - zi = ZoneInfoFile.addToCache(ID, zi); - zi = (ZoneInfo) zi.clone(); - break; - } - } - } catch (Exception e) { - // ignore exceptions - } - } - - if (givenID != null && zi != null) { - zi.setID(givenID); - } - return zi; + return ZoneInfoFile.getZoneInfo(ID); } private transient SimpleTimeZone lastRule; @@ -811,18 +716,6 @@ public class ZoneInfo extends TimeZone { return (checksum == ((ZoneInfo)other).checksum); } - private static SoftReference> aliasTable; - - static Map getCachedAliasTable() { - Map aliases = null; - - SoftReference> cache = aliasTable; - if (cache != null) { - aliases = cache.get(); - } - return aliases; - } - /** * Returns a Map from alias time zone IDs to their standard * time zone IDs. @@ -831,22 +724,9 @@ public class ZoneInfo extends TimeZone { * to their standard time zone IDs, or null if * ZoneInfoMappings file is not available. */ - public synchronized static Map getAliasTable() { - Map aliases = getCachedAliasTable(); - if (aliases == null) { - aliases = ZoneInfoFile.getZoneAliases(); - if (aliases != null) { - if (!USE_OLDMAPPING) { - // Remove the conflicting IDs from the alias table. - for (String key : conflictingIDs) { - aliases.remove(key); - } - } - aliasTable = new SoftReference>(aliases); - } - } - return aliases; - } + public static Map getAliasTable() { + return ZoneInfoFile.getAliasMap(); + } private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { diff --git a/jdk/src/share/classes/sun/util/calendar/ZoneInfoFile.java b/jdk/src/share/classes/sun/util/calendar/ZoneInfoFile.java index 094c956a365..2bddab21f2d 100644 --- a/jdk/src/share/classes/sun/util/calendar/ZoneInfoFile.java +++ b/jdk/src/share/classes/sun/util/calendar/ZoneInfoFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 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 @@ -25,494 +25,125 @@ package sun.util.calendar; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.lang.ref.SoftReference; -import java.nio.file.FileSystems; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.io.ByteArrayInputStream; +import java.io.DataInput; +import java.io.DataInputStream; +import java.io.File; +import java.io.IOException; +import java.io.StreamCorruptedException; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.time.DayOfWeek; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.Month; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.zone.ZoneRules; +import java.time.zone.ZoneOffsetTransition; +import java.time.zone.ZoneOffsetTransitionRule; +import java.time.zone.ZoneOffsetTransitionRule.TimeDefinition; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; +import java.util.SimpleTimeZone; +import java.util.concurrent.ConcurrentHashMap; +import java.util.zip.CRC32; +import java.util.zip.ZipFile; /** - * ZoneInfoFile reads Zone information files in the - * <java.home>/lib/zi directory and provides time zone - * information in the form of a {@link ZoneInfo} object. Also, it - * reads the ZoneInfoMappings file to obtain time zone IDs information - * that is used by the {@link ZoneInfo} class. The directory layout - * and data file formats are as follows. - * - *

      Directory layout

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

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

      File format

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

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

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

      1. ZoneInfo data file

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

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

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

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

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

      1.1 transition structure

      - *

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

      1.2 offset_table structure

      - *

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

      1.3 simpletimezone structure

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

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

      1.4 raw_offset structure

      - *

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

      1.5 dstsaving structure

      - * Value has dstSaving in seconds. - *

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

      1.6 checksum structure

      - *

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

      1.7 gmtoffsetwillchange structure

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

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

      2. ZoneInfoMappings file

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

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

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

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

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

      2.1 zone_id_table structure

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

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

      2.2 raw_offset_table structure

      - *
      - *

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

      2.3 raw_offset_index_table structure

      - *
      - *

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

      2.4 alias_table structure

      - *
      - *

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

      2.5 versionName structure

      - *
      - *

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

      2.6 excludeList structure

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

      - *
      - *   excluded_list {
      - *      u1      tag;              // 0x45 : constant
      - *      u2      length;           // byte length of whole values
      - *      u2      nentries;         // number of zone_ids
      - *      zone_id value[nentries];  // excluded zone IDs
      - *   }
      - * 
      - *
      - * - * @since 1.4 + * @since 1.8 */ - -public class ZoneInfoFile { +public final class ZoneInfoFile { /** - * The magic number for the ZoneInfo data file format. + * Gets all available IDs supported in the Java run-time. + * + * @return a set of time zone IDs. */ - public static final byte[] JAVAZI_LABEL = { - (byte)'j', (byte)'a', (byte)'v', (byte)'a', (byte)'z', (byte)'i', (byte)'\0' - }; - private static final int JAVAZI_LABEL_LENGTH = JAVAZI_LABEL.length; + public static Set getZoneIds() { + return zones.keySet(); + } /** - * The ZoneInfo data file format version number. Must increase - * one when any incompatible change has been made. + * Gets all available IDs that have the same value as the + * specified raw GMT offset. + * + * @param rawOffset the GMT offset in milliseconds. This + * value should not include any daylight saving time. + * @return an array of time zone IDs. */ - public static final byte JAVAZI_VERSION = 0x01; - - /** - * Raw offset data item tag. - */ - public static final byte TAG_RawOffset = 1; - - /** - * Known last Daylight Saving Time save value data item tag. - */ - public static final byte TAG_LastDSTSaving = 2; - - /** - * Checksum data item tag. - */ - public static final byte TAG_CRC32 = 3; - - /** - * Transition data item tag. - */ - public static final byte TAG_Transition = 4; - - /** - * Offset table data item tag. - */ - public static final byte TAG_Offset = 5; - - /** - * SimpleTimeZone parameters data item tag. - */ - public static final byte TAG_SimpleTimeZone = 6; - - /** - * Raw GMT offset will change in the future. - */ - public static final byte TAG_GMTOffsetWillChange = 7; - - - /** - * The ZoneInfoMappings file name. - */ - public static final String JAVAZM_FILE_NAME = "ZoneInfoMappings"; - - /** - * The magic number for the ZoneInfoMappings file format. - */ - public static final byte[] JAVAZM_LABEL = { - (byte)'j', (byte)'a', (byte)'v', (byte)'a', (byte)'z', (byte)'m', (byte)'\0' - }; - private static final int JAVAZM_LABEL_LENGTH = JAVAZM_LABEL.length; - - /** - * The ZoneInfoMappings file format version number. Must increase - * one when any incompatible change has been made. - */ - public static final byte JAVAZM_VERSION = 0x01; - - /** - * Time zone IDs data item tag. - */ - public static final byte TAG_ZoneIDs = 64; - - /** - * Raw GMT offsets table data item tag. - */ - public static final byte TAG_RawOffsets = 65; - - /** - * Indices to the raw GMT offset table data item tag. - */ - public static final byte TAG_RawOffsetIndices = 66; - - /** - * Time zone aliases table data item tag. - */ - public static final byte TAG_ZoneAliases = 67; - - /** - * Olson's public zone information version tag. - */ - public static final byte TAG_TZDataVersion = 68; - - /** - * Excluded zones item tag. (Added in Mustang) - */ - public static final byte TAG_ExcludedZones = 69; - - private static Map zoneInfoObjects = null; - - private static final ZoneInfo GMT = new ZoneInfo("GMT", 0); - - private static final String ziDir = AccessController.doPrivileged( - new PrivilegedAction() { - public String run() { - String zi = System.getProperty("java.home") + - File.separator + "lib" + File.separator + "zi"; - try { - zi = FileSystems.getDefault().getPath(zi).toRealPath().toString(); - } catch(Exception e) { - } - return zi; + public static String[] getZoneIds(int rawOffset) { + List ids = new ArrayList<>(); + for (String id : zones.keySet()) { + ZoneInfo zi = getZoneInfo0(id); + if (zi.getRawOffset() == rawOffset) { + ids.add(id); } - }); + } + // It appears the "zi" implementation returns the + // sorted list, though the specification does not + // specify it. Keep the same behavior for better + // compatibility. + String[] list = ids.toArray(new String[ids.size()]); + Arrays.sort(list); + return list; + } + + public static ZoneInfo getZoneInfo(String zoneId) { + if (!zones.containsKey(zoneId)) { + return null; + } + // ZoneInfo is mutable, return the copy + + ZoneInfo zi = getZoneInfo0(zoneId); + zi = (ZoneInfo)zi.clone(); + zi.setID(zoneId); + return zi; + } /** - * Converts the given time zone ID to a platform dependent path - * name. For example, "America/Los_Angeles" is converted to - * "America\Los_Angeles" on Win32. - * @return a modified ID replacing '/' with {@link - * java.io.File#separatorChar File.separatorChar} if needed. + * Returns a Map from alias time zone IDs to their standard + * time zone IDs. + * + * @return an unmodified alias mapping */ - public static String getFileName(String ID) { - if (File.separatorChar == '/') { - return ID; - } - return ID.replace('/', File.separatorChar); + public static Map getAliasMap() { + return aliases; + } + + /** + * Gets the version of this tz data. + * + * @return the tzdb version + */ + public static String getVersion() { + return versionId; } /** * Gets a ZoneInfo with the given GMT offset. The object * has its ID in the format of GMT{+|-}hh:mm. * - * @param originalId the given custom id (before normalized such as "GMT+9") - * @param gmtOffset GMT offset in milliseconds + * @param originalId the given custom id (before normalized such as "GMT+9") + * @param gmtOffset GMT offset in milliseconds * @return a ZoneInfo constructed with the given GMT offset */ public static ZoneInfo getCustomTimeZone(String originalId, int gmtOffset) { String id = toCustomID(gmtOffset); - + return new ZoneInfo(id, gmtOffset); +/* ZoneInfo zi = getFromCache(id); if (zi == null) { zi = new ZoneInfo(id, gmtOffset); @@ -522,6 +153,7 @@ public class ZoneInfoFile { } } return (ZoneInfo) zi.clone(); +*/ } public static String toCustomID(int gmtOffset) { @@ -549,531 +181,670 @@ public class ZoneInfoFile { return new String(buf); } - /** - * @return a ZoneInfo instance created for the specified id, or - * null if there is no time zone data file found for the specified - * id. - */ - public static ZoneInfo getZoneInfo(String id) { - //treat GMT zone as special - if ("GMT".equals(id)) - return (ZoneInfo) GMT.clone(); - ZoneInfo zi = getFromCache(id); - if (zi == null) { - Map aliases = ZoneInfo.getCachedAliasTable(); - if (aliases != null && aliases.get(id) != null) { - return null; - } - zi = createZoneInfo(id); - if (zi == null) { - return null; - } - zi = addToCache(id, zi); - } - return (ZoneInfo) zi.clone(); - } - synchronized static ZoneInfo getFromCache(String id) { - if (zoneInfoObjects == null) { - return null; - } - return zoneInfoObjects.get(id); - } - - synchronized static ZoneInfo addToCache(String id, ZoneInfo zi) { - if (zoneInfoObjects == null) { - zoneInfoObjects = new HashMap<>(); - } else { - ZoneInfo zone = zoneInfoObjects.get(id); - if (zone != null) { - return zone; - } - } - zoneInfoObjects.put(id, zi); - return zi; - } - - private static ZoneInfo createZoneInfo(String id) { - byte[] buf = readZoneInfoFile(getFileName(id)); - if (buf == null) { - return null; - } - - int index = 0; - int filesize = buf.length; - int rawOffset = 0; - int dstSavings = 0; - int checksum = 0; - boolean willGMTOffsetChange = false; - long[] transitions = null; - int[] offsets = null; - int[] simpleTimeZoneParams = null; + /////////////////////////////////////////////////////////// + private static ZoneInfo getZoneInfo0(String zoneId) { try { - for (index = 0; index < JAVAZI_LABEL.length; index++) { - if (buf[index] != JAVAZI_LABEL[index]) { - System.err.println("ZoneInfo: wrong magic number: " + id); - return null; - } + + Object obj = zones.get(zoneId); + if (obj instanceof byte[]) { + byte[] bytes = (byte[]) obj; + DataInputStream dis = new DataInputStream(new ByteArrayInputStream(bytes)); + obj = getZoneInfo(dis, zoneId); + zones.put(zoneId, obj); } - if (buf[index++] > JAVAZI_VERSION) { - System.err.println("ZoneInfo: incompatible version (" - + buf[index - 1] + "): " + id); - return null; - } - - while (index < filesize) { - byte tag = buf[index++]; - int len = ((buf[index++] & 0xFF) << 8) + (buf[index++] & 0xFF); - - if (filesize < index+len) { - break; - } - - switch (tag) { - case TAG_CRC32: - { - int val = buf[index++] & 0xff; - val = (val << 8) + (buf[index++] & 0xff); - val = (val << 8) + (buf[index++] & 0xff); - val = (val << 8) + (buf[index++] & 0xff); - checksum = val; - } - break; - - case TAG_LastDSTSaving: - { - short val = (short)(buf[index++] & 0xff); - val = (short)((val << 8) + (buf[index++] & 0xff)); - dstSavings = val * 1000; - } - break; - - case TAG_RawOffset: - { - int val = buf[index++] & 0xff; - val = (val << 8) + (buf[index++] & 0xff); - val = (val << 8) + (buf[index++] & 0xff); - val = (val << 8) + (buf[index++] & 0xff); - rawOffset = val; - } - break; - - case TAG_Transition: - { - int n = len / 8; - transitions = new long[n]; - for (int i = 0; i < n; i ++) { - long val = buf[index++] & 0xff; - val = (val << 8) + (buf[index++] & 0xff); - val = (val << 8) + (buf[index++] & 0xff); - val = (val << 8) + (buf[index++] & 0xff); - val = (val << 8) + (buf[index++] & 0xff); - val = (val << 8) + (buf[index++] & 0xff); - val = (val << 8) + (buf[index++] & 0xff); - val = (val << 8) + (buf[index++] & 0xff); - transitions[i] = val; - } - } - break; - - case TAG_Offset: - { - int n = len / 4; - offsets = new int[n]; - for (int i = 0; i < n; i ++) { - int val = buf[index++] & 0xff; - val = (val << 8) + (buf[index++] & 0xff); - val = (val << 8) + (buf[index++] & 0xff); - val = (val << 8) + (buf[index++] & 0xff); - offsets[i] = val; - } - } - break; - - case TAG_SimpleTimeZone: - { - if (len != 32 && len != 40) { - System.err.println("ZoneInfo: wrong SimpleTimeZone parameter size"); - return null; - } - int n = len / 4; - simpleTimeZoneParams = new int[n]; - for (int i = 0; i < n; i++) { - int val = buf[index++] & 0xff; - val = (val << 8) + (buf[index++] & 0xff); - val = (val << 8) + (buf[index++] & 0xff); - val = (val << 8) + (buf[index++] & 0xff); - simpleTimeZoneParams[i] = val; - } - } - break; - - case TAG_GMTOffsetWillChange: - { - if (len != 1) { - System.err.println("ZoneInfo: wrong byte length for TAG_GMTOffsetWillChange"); - } - willGMTOffsetChange = buf[index++] == 1; - } - break; - - default: - System.err.println("ZoneInfo: unknown tag < " + tag + ">. ignored."); - index += len; - break; - } - } - } catch (Exception e) { - System.err.println("ZoneInfo: corrupted zoneinfo file: " + id); - return null; + return (ZoneInfo)obj; + } catch (Exception ex) { + throw new RuntimeException("Invalid binary time-zone data: TZDB:" + + zoneId + ", version: " + versionId, ex); } - - if (index != filesize) { - System.err.println("ZoneInfo: wrong file size: " + id); - return null; - } - - return new ZoneInfo(id, rawOffset, dstSavings, checksum, - transitions, offsets, simpleTimeZoneParams, - willGMTOffsetChange); - } - - private volatile static SoftReference> zoneIDs = null; - - static List getZoneIDs() { - List ids = null; - - SoftReference> cache = zoneIDs; - if (cache != null) { - ids = cache.get(); - if (ids != null) { - return ids; - } - } - - byte[] buf = null; - buf = getZoneInfoMappings(); - int index = JAVAZM_LABEL_LENGTH + 1; - int filesize = buf.length; - - try { - loop: - while (index < filesize) { - byte tag = buf[index++]; - int len = ((buf[index++] & 0xFF) << 8) + (buf[index++] & 0xFF); - - switch (tag) { - case TAG_ZoneIDs: - { - int n = (buf[index++] << 8) + (buf[index++] & 0xFF); - ids = new ArrayList<>(n); - - for (int i = 0; i < n; i++) { - byte m = buf[index++]; - ids.add(new String(buf, index, m, "UTF-8")); - index += m; - } - } - break loop; - - default: - index += len; - break; - } - } - } catch (Exception e) { - System.err.println("ZoneInfo: corrupted " + JAVAZM_FILE_NAME); - } - - zoneIDs = new SoftReference<>(ids); - return ids; - } - - /** - * @return an alias table in HashMap where a key is an alias ID - * (e.g., "PST") and its value is a real time zone ID (e.g., - * "America/Los_Angeles"). - */ - static Map getZoneAliases() { - byte[] buf = getZoneInfoMappings(); - int index = JAVAZM_LABEL_LENGTH + 1; - int filesize = buf.length; - Map aliases = null; - - try { - loop: - while (index < filesize) { - byte tag = buf[index++]; - int len = ((buf[index++] & 0xFF) << 8) + (buf[index++] & 0xFF); - - switch (tag) { - case TAG_ZoneAliases: - { - int n = (buf[index++] << 8) + (buf[index++] & 0xFF); - aliases = new HashMap<>(n); - for (int i = 0; i < n; i++) { - byte m = buf[index++]; - String name = new String(buf, index, m, "UTF-8"); - index += m; - m = buf[index++]; - String realName = new String(buf, index, m, "UTF-8"); - index += m; - aliases.put(name, realName); - } - } - break loop; - - default: - index += len; - break; - } - } - } catch (Exception e) { - System.err.println("ZoneInfo: corrupted " + JAVAZM_FILE_NAME); - return null; - } - return aliases; - } - - private volatile static SoftReference> excludedIDs = null; - private volatile static boolean hasNoExcludeList = false; - - /** - * @return a List of zone IDs for zones that will change their GMT - * offsets in some future time. - * - * @since 1.6 - */ - static List getExcludedZones() { - if (hasNoExcludeList) { - return null; - } - - List excludeList = null; - - SoftReference> cache = excludedIDs; - if (cache != null) { - excludeList = cache.get(); - if (excludeList != null) { - return excludeList; - } - } - - byte[] buf = getZoneInfoMappings(); - int index = JAVAZM_LABEL_LENGTH + 1; - int filesize = buf.length; - - try { - loop: - while (index < filesize) { - byte tag = buf[index++]; - int len = ((buf[index++] & 0xFF) << 8) + (buf[index++] & 0xFF); - - switch (tag) { - case TAG_ExcludedZones: - { - int n = (buf[index++] << 8) + (buf[index++] & 0xFF); - excludeList = new ArrayList<>(); - for (int i = 0; i < n; i++) { - byte m = buf[index++]; - String name = new String(buf, index, m, "UTF-8"); - index += m; - excludeList.add(name); - } - } - break loop; - - default: - index += len; - break; - } - } - } catch (Exception e) { - System.err.println("ZoneInfo: corrupted " + JAVAZM_FILE_NAME); - return null; - } - - if (excludeList != null) { - excludedIDs = new SoftReference<>(excludeList); - } else { - hasNoExcludeList = true; - } - return excludeList; - } - - private volatile static SoftReference rawOffsetIndices = null; - - static byte[] getRawOffsetIndices() { - byte[] indices = null; - - SoftReference cache = rawOffsetIndices; - if (cache != null) { - indices = cache.get(); - if (indices != null) { - return indices; - } - } - - byte[] buf = getZoneInfoMappings(); - int index = JAVAZM_LABEL_LENGTH + 1; - int filesize = buf.length; - - try { - loop: - while (index < filesize) { - byte tag = buf[index++]; - int len = ((buf[index++] & 0xFF) << 8) + (buf[index++] & 0xFF); - - switch (tag) { - case TAG_RawOffsetIndices: - { - indices = new byte[len]; - for (int i = 0; i < len; i++) { - indices[i] = buf[index++]; - } - } - break loop; - - default: - index += len; - break; - } - } - } catch (ArrayIndexOutOfBoundsException e) { - System.err.println("ZoneInfo: corrupted " + JAVAZM_FILE_NAME); - } - - rawOffsetIndices = new SoftReference<>(indices); - return indices; - } - - private volatile static SoftReference rawOffsets = null; - - static int[] getRawOffsets() { - int[] offsets = null; - - SoftReference cache = rawOffsets; - if (cache != null) { - offsets = cache.get(); - if (offsets != null) { - return offsets; - } - } - - byte[] buf = getZoneInfoMappings(); - int index = JAVAZM_LABEL_LENGTH + 1; - int filesize = buf.length; - - try { - loop: - while (index < filesize) { - byte tag = buf[index++]; - int len = ((buf[index++] & 0xFF) << 8) + (buf[index++] & 0xFF); - - switch (tag) { - case TAG_RawOffsets: - { - int n = len/4; - offsets = new int[n]; - for (int i = 0; i < n; i++) { - int val = buf[index++] & 0xff; - val = (val << 8) + (buf[index++] & 0xff); - val = (val << 8) + (buf[index++] & 0xff); - val = (val << 8) + (buf[index++] & 0xff); - offsets[i] = val; - } - } - break loop; - - default: - index += len; - break; - } - } - } catch (ArrayIndexOutOfBoundsException e) { - System.err.println("ZoneInfo: corrupted " + JAVAZM_FILE_NAME); - } - - rawOffsets = new SoftReference<>(offsets); - return offsets; - } - - private volatile static SoftReference zoneInfoMappings = null; - - private static byte[] getZoneInfoMappings() { - byte[] data; - - SoftReference cache = zoneInfoMappings; - if (cache != null) { - data = cache.get(); - if (data != null) { - return data; - } - } - - data = readZoneInfoFile(JAVAZM_FILE_NAME); - - if (data == null) { - return null; - } - - int index; - for (index = 0; index < JAVAZM_LABEL.length; index++) { - if (data[index] != JAVAZM_LABEL[index]) { - System.err.println("ZoneInfo: wrong magic number: " + JAVAZM_FILE_NAME); - return null; - } - } - if (data[index++] > JAVAZM_VERSION) { - System.err.println("ZoneInfo: incompatible version (" - + data[index - 1] + "): " + JAVAZM_FILE_NAME); - return null; - } - - zoneInfoMappings = new SoftReference<>(data); - return data; - } - - /** - * Reads the specified file under <java.home>/lib/zi into a buffer. - * @return the buffer, or null if any I/O error occurred. - */ - private static byte[] readZoneInfoFile(final String fileName) { - if (fileName.indexOf("..") >= 0) { - return null; - } - byte[] buffer = null; - - try { - buffer = AccessController.doPrivileged(new PrivilegedExceptionAction() { - public byte[] run() throws IOException { - File file = new File(ziDir, fileName); - byte[] buf = null; - int filesize = (int)file.length(); - if (filesize > 0) { - FileInputStream fis = new FileInputStream(file); - buf = new byte[filesize]; - try { - if (fis.read(buf) != filesize) { - throw new IOException("read error on " + fileName); - } - } finally { - fis.close(); - } - } - return buf; - } - }); - } catch (PrivilegedActionException e) { - Exception ex = e.getException(); - if (!(ex instanceof FileNotFoundException) || JAVAZM_FILE_NAME.equals(fileName)) { - System.err.println("ZoneInfo: " + ex.getMessage()); - } - } - return buffer; } private ZoneInfoFile() { } + + private static String versionId; + private final static Map zones = new ConcurrentHashMap<>(); + private static Map aliases = new HashMap<>(); + + // Flag for supporting JDK backward compatible IDs, such as "EST". + private static final boolean USE_OLDMAPPING; + + static { + String oldmapping = AccessController.doPrivileged( + new sun.security.action.GetPropertyAction("sun.timezone.ids.oldmapping", "false")).toLowerCase(Locale.ROOT); + USE_OLDMAPPING = (oldmapping.equals("yes") || oldmapping.equals("true")); + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + try { + + String libDir = System.getProperty("java.home") + File.separator + "lib"; + File tzdbJar = new File(libDir, "tzdb.jar"); + try (ZipFile zf = new ZipFile(tzdbJar); + DataInputStream dis = new DataInputStream( + zf.getInputStream(zf.getEntry("TZDB.dat")))) { + load(dis); + } + } catch (Exception x) { + throw new Error(x); + } + return null; + } + }); + } + + // Must be invoked after loading in all data + private static void addOldMapping() { + String[][] oldMappings = new String[][] { + { "ACT", "Australia/Darwin" }, + { "AET", "Australia/Sydney" }, + { "AGT", "America/Argentina/Buenos_Aires" }, + { "ART", "Africa/Cairo" }, + { "AST", "America/Anchorage" }, + { "BET", "America/Sao_Paulo" }, + { "BST", "Asia/Dhaka" }, + { "CAT", "Africa/Harare" }, + { "CNT", "America/St_Johns" }, + { "CST", "America/Chicago" }, + { "CTT", "Asia/Shanghai" }, + { "EAT", "Africa/Addis_Ababa" }, + { "ECT", "Europe/Paris" }, + { "IET", "America/Indiana/Indianapolis" }, + { "IST", "Asia/Kolkata" }, + { "JST", "Asia/Tokyo" }, + { "MIT", "Pacific/Apia" }, + { "NET", "Asia/Yerevan" }, + { "NST", "Pacific/Auckland" }, + { "PLT", "Asia/Karachi" }, + { "PNT", "America/Phoenix" }, + { "PRT", "America/Puerto_Rico" }, + { "PST", "America/Los_Angeles" }, + { "SST", "Pacific/Guadalcanal" }, + { "VST", "Asia/Ho_Chi_Minh" }, + }; + for (String[] alias : oldMappings) { + String k = alias[0]; + String v = alias[1]; + if (zones.containsKey(v)) { // make sure we do have the data + aliases.put(k, v); + zones.put(k, zones.get(v)); + } + } + if (USE_OLDMAPPING) { + if (zones.containsKey("America/New_York")) { + aliases.put("EST", "America/New_York"); + zones.put("EST", zones.get("America/New_York")); + } + if (zones.containsKey("America/Denver")) { + aliases.put("MST", "America/Denver"); + zones.put("MST", zones.get("America/Denver")); + } + if (zones.containsKey("Pacific/Honolulu")) { + aliases.put("HST", "Pacific/Honolulu"); + zones.put("HST", zones.get("Pacific/Honolulu")); + } + } + } + + /** + * Loads the rules from a DateInputStream + * + * @param dis the DateInputStream to load, not null + * @throws Exception if an error occurs + */ + private static void 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, only keep the last one + int versionCount = dis.readShort(); + for (int i = 0; i < versionCount; i++) { + versionId = dis.readUTF(); + + } + // regions + int regionCount = dis.readShort(); + String[] regionArray = new String[regionCount]; + for (int i = 0; i < regionCount; i++) { + regionArray[i] = dis.readUTF(); + } + // 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; + } + // link version-region-rules, only keep the last version, if more than one + for (int i = 0; i < versionCount; i++) { + regionCount = dis.readShort(); + zones.clear(); + for (int j = 0; j < regionCount; j++) { + String region = regionArray[dis.readShort()]; + Object rule = ruleArray[dis.readShort() & 0xffff]; + zones.put(region, rule); + } + } + // remove the following ids from the map, they + // are exclued from the "old" ZoneInfo + zones.remove("ROC"); + for (int i = 0; i < versionCount; i++) { + int aliasCount = dis.readShort(); + aliases.clear(); + for (int j = 0; j < aliasCount; j++) { + String alias = regionArray[dis.readShort()]; + String region = regionArray[dis.readShort()]; + aliases.put(alias, region); + } + } + // old us time-zone names + addOldMapping(); + aliases = Collections.unmodifiableMap(aliases); + } + + /////////////////////////Ser///////////////////////////////// + public static ZoneInfo getZoneInfo(DataInput in, String zoneId) throws Exception { + byte type = in.readByte(); + // TBD: assert ZRULES: + int stdSize = in.readInt(); + long[] stdTrans = new long[stdSize]; + for (int i = 0; i < stdSize; i++) { + stdTrans[i] = readEpochSec(in); + } + int [] stdOffsets = new int[stdSize + 1]; + for (int i = 0; i < stdOffsets.length; i++) { + stdOffsets[i] = readOffset(in); + } + int savSize = in.readInt(); + long[] savTrans = new long[savSize]; + for (int i = 0; i < savSize; i++) { + savTrans[i] = readEpochSec(in); + } + int[] savOffsets = new int[savSize + 1]; + for (int i = 0; i < savOffsets.length; i++) { + savOffsets[i] = readOffset(in); + } + int ruleSize = in.readByte(); + ZoneOffsetTransitionRule[] rules = new ZoneOffsetTransitionRule[ruleSize]; + for (int i = 0; i < ruleSize; i++) { + rules[i] = readZOTRule(in); + } + return getZoneInfo(zoneId, stdTrans, stdOffsets, savTrans, savOffsets, rules); + } + + public static int readOffset(DataInput in) throws IOException { + int offsetByte = in.readByte(); + return offsetByte == 127 ? in.readInt() : offsetByte * 900; + } + + 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; + } + } + + static ZoneOffsetTransitionRule readZOTRule(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); + } + + /////////////////////////ZoneRules --> ZoneInfo///////////////////////////////// + + // ZoneInfo starts with UTC1900 + private static final long UTC1900 = -2208988800L; + // ZoneInfo ends with UTC2037 + private static final long UTC2037 = + LocalDateTime.of(2038, 1, 1, 0, 0, 0).toEpochSecond(ZoneOffset.UTC) - 1; + + /* Get a ZoneInfo instance. + * + * @param standardTransitions the standard transitions, not null + * @param standardOffsets the standard offsets, not null + * @param savingsInstantTransitions the standard transitions, not null + * @param wallOffsets the wall offsets, not null + * @param lastRules the recurring last rules, size 15 or less, not null + */ + private static ZoneInfo getZoneInfo(String zoneId, + long[] standardTransitions, + int[] standardOffsets, + long[] savingsInstantTransitions, + int[] wallOffsets, + ZoneOffsetTransitionRule[] lastRules) { + int rawOffset = 0; + int dstSavings = 0; + int checksum = 0; + int[] params = null; + boolean willGMTOffsetChange = false; + + // rawOffset, pick the last one + if (standardTransitions.length > 0) + rawOffset = standardOffsets[standardOffsets.length - 1] * 1000; + else + rawOffset = standardOffsets[0] * 1000; + + // transitions, offsets; + long[] transitions = null; + int[] offsets = null; + int nOffsets = 0; + int nTrans = 0; + + if (savingsInstantTransitions.length != 0) { + transitions = new long[250]; + offsets = new int[100]; // TBD: ZoneInfo actually can't handle + // offsets.length > 16 (4-bit index limit) + // last year in trans table + // It should not matter to use before or after offset for year + int lastyear = LocalDateTime.ofEpochSecond( + savingsInstantTransitions[savingsInstantTransitions.length - 1], 0, + ZoneOffset.ofTotalSeconds(wallOffsets[savingsInstantTransitions.length - 1])).getYear(); + // int lastyear = savingsLocalTransitions[savingsLocalTransitions.length - 1].getYear(); + + int i = 0, k = 1; + while (i < savingsInstantTransitions.length && + savingsInstantTransitions[i] < UTC1900) { + i++; // skip any date before UTC1900 + } + if (i < savingsInstantTransitions.length) { + // javazic writes the last GMT offset into index 0! + if (i < savingsInstantTransitions.length) { + offsets[0] = standardOffsets[standardOffsets.length - 1] * 1000; + nOffsets = 1; + } + // ZoneInfo has a beginning entry for 1900. + // Only add it if this is not the only one in table + nOffsets = addTrans(transitions, nTrans++, offsets, nOffsets, + UTC1900, + wallOffsets[i], + getStandardOffset(standardTransitions, standardOffsets, UTC1900)); + } + for (; i < savingsInstantTransitions.length; i++) { + //if (savingsLocalTransitions[i * 2].getYear() > LASTYEAR) { + if (savingsInstantTransitions[i] > UTC2037) { + // no trans beyond LASTYEAR + lastyear = LASTYEAR; + break; + } + long trans = savingsInstantTransitions[i]; + while (k < standardTransitions.length) { + // some standard offset transitions don't exist in + // savingInstantTrans, if the offset "change" doesn't + // really change the "effectiveWallOffset". For example + // the 1999/2000 pair in Zone Arg/Buenos_Aires, in which + // the daylightsaving "happened" but it actually does + // not result in the timezone switch. ZoneInfo however + // needs them in its transitions table + long trans_s = standardTransitions[k]; + if (trans_s >= UTC1900) { + if (trans_s > trans) + break; + if (trans_s < trans) { + if (nOffsets + 2 >= offsets.length) { + offsets = Arrays.copyOf(offsets, offsets.length + 100); + } + if (nTrans + 1 >= transitions.length) { + transitions = Arrays.copyOf(transitions, transitions.length + 100); + } + nOffsets = addTrans(transitions, nTrans++, offsets, nOffsets, + trans_s, + wallOffsets[i], + standardOffsets[k+1]); + } + } + k++; + } + if (nOffsets + 2 >= offsets.length) { + offsets = Arrays.copyOf(offsets, offsets.length + 100); + } + if (nTrans + 1 >= transitions.length) { + transitions = Arrays.copyOf(transitions, transitions.length + 100); + } + nOffsets = addTrans(transitions, nTrans++, offsets, nOffsets, + trans, + wallOffsets[i + 1], + getStandardOffset(standardTransitions, standardOffsets, trans)); + } + // append any leftover standard trans + while (k < standardTransitions.length) { + long trans = standardTransitions[k]; + if (trans >= UTC1900) { + int offset = wallOffsets[i]; + int offsetIndex = indexOf(offsets, 0, nOffsets, offset); + if (offsetIndex == nOffsets) + nOffsets++; + transitions[nTrans++] = ((trans * 1000) << TRANSITION_NSHIFT) | + (offsetIndex & OFFSET_MASK); + } + k++; + } + if (lastRules.length > 1) { + // fill the gap between the last trans until LASTYEAR + while (lastyear++ < LASTYEAR) { + for (ZoneOffsetTransitionRule zotr : lastRules) { + ZoneOffsetTransition zot = zotr.createTransition(lastyear); + //long trans = zot.getDateTimeBefore().toEpochSecond(); + long trans = zot.toEpochSecond(); + if (nOffsets + 2 >= offsets.length) { + offsets = Arrays.copyOf(offsets, offsets.length + 100); + } + if (nTrans + 1 >= transitions.length) { + transitions = Arrays.copyOf(transitions, transitions.length + 100); + } + nOffsets = addTrans(transitions, nTrans++, offsets, nOffsets, + trans, + zot.getOffsetAfter().getTotalSeconds(), + getStandardOffset(standardTransitions, standardOffsets, trans)); + } + } + ZoneOffsetTransitionRule startRule = lastRules[lastRules.length - 2]; + ZoneOffsetTransitionRule endRule = lastRules[lastRules.length - 1]; + params = new int[10]; + if (startRule.getOffsetBefore().compareTo(startRule.getOffsetAfter()) < 0 && + endRule.getOffsetBefore().compareTo(endRule.getOffsetAfter()) > 0) { + ZoneOffsetTransitionRule tmp; + tmp = startRule; + startRule = endRule; + endRule = tmp; + } + params[0] = startRule.getMonth().getValue() - 1; + // params[1] = startRule.getDayOfMonthIndicator(); + // params[2] = toCalendarDOW[startRule.getDayOfWeek().getValue()]; + int dom = startRule.getDayOfMonthIndicator(); + DayOfWeek dow = startRule.getDayOfWeek(); + if (dow == null) { + params[1] = startRule.getDayOfMonthIndicator(); + params[2] = 0; + } else { + // ZoneRulesBuilder adjusts < 0 case (-1, for last, don't have + // "<=" case yet) to positive value if not February (it appears + // we don't have February cutoff in tzdata table yet) + // Ideally, if JSR310 can just pass in the nagative and + // we can then pass in the dom = -1, dow > 0 into ZoneInfo + // + // hacking, assume the >=24 is the result of ZRB optimization for + // "last", it works for now. + if (dom < 0 || dom >= 24) { + params[1] = -1; + params[2] = toCalendarDOW[dow.getValue()]; + } else { + params[1] = dom; + // To specify a day of week on or after an exact day of month, + // set the month to an exact month value, day-of-month to the + // day on or after which the rule is applied, and day-of-week + // to a negative Calendar.DAY_OF_WEEK DAY_OF_WEEK field value. + params[2] = -toCalendarDOW[dow.getValue()]; + } + } + params[3] = startRule.getLocalTime().toSecondOfDay() * 1000; + params[4] = toSTZTime[startRule.getTimeDefinition().ordinal()]; + + params[5] = endRule.getMonth().getValue() - 1; + // params[6] = endRule.getDayOfMonthIndicator(); + // params[7] = toCalendarDOW[endRule.getDayOfWeek().getValue()]; + dom = endRule.getDayOfMonthIndicator(); + dow = endRule.getDayOfWeek(); + if (dow == null) { + params[6] = dom; + params[7] = 0; + } else { + // hacking: see comment above + if (dom < 0 || dom >= 24) { + params[6] = -1; + params[7] = toCalendarDOW[dow.getValue()]; + } else { + params[6] = dom; + params[7] = -toCalendarDOW[dow.getValue()]; + } + } + params[8] = endRule.getLocalTime().toSecondOfDay() * 1000; + params[9] = toSTZTime[endRule.getTimeDefinition().ordinal()]; + dstSavings = (startRule.getOffsetAfter().getTotalSeconds() + - startRule.getOffsetBefore().getTotalSeconds()) * 1000; + // Note: known mismatching -> Asia/Amman + // ZoneInfo : startDayOfWeek=5 <= Thursday + // startTime=86400000 <= 24 hours + // This: startDayOfWeek=6 + // startTime=0 + // Below is the workaround, it probably slows down everyone a little + if (params[2] == 6 && params[3] == 0 && zoneId.equals("Asia/Amman")) { + params[2] = 5; + params[3] = 86400000; + } + } else if (nTrans > 0) { // only do this if there is something in table already + if (lastyear < LASTYEAR) { + // ZoneInfo has an ending entry for 2037 + long trans = OffsetDateTime.of(LASTYEAR, Month.JANUARY.getValue(), 1, 0, 0, 0, 0, + ZoneOffset.ofTotalSeconds(rawOffset/1000)) + .toEpochSecond(); + int offsetIndex = indexOf(offsets, 0, nOffsets, rawOffset/1000); + if (offsetIndex == nOffsets) + nOffsets++; + transitions[nTrans++] = (trans * 1000) << TRANSITION_NSHIFT | + (offsetIndex & OFFSET_MASK); + } else if (savingsInstantTransitions.length > 2) { + // Workaround: create the params based on the last pair for + // zones like Israel and Iran which have trans defined + // up until 2037, but no "transition rule" defined + // + // Note: Known mismatching for Israel, Asia/Jerusalem/Tel Aviv + // ZoneInfo: startMode=3 + // startMonth=2 + // startDay=26 + // startDayOfWeek=6 + // + // This: startMode=1 + // startMonth=2 + // startDay=27 + // startDayOfWeek=0 + // these two are actually the same for 2037, the SimpleTimeZone + // for the last "known" year + int m = savingsInstantTransitions.length; + long startTrans = savingsInstantTransitions[m - 2]; + int startOffset = wallOffsets[m - 2 + 1]; + int startStd = getStandardOffset(standardTransitions, standardOffsets, startTrans); + long endTrans = savingsInstantTransitions[m - 1]; + int endOffset = wallOffsets[m - 1 + 1]; + int endStd = getStandardOffset(standardTransitions, standardOffsets, endTrans); + + if (startOffset > startStd && endOffset == endStd) { + /* + m = savingsLocalTransitions.length; + LocalDateTime startLDT = savingsLocalTransitions[m -4]; //gap + LocalDateTime endLDT = savingsLocalTransitions[m - 1]; //over + */ + // last - 1 trans + m = savingsInstantTransitions.length - 2; + ZoneOffset before = ZoneOffset.ofTotalSeconds(wallOffsets[m]); + ZoneOffset after = ZoneOffset.ofTotalSeconds(wallOffsets[m + 1]); + ZoneOffsetTransition trans = ZoneOffsetTransition.of( + LocalDateTime.ofEpochSecond(savingsInstantTransitions[m], 0, before), + before, + after); + LocalDateTime startLDT; + if (trans.isGap()) { + startLDT = trans.getDateTimeBefore(); + } else { + startLDT = trans.getDateTimeAfter(); + } + // last trans + m = savingsInstantTransitions.length - 1; + before = ZoneOffset.ofTotalSeconds(wallOffsets[m]); + after = ZoneOffset.ofTotalSeconds(wallOffsets[m + 1]); + trans = ZoneOffsetTransition.of( + LocalDateTime.ofEpochSecond(savingsInstantTransitions[m], 0, before), + before, + after); + LocalDateTime endLDT; + if (trans.isGap()) { + endLDT = trans.getDateTimeAfter(); + } else { + endLDT = trans.getDateTimeBefore(); + } + params = new int[10]; + params[0] = startLDT.getMonthValue() - 1; + params[1] = startLDT.getDayOfMonth(); + params[2] = 0; + params[3] = startLDT.toLocalTime().toSecondOfDay() * 1000; + params[4] = SimpleTimeZone.WALL_TIME; + params[5] = endLDT.getMonthValue() - 1; + params[6] = endLDT.getDayOfMonth(); + params[7] = 0; + params[8] = endLDT.toLocalTime().toSecondOfDay() * 1000; + params[9] = SimpleTimeZone.WALL_TIME; + dstSavings = (startOffset - startStd) * 1000; + } + } + } + if (transitions != null && transitions.length != nTrans) { + if (nTrans == 0) { + transitions = null; + } else { + transitions = Arrays.copyOf(transitions, nTrans); + } + } + if (offsets != null && offsets.length != nOffsets) { + if (nOffsets == 0) { + offsets = null; + } else { + offsets = Arrays.copyOf(offsets, nOffsets); + } + } + if (transitions != null) { + Checksum sum = new Checksum(); + for (i = 0; i < transitions.length; i++) { + long val = transitions[i]; + int dst = (int)((val >>> DST_NSHIFT) & 0xfL); + int saving = (dst == 0) ? 0 : offsets[dst]; + int index = (int)(val & OFFSET_MASK); + int offset = offsets[index]; + long second = (val >> TRANSITION_NSHIFT); + // javazic uses "index of the offset in offsets", + // instead of the real offset value itself to + // calculate the checksum. Have to keep doing + // the same thing, checksum is part of the + // ZoneInfo serialization form. + sum.update(second + index); + sum.update(index); + sum.update(dst == 0 ? -1 : dst); + } + checksum = (int)sum.getValue(); + } + } + return new ZoneInfo(zoneId, rawOffset, dstSavings, checksum, transitions, + offsets, params, willGMTOffsetChange); + } + + private static int getStandardOffset(long[] standardTransitions, + int[] standardOffsets, + long epochSec) { + int index = Arrays.binarySearch(standardTransitions, epochSec); + if (index < 0) { + // switch negative insert position to start of matched range + index = -index - 2; + } + return standardOffsets[index + 1]; + } + + private static int toCalendarDOW[] = new int[] { + -1, + Calendar.MONDAY, + Calendar.TUESDAY, + Calendar.WEDNESDAY, + Calendar.THURSDAY, + Calendar.FRIDAY, + Calendar.SATURDAY, + Calendar.SUNDAY + }; + + private static int toSTZTime[] = new int[] { + SimpleTimeZone.UTC_TIME, + SimpleTimeZone.WALL_TIME, + SimpleTimeZone.STANDARD_TIME, + }; + + private static final long OFFSET_MASK = 0x0fL; + private static final long DST_MASK = 0xf0L; + private static final int DST_NSHIFT = 4; + private static final int TRANSITION_NSHIFT = 12; + private static final int LASTYEAR = 2037; + + // from: 0 for offset lookup, 1 for dstsvings lookup + private static int indexOf(int[] offsets, int from, int nOffsets, int offset) { + offset *= 1000; + for (; from < nOffsets; from++) { + if (offsets[from] == offset) + return from; + } + offsets[from] = offset; + return from; + } + + // return updated nOffsets + private static int addTrans(long transitions[], int nTrans, + int offsets[], int nOffsets, + long trans, int offset, int stdOffset) { + int offsetIndex = indexOf(offsets, 0, nOffsets, offset); + if (offsetIndex == nOffsets) + nOffsets++; + int dstIndex = 0; + if (offset != stdOffset) { + dstIndex = indexOf(offsets, 1, nOffsets, offset - stdOffset); + if (dstIndex == nOffsets) + nOffsets++; + } + transitions[nTrans] = ((trans * 1000) << TRANSITION_NSHIFT) | + ((dstIndex << DST_NSHIFT) & DST_MASK) | + (offsetIndex & OFFSET_MASK); + return nOffsets; + } + + ///////////////////////////////////////////////////////////// + // ZoneInfo checksum, copy/pasted from javazic + private static class Checksum extends CRC32 { + public void update(int val) { + byte[] b = new byte[4]; + b[0] = (byte)((val >>> 24) & 0xff); + b[1] = (byte)((val >>> 16) & 0xff); + b[2] = (byte)((val >>> 8) & 0xff); + b[3] = (byte)(val & 0xff); + update(b); + } + void update(long val) { + byte[] b = new byte[8]; + b[0] = (byte)((val >>> 56) & 0xff); + b[1] = (byte)((val >>> 48) & 0xff); + b[2] = (byte)((val >>> 40) & 0xff); + b[3] = (byte)((val >>> 32) & 0xff); + b[4] = (byte)((val >>> 24) & 0xff); + b[5] = (byte)((val >>> 16) & 0xff); + b[6] = (byte)((val >>> 8) & 0xff); + b[7] = (byte)(val & 0xff); + update(b); + } + } } diff --git a/jdk/src/share/classes/sun/util/locale/provider/CalendarDataUtility.java b/jdk/src/share/classes/sun/util/locale/provider/CalendarDataUtility.java index 5b11c6cd9ac..656b6958bc6 100644 --- a/jdk/src/share/classes/sun/util/locale/provider/CalendarDataUtility.java +++ b/jdk/src/share/classes/sun/util/locale/provider/CalendarDataUtility.java @@ -66,17 +66,43 @@ public class CalendarDataUtility { LocaleServiceProviderPool pool = LocaleServiceProviderPool.getPool(CalendarNameProvider.class); return pool.getLocalizedObject(CalendarFieldValueNameGetter.INSTANCE, locale, normalizeCalendarType(id), - field, value, style); + field, value, style, false); + } + + public static String retrieveCldrFieldValueName(String id, int field, int value, int style, Locale locale) { + LocaleServiceProviderPool pool = + LocaleServiceProviderPool.getPool(CalendarNameProvider.class); + String name; + name = pool.getLocalizedObject(CalendarFieldValueNameGetter.INSTANCE, locale, normalizeCalendarType(id), + field, value, style, true); + if (name == null) { + name = pool.getLocalizedObject(CalendarFieldValueNameGetter.INSTANCE, locale, normalizeCalendarType(id), + field, value, style, false); + } + return name; } public static Map retrieveFieldValueNames(String id, int field, int style, Locale locale) { LocaleServiceProviderPool pool = LocaleServiceProviderPool.getPool(CalendarNameProvider.class); return pool.getLocalizedObject(CalendarFieldValueNamesMapGetter.INSTANCE, locale, - normalizeCalendarType(id), field, style); + normalizeCalendarType(id), field, style, false); } - private static String normalizeCalendarType(String requestID) { + public static Map retrieveCldrFieldValueNames(String id, int field, int style, Locale locale) { + LocaleServiceProviderPool pool = + LocaleServiceProviderPool.getPool(CalendarNameProvider.class); + Map map; + map = pool.getLocalizedObject(CalendarFieldValueNamesMapGetter.INSTANCE, locale, + normalizeCalendarType(id), field, style, true); + if (map == null) { + map = pool.getLocalizedObject(CalendarFieldValueNamesMapGetter.INSTANCE, locale, + normalizeCalendarType(id), field, style, false); + } + return map; + } + + static String normalizeCalendarType(String requestID) { String type; if (requestID.equals("gregorian") || requestID.equals("iso8601")) { type = "gregory"; @@ -103,10 +129,20 @@ public class CalendarDataUtility { Locale locale, String requestID, // calendarType Object... params) { - assert params.length == 3; + assert params.length == 4; int field = (int) params[0]; int value = (int) params[1]; int style = (int) params[2]; + boolean cldr = (boolean) params[3]; + + // If cldr is true, resources from CLDR have precedence over JRE + // native resources. + if (cldr && calendarNameProvider instanceof CalendarNameProviderImpl) { + String name; + name = ((CalendarNameProviderImpl)calendarNameProvider) + .getCldrDisplayName(requestID, field, value, style, locale); + return name; + } return calendarNameProvider.getDisplayName(requestID, field, value, style, locale); } } @@ -126,9 +162,19 @@ public class CalendarDataUtility { Locale locale, String requestID, // calendarType Object... params) { - assert params.length == 2; + assert params.length == 3; int field = (int) params[0]; int style = (int) params[1]; + boolean cldr = (boolean) params[2]; + + // If cldr is true, resources from CLDR have precedence over JRE + // native resources. + if (cldr && calendarNameProvider instanceof CalendarNameProviderImpl) { + Map map; + map = ((CalendarNameProviderImpl)calendarNameProvider) + .getCldrDisplayNames(requestID, field, style, locale); + return map; + } return calendarNameProvider.getDisplayNames(requestID, field, style, locale); } } diff --git a/jdk/src/share/classes/sun/util/locale/provider/CalendarNameProviderImpl.java b/jdk/src/share/classes/sun/util/locale/provider/CalendarNameProviderImpl.java index 6aa2893e173..afdfd072b8d 100644 --- a/jdk/src/share/classes/sun/util/locale/provider/CalendarNameProviderImpl.java +++ b/jdk/src/share/classes/sun/util/locale/provider/CalendarNameProviderImpl.java @@ -50,14 +50,25 @@ public class CalendarNameProviderImpl extends CalendarNameProvider implements Av @Override public String getDisplayName(String calendarType, int field, int value, int style, Locale locale) { + return getDisplayNameImpl(calendarType, field, value, style, locale, false); + } + + public String getCldrDisplayName(String calendarType, int field, int value, int style, Locale locale) { + return getDisplayNameImpl(calendarType, field, value, style, locale, true); + } + + public String getDisplayNameImpl(String calendarType, int field, int value, int style, Locale locale, boolean cldr) { String name = null; - String key = getResourceKey(calendarType, field, style); + String key = getResourceKey(calendarType, field, style, cldr); if (key != null) { String[] strings = LocaleProviderAdapter.forType(type).getLocaleResources(locale).getCalendarNames(key); if (strings != null && strings.length > 0) { if (field == DAY_OF_WEEK || field == YEAR) { --value; } + if (value < 0 || value >= strings.length) { + return null; + } name = strings[value]; // If name is empty in standalone, try its `format' style. if (name.length() == 0 @@ -76,24 +87,32 @@ public class CalendarNameProviderImpl extends CalendarNameProvider implements Av SHORT_STANDALONE, LONG_FORMAT, LONG_STANDALONE, NARROW_FORMAT, NARROW_STANDALONE }; + @Override public Map getDisplayNames(String calendarType, int field, int style, Locale locale) { Map names; if (style == ALL_STYLES) { - names = getDisplayNamesImpl(calendarType, field, SHORT_FORMAT, locale); + names = getDisplayNamesImpl(calendarType, field, SHORT_FORMAT, locale, false); for (int st : REST_OF_STYLES) { - names.putAll(getDisplayNamesImpl(calendarType, field, st, locale)); + names.putAll(getDisplayNamesImpl(calendarType, field, st, locale, false)); } } else { // specific style - names = getDisplayNamesImpl(calendarType, field, style, locale); + names = getDisplayNamesImpl(calendarType, field, style, locale, false); } return names.isEmpty() ? null : names; } + // NOTE: This method should be used ONLY BY JSR 310 classes. + public Map getCldrDisplayNames(String calendarType, int field, int style, Locale locale) { + Map names; + names = getDisplayNamesImpl(calendarType, field, style, locale, true); + return names.isEmpty() ? null : names; + } + private Map getDisplayNamesImpl(String calendarType, int field, - int style, Locale locale) { - String key = getResourceKey(calendarType, field, style); + int style, Locale locale, boolean cldr) { + String key = getResourceKey(calendarType, field, style, cldr); Map map = new TreeMap<>(LengthBasedComparator.INSTANCE); if (key != null) { String[] strings = LocaleProviderAdapter.forType(type).getLocaleResources(locale).getCalendarNames(key); @@ -201,7 +220,7 @@ public class CalendarNameProviderImpl extends CalendarNameProvider implements Av return false; } - private String getResourceKey(String type, int field, int style) { + private String getResourceKey(String type, int field, int style, boolean cldr) { int baseStyle = getBaseStyle(style); boolean isStandalone = (style != baseStyle); @@ -210,6 +229,10 @@ public class CalendarNameProviderImpl extends CalendarNameProvider implements Av } boolean isNarrow = (baseStyle == NARROW_FORMAT); StringBuilder key = new StringBuilder(); + // If cldr is true, use prefix "cldr.". + if (cldr) { + key.append("cldr."); + } switch (field) { case ERA: if (type != null) { @@ -222,6 +245,11 @@ public class CalendarNameProviderImpl extends CalendarNameProvider implements Av // due to historical reasons. (JRE DateFormatSymbols.getEras returns // abbreviations while other getShort*() return abbreviations.) if (this.type == LocaleProviderAdapter.Type.JRE) { + if (cldr) { + if (baseStyle == LONG) { + key.append("long."); + } + } if (baseStyle == SHORT) { key.append("short."); } diff --git a/jdk/src/share/classes/sun/util/locale/provider/LocaleResources.java b/jdk/src/share/classes/sun/util/locale/provider/LocaleResources.java index 009cc5b8a63..dafa74e2ab1 100644 --- a/jdk/src/share/classes/sun/util/locale/provider/LocaleResources.java +++ b/jdk/src/share/classes/sun/util/locale/provider/LocaleResources.java @@ -332,23 +332,61 @@ public class LocaleResources { } public String getDateTimePattern(int timeStyle, int dateStyle, Calendar cal) { - String pattern; - if (cal == null) { cal = Calendar.getInstance(locale); } - String calType = cal.getCalendarType(); + return getDateTimePattern(null, timeStyle, dateStyle, cal.getCalendarType()); + } + + /** + * Returns a date-time format pattern + * @param timeStyle style of time; one of FULL, LONG, MEDIUM, SHORT in DateFormat, + * or -1 if not required + * @param dateStyle style of time; one of FULL, LONG, MEDIUM, SHORT in DateFormat, + * or -1 if not required + * @param calType the calendar type for the pattern + * @return the pattern string + */ + public String getCldrDateTimePattern(int timeStyle, int dateStyle, String calType) { + calType = CalendarDataUtility.normalizeCalendarType(calType); + String pattern; + pattern = getDateTimePattern("cldr.", timeStyle, dateStyle, calType); + if (pattern == null) { + pattern = getDateTimePattern(null, timeStyle, dateStyle, calType); + } + return pattern; + } + + private String getDateTimePattern(String prefix, int timeStyle, int dateStyle, String calType) { + String pattern; String timePattern = null; String datePattern = null; + if (timeStyle >= 0) { - timePattern = getDateTimePattern("TimePatterns", timeStyle, calType); + if (prefix != null) { + timePattern = getDateTimePattern(prefix, "TimePatterns", timeStyle, calType); + } + if (timePattern == null) { + timePattern = getDateTimePattern(null, "TimePatterns", timeStyle, calType); + } } if (dateStyle >= 0) { - datePattern = getDateTimePattern("DatePatterns", dateStyle, calType); + if (prefix != null) { + datePattern = getDateTimePattern(prefix, "DatePatterns", dateStyle, calType); + } + if (datePattern == null) { + datePattern = getDateTimePattern(null, "DatePatterns", dateStyle, calType); + } } if (timeStyle >= 0) { if (dateStyle >= 0) { - String dateTimePattern = getDateTimePattern("DateTimePatterns", 0, calType); + String dateTimePattern = null; + if (prefix != null) { + dateTimePattern = getDateTimePattern(prefix, "DateTimePatterns", 0, calType); + } + if (dateTimePattern == null) { + dateTimePattern = getDateTimePattern(null, "DateTimePatterns", 0, calType); + } switch (dateTimePattern) { case "{1} {0}": pattern = datePattern + " " + timePattern; @@ -396,27 +434,40 @@ public class LocaleResources { return localeData.getDateFormatData(locale); } - private String getDateTimePattern(String key, int styleIndex, String calendarType) { - String resourceKey = "gregory".equals(calendarType) ? key : calendarType + "." + key; - String cacheKey = DATE_TIME_PATTERN + resourceKey; - String[] patterns = null; + private String getDateTimePattern(String prefix, String key, int styleIndex, String calendarType) { + StringBuilder sb = new StringBuilder(); + if (prefix != null) { + sb.append(prefix); + } + if (!"gregory".equals(calendarType)) { + sb.append(calendarType).append('.'); + } + sb.append(key); + String resourceKey = sb.toString(); + String cacheKey = sb.insert(0, DATE_TIME_PATTERN).toString(); removeEmptyReferences(); ResourceReference data = cache.get(cacheKey); + Object value = NULLOBJECT; - if (data == null || ((patterns = (String[]) data.get()) == null)) { + if (data == null || ((value = data.get()) == null)) { ResourceBundle r = localeData.getDateFormatData(locale); if (r.containsKey(resourceKey)) { - patterns = r.getStringArray(resourceKey); + value = r.getStringArray(resourceKey); } else { assert !resourceKey.equals(key); - patterns = r.getStringArray(key); + if (r.containsKey(key)) { + value = r.getStringArray(key); + } } cache.put(cacheKey, - new ResourceReference(cacheKey, (Object) patterns, referenceQueue)); + new ResourceReference(cacheKey, value, referenceQueue)); } - - return patterns[styleIndex]; + if (value == NULLOBJECT) { + assert prefix != null; + return null; + } + return ((String[])value)[styleIndex]; } private static class ResourceReference extends SoftReference { diff --git a/jdk/src/share/javavm/export/jvm.h b/jdk/src/share/javavm/export/jvm.h index 28885cfb14d..44b0be576d4 100644 --- a/jdk/src/share/javavm/export/jvm.h +++ b/jdk/src/share/javavm/export/jvm.h @@ -465,6 +465,12 @@ JVM_GetClassSignature(JNIEnv *env, jclass cls); JNIEXPORT jbyteArray JNICALL JVM_GetClassAnnotations(JNIEnv *env, jclass cls); +/* Type use annotations support (JDK 1.8) */ + +JNIEXPORT jbyteArray JNICALL +JVM_GetClassTypeAnnotations(JNIEnv *env, jclass cls); + + /* * New (JDK 1.4) reflection implementation */ @@ -815,6 +821,13 @@ JVM_GetMethodIxMaxStack(JNIEnv *env, jclass cb, int index); JNIEXPORT jboolean JNICALL JVM_IsConstructorIx(JNIEnv *env, jclass cb, int index); +/* + * Is the given method generated by the VM. + * The method is identified by method_index. + */ +JNIEXPORT jboolean JNICALL +JVM_IsVMGeneratedMethodIx(JNIEnv *env, jclass cb, int index); + /* * Returns the name of a given method in UTF format. * The result remains valid until JVM_ReleaseUTF is called. @@ -1395,8 +1408,7 @@ typedef struct { * the new bit is also added in the main/baseline. */ unsigned int is_attach_supported : 1; - unsigned int is_kernel_jvm : 1; - unsigned int : 30; + unsigned int : 31; unsigned int : 32; unsigned int : 32; } jvm_version_info; diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp b/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp index bc91827f66c..4b5e38a0de1 100644 --- a/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp +++ b/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp @@ -4758,8 +4758,8 @@ int unpacker::write_bsms(int naOffset, int na) { PTRLIST_QSORT(cp.requested_bsms, outputEntry_cmp); // append the BootstrapMethods attribute (after the InnerClasses attr): putref(cp.sym[cpool::s_BootstrapMethods]); + // make a note of the offset, for lazy patching int sizeOffset = (int)wpoffset(); - byte* sizewp = wp; putu4(-99); // attr size will be patched putu2(cur_class_local_bsm_count); int written_bsms = 0; @@ -4776,6 +4776,7 @@ int unpacker::write_bsms(int naOffset, int na) { written_bsms += 1; } assert(written_bsms == cur_class_local_bsm_count); // else insane + byte* sizewp = wp_at(sizeOffset); putu4_at(sizewp, (int)(wp - (sizewp+4))); // size of code attr putu2_at(wp_at(naOffset), ++na); // increment class attr count } diff --git a/jdk/src/share/native/common/check_code.c b/jdk/src/share/native/common/check_code.c index c5e8855ee68..c761a3d9158 100644 --- a/jdk/src/share/native/common/check_code.c +++ b/jdk/src/share/native/common/check_code.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -983,6 +983,12 @@ verify_method(context_type *context, jclass cb, int method_index, CCerror(context, "Inconsistent access bits."); } + // If this method is an overpass method, which is generated by the VM, + // we trust the code and no check needs to be done. + if (JVM_IsVMGeneratedMethodIx(env, cb, method_index)) { + return; + } + /* Run through the code. Mark the start of each instruction, and give * the instruction a number */ for (i = 0, offset = 0; offset < code_length; i++) { diff --git a/jdk/src/share/native/java/lang/Class.c b/jdk/src/share/native/java/lang/Class.c index 3e595e726af..20d03060101 100644 --- a/jdk/src/share/native/java/lang/Class.c +++ b/jdk/src/share/native/java/lang/Class.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2010, 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 @@ -75,7 +75,8 @@ static JNINativeMethod methods[] = { {"getRawAnnotations", "()" BA, (void *)&JVM_GetClassAnnotations}, {"getConstantPool", "()" CPL, (void *)&JVM_GetClassConstantPool}, {"desiredAssertionStatus0","("CLS")Z",(void *)&JVM_DesiredAssertionStatus}, - {"getEnclosingMethod0", "()[" OBJ, (void *)&JVM_GetEnclosingMethodInfo} + {"getEnclosingMethod0", "()[" OBJ, (void *)&JVM_GetEnclosingMethodInfo}, + {"getRawTypeAnnotations", "()" BA, (void *)&JVM_GetClassTypeAnnotations}, }; #undef OBJ diff --git a/jdk/src/share/native/sun/awt/image/awt_parseImage.c b/jdk/src/share/native/sun/awt/image/awt_parseImage.c index 264a02f1642..d6f6d60d356 100644 --- a/jdk/src/share/native/sun/awt/image/awt_parseImage.c +++ b/jdk/src/share/native/sun/awt/image/awt_parseImage.c @@ -489,6 +489,71 @@ void awt_freeParsedImage(BufImageS_t *imageP, int freeImageP) { } } +static void +awt_getBIColorOrder(int type, int *colorOrder) { + switch(type) { + case java_awt_image_BufferedImage_TYPE_INT_ARGB: + case java_awt_image_BufferedImage_TYPE_INT_ARGB_PRE: +#ifdef _LITTLE_ENDIAN + colorOrder[0] = 2; + colorOrder[1] = 1; + colorOrder[2] = 0; + colorOrder[3] = 3; +#else + colorOrder[0] = 1; + colorOrder[1] = 2; + colorOrder[2] = 3; + colorOrder[3] = 0; +#endif + break; + case java_awt_image_BufferedImage_TYPE_INT_BGR: +#ifdef _LITTLE_ENDIAN + colorOrder[0] = 0; + colorOrder[1] = 1; + colorOrder[2] = 2; +#else + colorOrder[0] = 3; + colorOrder[1] = 2; + colorOrder[2] = 1; +#endif + break; + case java_awt_image_BufferedImage_TYPE_INT_RGB: +#ifdef _LITTLE_ENDIAN + colorOrder[0] = 2; + colorOrder[1] = 1; + colorOrder[2] = 0; +#else + colorOrder[0] = 1; + colorOrder[1] = 2; + colorOrder[2] = 3; +#endif + break; + case java_awt_image_BufferedImage_TYPE_4BYTE_ABGR: + case java_awt_image_BufferedImage_TYPE_4BYTE_ABGR_PRE: + colorOrder[0] = 3; + colorOrder[1] = 2; + colorOrder[2] = 1; + colorOrder[3] = 0; + break; + case java_awt_image_BufferedImage_TYPE_3BYTE_BGR: + colorOrder[0] = 2; + colorOrder[1] = 1; + colorOrder[2] = 0; + break; + case java_awt_image_BufferedImage_TYPE_USHORT_565_RGB: + case java_awt_image_BufferedImage_TYPE_USHORT_555_RGB: + colorOrder[0] = 0; + colorOrder[1] = 1; + colorOrder[2] = 2; + break; + case java_awt_image_BufferedImage_TYPE_BYTE_GRAY: + case java_awt_image_BufferedImage_TYPE_USHORT_GRAY: + case java_awt_image_BufferedImage_TYPE_BYTE_BINARY: + case java_awt_image_BufferedImage_TYPE_BYTE_INDEXED: + colorOrder[0] = 0; + break; + } +} static int setHints(JNIEnv *env, BufImageS_t *imageP) { diff --git a/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c b/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c index 0f39761750a..b405618be98 100644 --- a/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c +++ b/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c @@ -2694,6 +2694,11 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeImage scale[i] = (UINT8*) malloc((maxBandValue + 1) * sizeof(UINT8)); if (scale[i] == NULL) { + // Cleanup before throwing an out of memory exception + for (j = 0; j < i; j++) { + free(scale[j]); + } + free(scale); JNU_ThrowByName( env, "java/lang/OutOfMemoryError", "Writing JPEG Stream"); return JNI_FALSE; diff --git a/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv.h b/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv.h index 82243b91358..24d99cef103 100644 --- a/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv.h +++ b/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv.h @@ -31,6 +31,16 @@ extern "C" { #endif /* __cplusplus */ +// Shared macro defined for cleanup of allocated memory. +#ifndef FREE_AND_RETURN_STATUS +#define FREE_AND_RETURN_STATUS \ +{ \ +if (pbuff != buff) mlib_free(pbuff); \ +if (k != akernel) mlib_free(k); \ +return status; \ +} +#endif /* FREE_AND_RETURN_STATUS */ + void mlib_ImageXor80_aa(mlib_u8 *dl, mlib_s32 wid, mlib_s32 hgt, diff --git a/jdk/src/share/native/sun/awt/medialib/mlib_ImageConvMxN_ext.c b/jdk/src/share/native/sun/awt/medialib/mlib_ImageConvMxN_ext.c index e489f57dafb..88ade07e31c 100644 --- a/jdk/src/share/native/sun/awt/medialib/mlib_ImageConvMxN_ext.c +++ b/jdk/src/share/native/sun/awt/medialib/mlib_ImageConvMxN_ext.c @@ -253,8 +253,10 @@ mlib_status mlib_convMxNext_s32(mlib_image *dst, if (mn > 256) { dkernel = mlib_malloc(mn * sizeof(mlib_d64)); - if (dkernel == NULL) + if (dkernel == NULL) { + if (dsa != dspace) mlib_free(dsa); return MLIB_FAILURE; + } } while (scale > 30) { diff --git a/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_16ext.c b/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_16ext.c index 5ddcbb3e9b4..70f3831bcc2 100644 --- a/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_16ext.c +++ b/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_16ext.c @@ -1884,6 +1884,8 @@ mlib_status CONV_FUNC_MxN mlib_s32 nchannel, chan1, chan2; mlib_s32 i, j, c, swid; d64_2x32 dd; + mlib_status status = MLIB_SUCCESS; + GET_SRC_DST_PARAMETERS(DTYPE); if (scale > 30) { @@ -1905,7 +1907,10 @@ mlib_status CONV_FUNC_MxN k[i] = kernel[i]*fscale; } - if (m == 1) return mlib_ImageConv1xN_ext(dst, src, k, n, dy_t, dy_b, cmask); + if (m == 1) { + status = mlib_ImageConv1xN_ext(dst, src, k, n, dy_t, dy_b, cmask); + FREE_AND_RETURN_STATUS; + } swid = wid + (m - 1); @@ -1914,7 +1919,10 @@ mlib_status CONV_FUNC_MxN if ((bsize > BUFF_SIZE) || (n > MAX_N)) { pbuff = mlib_malloc(sizeof(FTYPE)*bsize + sizeof(FTYPE *)*2*(n + 1)); - if (pbuff == NULL) return MLIB_FAILURE; + if (pbuff == NULL) { + status = MLIB_FAILURE; + FREE_AND_RETURN_STATUS; + } buffs = (FTYPE **)(pbuff + bsize); } @@ -2318,9 +2326,7 @@ mlib_status CONV_FUNC_MxN } } - if (pbuff != buff) mlib_free(pbuff); - - return MLIB_SUCCESS; + FREE_AND_RETURN_STATUS; } /***************************************************************/ diff --git a/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_16nw.c b/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_16nw.c index 8c5ada353bd..7fc3d5e0464 100644 --- a/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_16nw.c +++ b/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_16nw.c @@ -1651,6 +1651,8 @@ mlib_status CONV_FUNC(MxN)(mlib_image *dst, DEF_VARS(DTYPE); mlib_s32 chan2; mlib_s32 *buffo, *buffi; + mlib_status status = MLIB_SUCCESS; + GET_SRC_DST_PARAMETERS(DTYPE); if (scale > 30) { @@ -1672,14 +1674,20 @@ mlib_status CONV_FUNC(MxN)(mlib_image *dst, k[i] = kernel[i]*fscale; } - if (m == 1) return mlib_ImageConv1xN(dst, src, k, n, dn, cmask); + if (m == 1) { + status = mlib_ImageConv1xN(dst, src, k, n, dn, cmask); + FREE_AND_RETURN_STATUS; + } bsize = (n + 3)*wid; if ((bsize > BUFF_SIZE) || (n > MAX_N)) { pbuff = mlib_malloc(sizeof(FTYPE)*bsize + sizeof(FTYPE *)*2*(n + 1)); - if (pbuff == NULL) return MLIB_FAILURE; + if (pbuff == NULL) { + status = MLIB_FAILURE; + FREE_AND_RETURN_STATUS; + } buffs = (FTYPE **)(pbuff + bsize); } @@ -2033,9 +2041,7 @@ mlib_status CONV_FUNC(MxN)(mlib_image *dst, } } - if (pbuff != buff) mlib_free(pbuff); - - return MLIB_SUCCESS; + FREE_AND_RETURN_STATUS; } /***************************************************************/ diff --git a/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_32nw.c b/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_32nw.c index eb7037307ca..9d80dddaf1b 100644 --- a/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_32nw.c +++ b/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_32nw.c @@ -1160,6 +1160,8 @@ mlib_status CONV_FUNC(MxN)(mlib_image *dst, DEF_VARS_MxN(mlib_s32); mlib_s32 chan2 = chan1 + chan1; + mlib_status status = MLIB_SUCCESS; + if (scale > 30) { fscale *= 1.0/(1 << 30); scale -= 30; @@ -1179,14 +1181,20 @@ mlib_status CONV_FUNC(MxN)(mlib_image *dst, k[i] = kernel[i]*fscale; } - if (m == 1) return mlib_ImageConv1xN(dst, src, k, n, dn, cmask); + if (m == 1) { + status = mlib_ImageConv1xN(dst, src, k, n, dn, cmask); + FREE_AND_RETURN_STATUS; + } bsize = (n + 2)*wid; if ((bsize > BUFF_SIZE) || (n > MAX_N)) { pbuff = mlib_malloc(sizeof(mlib_d64)*bsize + sizeof(mlib_d64*)*2*(n + 1)); - if (pbuff == NULL) return MLIB_FAILURE; + if (pbuff == NULL) { + status = MLIB_FAILURE; + FREE_AND_RETURN_STATUS; + } buffs = (mlib_d64**)(pbuff + bsize); } @@ -1531,9 +1539,7 @@ mlib_status CONV_FUNC(MxN)(mlib_image *dst, } } - if (pbuff != buff) mlib_free(pbuff); - - return MLIB_SUCCESS; + FREE_AND_RETURN_STATUS; } /***************************************************************/ diff --git a/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_8ext.c b/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_8ext.c index 3a006ed5f83..1ca321e1237 100644 --- a/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_8ext.c +++ b/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_8ext.c @@ -1884,6 +1884,8 @@ mlib_status CONV_FUNC_MxN mlib_s32 nchannel, chan1, chan2; mlib_s32 i, j, c, swid; d64_2x32 dd; + mlib_status status = MLIB_SUCCESS; + GET_SRC_DST_PARAMETERS(DTYPE); if (scale > 30) { @@ -1905,7 +1907,10 @@ mlib_status CONV_FUNC_MxN k[i] = kernel[i]*fscale; } - if (m == 1) return mlib_ImageConv1xN_ext(dst, src, k, n, dy_t, dy_b, cmask); + if (m == 1) { + status = mlib_ImageConv1xN_ext(dst, src, k, n, dy_t, dy_b, cmask); + FREE_AND_RETURN_STATUS; + } swid = wid + (m - 1); @@ -1914,7 +1919,10 @@ mlib_status CONV_FUNC_MxN if ((bsize > BUFF_SIZE) || (n > MAX_N)) { pbuff = mlib_malloc(sizeof(FTYPE)*bsize + sizeof(FTYPE *)*2*(n + 1)); - if (pbuff == NULL) return MLIB_FAILURE; + if (pbuff == NULL) { + status = MLIB_FAILURE; + FREE_AND_RETURN_STATUS; + } buffs = (FTYPE **)(pbuff + bsize); } @@ -2318,9 +2326,7 @@ mlib_status CONV_FUNC_MxN } } - if (pbuff != buff) mlib_free(pbuff); - - return MLIB_SUCCESS; + FREE_AND_RETURN_STATUS; } /***************************************************************/ diff --git a/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_8nw.c b/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_8nw.c index ce337534c6f..5c4de68db69 100644 --- a/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_8nw.c +++ b/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_8nw.c @@ -1652,6 +1652,8 @@ mlib_status CONV_FUNC(MxN)(mlib_image *dst, DEF_VARS(DTYPE); mlib_s32 chan2; mlib_s32 *buffo, *buffi; + mlib_status status = MLIB_SUCCESS; + GET_SRC_DST_PARAMETERS(DTYPE); if (scale > 30) { @@ -1673,14 +1675,20 @@ mlib_status CONV_FUNC(MxN)(mlib_image *dst, k[i] = kernel[i]*fscale; } - if (m == 1) return mlib_ImageConv1xN(dst, src, k, n, dn, cmask); + if (m == 1) { + status = mlib_ImageConv1xN(dst, src, k, n, dn, cmask); + FREE_AND_RETURN_STATUS; + } bsize = (n + 3)*wid; if ((bsize > BUFF_SIZE) || (n > MAX_N)) { pbuff = mlib_malloc(sizeof(FTYPE)*bsize + sizeof(FTYPE *)*2*(n + 1)); - if (pbuff == NULL) return MLIB_FAILURE; + if (pbuff == NULL) { + status = MLIB_FAILURE; + FREE_AND_RETURN_STATUS; + } buffs = (FTYPE **)(pbuff + bsize); } @@ -2034,9 +2042,7 @@ mlib_status CONV_FUNC(MxN)(mlib_image *dst, } } - if (pbuff != buff) mlib_free(pbuff); - - return MLIB_SUCCESS; + FREE_AND_RETURN_STATUS; } /***************************************************************/ diff --git a/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_u16ext.c b/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_u16ext.c index f412112b168..0369f57b250 100644 --- a/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_u16ext.c +++ b/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_u16ext.c @@ -1884,6 +1884,8 @@ mlib_status CONV_FUNC_MxN mlib_s32 nchannel, chan1, chan2; mlib_s32 i, j, c, swid; d64_2x32 dd; + mlib_status status = MLIB_SUCCESS; + GET_SRC_DST_PARAMETERS(DTYPE); if (scale > 30) { @@ -1905,7 +1907,10 @@ mlib_status CONV_FUNC_MxN k[i] = kernel[i]*fscale; } - if (m == 1) return mlib_ImageConv1xN_ext(dst, src, k, n, dy_t, dy_b, cmask); + if (m == 1) { + status = mlib_ImageConv1xN_ext(dst, src, k, n, dy_t, dy_b, cmask); + FREE_AND_RETURN_STATUS; + } swid = wid + (m - 1); @@ -1914,7 +1919,10 @@ mlib_status CONV_FUNC_MxN if ((bsize > BUFF_SIZE) || (n > MAX_N)) { pbuff = mlib_malloc(sizeof(FTYPE)*bsize + sizeof(FTYPE *)*2*(n + 1)); - if (pbuff == NULL) return MLIB_FAILURE; + if (pbuff == NULL) { + status = MLIB_FAILURE; + FREE_AND_RETURN_STATUS; + } buffs = (FTYPE **)(pbuff + bsize); } @@ -2318,9 +2326,7 @@ mlib_status CONV_FUNC_MxN } } - if (pbuff != buff) mlib_free(pbuff); - - return MLIB_SUCCESS; + FREE_AND_RETURN_STATUS; } /***************************************************************/ diff --git a/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_u16nw.c b/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_u16nw.c index eb68aeff7dd..fe159095545 100644 --- a/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_u16nw.c +++ b/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_u16nw.c @@ -1651,6 +1651,8 @@ mlib_status CONV_FUNC(MxN)(mlib_image *dst, DEF_VARS(DTYPE); mlib_s32 chan2; mlib_s32 *buffo, *buffi; + mlib_status status = MLIB_SUCCESS; + GET_SRC_DST_PARAMETERS(DTYPE); if (scale > 30) { @@ -1672,14 +1674,20 @@ mlib_status CONV_FUNC(MxN)(mlib_image *dst, k[i] = kernel[i]*fscale; } - if (m == 1) return mlib_ImageConv1xN(dst, src, k, n, dn, cmask); + if (m == 1) { + status = mlib_ImageConv1xN(dst, src, k, n, dn, cmask); + FREE_AND_RETURN_STATUS; + } bsize = (n + 3)*wid; if ((bsize > BUFF_SIZE) || (n > MAX_N)) { pbuff = mlib_malloc(sizeof(FTYPE)*bsize + sizeof(FTYPE *)*2*(n + 1)); - if (pbuff == NULL) return MLIB_FAILURE; + if (pbuff == NULL) { + status = MLIB_FAILURE; + FREE_AND_RETURN_STATUS; + } buffs = (FTYPE **)(pbuff + bsize); } @@ -2033,9 +2041,7 @@ mlib_status CONV_FUNC(MxN)(mlib_image *dst, } } - if (pbuff != buff) mlib_free(pbuff); - - return MLIB_SUCCESS; + FREE_AND_RETURN_STATUS; } /***************************************************************/ diff --git a/jdk/src/share/native/sun/awt/medialib/mlib_ImageCreate.c b/jdk/src/share/native/sun/awt/medialib/mlib_ImageCreate.c index fe065b35df3..40662d6b8cc 100644 --- a/jdk/src/share/native/sun/awt/medialib/mlib_ImageCreate.c +++ b/jdk/src/share/native/sun/awt/medialib/mlib_ImageCreate.c @@ -477,9 +477,9 @@ void *mlib_ImageCreateRowTable(mlib_image *img) im_height = mlib_ImageGetHeight(img); im_stride = mlib_ImageGetStride(img); tline = mlib_ImageGetData(img); + if (tline == NULL) return NULL; rtable = mlib_malloc((3 + im_height)*sizeof(mlib_u8 *)); - - if (rtable == NULL || tline == NULL) return NULL; + if (rtable == NULL) return NULL; rtable[0] = 0; rtable[1] = (mlib_u8*)((void **)rtable + 1); diff --git a/jdk/src/share/native/sun/awt/medialib/mlib_c_ImageConv.h b/jdk/src/share/native/sun/awt/medialib/mlib_c_ImageConv.h index 8b94af09ac8..ba1cfa303c2 100644 --- a/jdk/src/share/native/sun/awt/medialib/mlib_c_ImageConv.h +++ b/jdk/src/share/native/sun/awt/medialib/mlib_c_ImageConv.h @@ -31,6 +31,16 @@ extern "C" { #endif /* __cplusplus */ +// Shared macro defined for cleanup of allocated memory. +#ifndef FREE_AND_RETURN_STATUS +#define FREE_AND_RETURN_STATUS \ +{ \ +if (pbuff != buff) mlib_free(pbuff); \ +if (k != akernel) mlib_free(k); \ +return status; \ +} +#endif /* FREE_AND_RETURN_STATUS */ + mlib_status mlib_c_conv2x2ext_s16(mlib_image *dst, const mlib_image *src, mlib_s32 dx_l, diff --git a/jdk/src/solaris/classes/sun/awt/X11/XIconWindow.java b/jdk/src/solaris/classes/sun/awt/X11/XIconWindow.java index 1d0e55d31ef..bf521db3b72 100644 --- a/jdk/src/solaris/classes/sun/awt/X11/XIconWindow.java +++ b/jdk/src/solaris/classes/sun/awt/X11/XIconWindow.java @@ -92,7 +92,7 @@ public class XIconWindow extends XBaseWindow { } XIconSize[] sizeList = getIconSizes(); - log.finest("Icon sizes: {0}", sizeList); + log.finest("Icon sizes: {0}", (Object[]) sizeList); if (sizeList == null) { // No icon sizes so we simply fall back to 16x16 return new Dimension(16, 16); diff --git a/jdk/src/solaris/classes/sun/awt/X11InputMethod.java b/jdk/src/solaris/classes/sun/awt/X11InputMethod.java index b2a62c60ce8..b1939a67d9b 100644 --- a/jdk/src/solaris/classes/sun/awt/X11InputMethod.java +++ b/jdk/src/solaris/classes/sun/awt/X11InputMethod.java @@ -57,6 +57,7 @@ import java.io.File; import java.io.FileReader; import java.io.BufferedReader; import java.io.IOException; +import java.lang.ref.WeakReference; import sun.util.logging.PlatformLogger; import java.util.StringTokenizer; import java.util.regex.Pattern; @@ -104,7 +105,7 @@ public abstract class X11InputMethod extends InputMethodAdapter { //reset the XIC if necessary private boolean needResetXIC = false; - private Component needResetXICClient = null; + private WeakReference needResetXICClient = new WeakReference<>(null); // The use of compositionEnableSupported is to reduce unnecessary // native calls if set/isCompositionEnabled @@ -272,14 +273,14 @@ public abstract class X11InputMethod extends InputMethodAdapter { called on the passive client when endComposition is called. */ if (needResetXIC && haveActiveClient() && - getClientComponent() != needResetXICClient){ + getClientComponent() != needResetXICClient.get()){ resetXIC(); // needs to reset the last xic focussed component. lastXICFocussedComponent = null; isLastXICActive = false; - needResetXICClient = null; + needResetXICClient.clear(); needResetXIC = false; } } @@ -417,7 +418,7 @@ public abstract class X11InputMethod extends InputMethodAdapter { isLastXICActive = false; resetXIC(); - needResetXICClient = null; + needResetXICClient.clear(); needResetXIC = false; } } @@ -478,7 +479,7 @@ public abstract class X11InputMethod extends InputMethodAdapter { disableInputMethod(); if (needResetXIC) { resetXIC(); - needResetXICClient = null; + needResetXICClient.clear(); needResetXIC = false; } } @@ -877,7 +878,7 @@ public abstract class X11InputMethod extends InputMethodAdapter { boolean active = haveActiveClient(); if (active && composedText == null && committedText == null){ needResetXIC = true; - needResetXICClient = getClientComponent(); + needResetXICClient = new WeakReference<>(getClientComponent()); return; } diff --git a/jdk/src/solaris/native/java/net/linux_close.c b/jdk/src/solaris/native/java/net/linux_close.c index 5665e85e09c..51f9cb2ee70 100644 --- a/jdk/src/solaris/native/java/net/linux_close.c +++ b/jdk/src/solaris/native/java/net/linux_close.c @@ -191,17 +191,6 @@ static int closefd(int fd1, int fd2) { pthread_mutex_lock(&(fdEntry->lock)); { - /* - * Send a wakeup signal to all threads blocked on this - * file descriptor. - */ - threadEntry_t *curr = fdEntry->threads; - while (curr != NULL) { - curr->intr = 1; - pthread_kill( curr->thr, sigWakeup ); - curr = curr->next; - } - /* * And close/dup the file descriptor * (restart if interrupted by signal) @@ -214,6 +203,16 @@ static int closefd(int fd1, int fd2) { } } while (rv == -1 && errno == EINTR); + /* + * Send a wakeup signal to all threads blocked on this + * file descriptor. + */ + threadEntry_t *curr = fdEntry->threads; + while (curr != NULL) { + curr->intr = 1; + pthread_kill( curr->thr, sigWakeup ); + curr = curr->next; + } } /* diff --git a/jdk/src/solaris/native/sun/awt/awt_Mlib.c b/jdk/src/solaris/native/sun/awt/awt_Mlib.c index fb00d4d9f12..0b7c291c811 100644 --- a/jdk/src/solaris/native/sun/awt/awt_Mlib.c +++ b/jdk/src/solaris/native/sun/awt/awt_Mlib.c @@ -145,52 +145,6 @@ mlib_stop_timer awt_setMlibStopTimer() { return stop_timer; } -void awt_getBIColorOrder(int type, int *colorOrder) { - switch(type) { - case java_awt_image_BufferedImage_TYPE_INT_ARGB: - case java_awt_image_BufferedImage_TYPE_INT_ARGB_PRE: - colorOrder[0] = 1; - colorOrder[1] = 2; - colorOrder[2] = 3; - colorOrder[3] = 0; - break; - case java_awt_image_BufferedImage_TYPE_INT_BGR: - colorOrder[0] = 2; - colorOrder[1] = 1; - colorOrder[2] = 0; - break; - case java_awt_image_BufferedImage_TYPE_4BYTE_ABGR: - case java_awt_image_BufferedImage_TYPE_4BYTE_ABGR_PRE: - colorOrder[0] = 3; - colorOrder[1] = 2; - colorOrder[2] = 1; - colorOrder[3] = 0; - break; - case java_awt_image_BufferedImage_TYPE_3BYTE_BGR: - colorOrder[0] = 2; - colorOrder[1] = 1; - colorOrder[2] = 0; - break; - case java_awt_image_BufferedImage_TYPE_INT_RGB: - colorOrder[0] = 1; - colorOrder[1] = 2; - colorOrder[2] = 3; - break; - case java_awt_image_BufferedImage_TYPE_USHORT_565_RGB: - case java_awt_image_BufferedImage_TYPE_USHORT_555_RGB: - colorOrder[0] = 0; - colorOrder[1] = 1; - colorOrder[2] = 2; - break; - case java_awt_image_BufferedImage_TYPE_BYTE_GRAY: - case java_awt_image_BufferedImage_TYPE_USHORT_GRAY: - case java_awt_image_BufferedImage_TYPE_BYTE_BINARY: - case java_awt_image_BufferedImage_TYPE_BYTE_INDEXED: - colorOrder[0] = 0; - break; - } -} - /*************************************************************************** * Static Functions * ***************************************************************************/ diff --git a/jdk/src/solaris/native/sun/awt/awt_Mlib.h b/jdk/src/solaris/native/sun/awt/awt_Mlib.h index 03d65868994..cbaf38d1de6 100644 --- a/jdk/src/solaris/native/sun/awt/awt_Mlib.h +++ b/jdk/src/solaris/native/sun/awt/awt_Mlib.h @@ -33,6 +33,5 @@ typedef void (*mlib_stop_timer)(int, int); mlib_status awt_getImagingLib(JNIEnv *, mlibFnS_t *, mlibSysFnS_t *); mlib_start_timer awt_setMlibStartTimer(); mlib_stop_timer awt_setMlibStopTimer(); -void awt_getBIColorOrder(int type, int *colorOrder); #endif /* _AWT_MLIB_H */ diff --git a/jdk/src/solaris/native/sun/java2d/opengl/GLXSurfaceData.c b/jdk/src/solaris/native/sun/java2d/opengl/GLXSurfaceData.c index 16209e72395..a9549e0cd03 100644 --- a/jdk/src/solaris/native/sun/java2d/opengl/GLXSurfaceData.c +++ b/jdk/src/solaris/native/sun/java2d/opengl/GLXSurfaceData.c @@ -57,22 +57,23 @@ Java_sun_java2d_opengl_GLXSurfaceData_initOps(JNIEnv *env, jobject glxsd, jobject peer, jlong aData) { #ifndef HEADLESS - OGLSDOps *oglsdo = (OGLSDOps *)SurfaceData_InitOps(env, glxsd, - sizeof(OGLSDOps)); GLXSDOps *glxsdo = (GLXSDOps *)malloc(sizeof(GLXSDOps)); - J2dTraceLn(J2D_TRACE_INFO, "GLXSurfaceData_initOps"); - - if (oglsdo == NULL) { - JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed."); - return; - } - if (glxsdo == NULL) { JNU_ThrowOutOfMemoryError(env, "creating native GLX ops"); return; } + OGLSDOps *oglsdo = (OGLSDOps *)SurfaceData_InitOps(env, glxsd, + sizeof(OGLSDOps)); + if (oglsdo == NULL) { + free(glxsdo); + JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed."); + return; + } + + J2dTraceLn(J2D_TRACE_INFO, "GLXSurfaceData_initOps"); + oglsdo->privOps = glxsdo; oglsdo->sdOps.Lock = OGLSD_Lock; diff --git a/jdk/src/solaris/native/sun/java2d/x11/X11SurfaceData.c b/jdk/src/solaris/native/sun/java2d/x11/X11SurfaceData.c index 5b8aeb4be20..cee9bb75bfd 100644 --- a/jdk/src/solaris/native/sun/java2d/x11/X11SurfaceData.c +++ b/jdk/src/solaris/native/sun/java2d/x11/X11SurfaceData.c @@ -135,11 +135,11 @@ jboolean XShared_initIDs(JNIEnv *env, jboolean allowShmPixmaps) useMitShmPixmaps = JNI_FALSE; } } - - return JNI_TRUE; #endif /* MITSHM */ #endif /* !HEADLESS */ + + return JNI_TRUE; } @@ -468,8 +468,8 @@ jboolean XShared_initSurface(JNIEnv *env, X11SDOps *xsdo, jint depth, jint width return JNI_FALSE; } - return JNI_TRUE; #endif /* !HEADLESS */ + return JNI_TRUE; } diff --git a/jdk/src/windows/bin/cmdtoargs.c b/jdk/src/windows/bin/cmdtoargs.c index 4e92d18708c..669f3683bfe 100644 --- a/jdk/src/windows/bin/cmdtoargs.c +++ b/jdk/src/windows/bin/cmdtoargs.c @@ -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 @@ -104,6 +104,11 @@ static char* next_arg(char* cmdline, char* arg, jboolean* wildcard) { case ' ': case '\t': + if (prev == '\\') { + for (i = 0 ; i < slashes; i++) { + *dest++ = prev; + } + } if (quotes % 2 == 1) { *dest++ = ch; } else { @@ -591,6 +596,12 @@ int main(int argc, char* argv[]) { // v->disable(); vectors[i++] = v; + v= new Vector(argv[0], "a b\\\\ d"); + v->add("a", FALSE); + v->add("b\\\\", FALSE); + v->add("d", FALSE); + vectors[i++] = v; + dotest(vectors); printf("All tests pass [%d]\n", i); doexit(0); diff --git a/jdk/src/windows/native/sun/windows/awt_Mlib.cpp b/jdk/src/windows/native/sun/windows/awt_Mlib.cpp index 022ebd0419a..308b2823e4c 100644 --- a/jdk/src/windows/native/sun/windows/awt_Mlib.cpp +++ b/jdk/src/windows/native/sun/windows/awt_Mlib.cpp @@ -105,50 +105,4 @@ extern "C" mlib_stop_timer awt_setMlibStopTimer() { return NULL; } - - void awt_getBIColorOrder(int type, int *colorOrder) { - switch(type) { - case java_awt_image_BufferedImage_TYPE_INT_ARGB: - case java_awt_image_BufferedImage_TYPE_INT_ARGB_PRE: - colorOrder[0] = 2; - colorOrder[1] = 1; - colorOrder[2] = 0; - colorOrder[3] = 3; - break; - case java_awt_image_BufferedImage_TYPE_INT_BGR: - colorOrder[0] = 0; - colorOrder[1] = 1; - colorOrder[2] = 2; - break; - case java_awt_image_BufferedImage_TYPE_INT_RGB: - colorOrder[0] = 2; - colorOrder[1] = 1; - colorOrder[2] = 0; - break; - case java_awt_image_BufferedImage_TYPE_4BYTE_ABGR: - case java_awt_image_BufferedImage_TYPE_4BYTE_ABGR_PRE: - colorOrder[0] = 3; - colorOrder[1] = 2; - colorOrder[2] = 1; - colorOrder[3] = 0; - break; - case java_awt_image_BufferedImage_TYPE_3BYTE_BGR: - colorOrder[0] = 2; - colorOrder[1] = 1; - colorOrder[2] = 0; - break; - case java_awt_image_BufferedImage_TYPE_USHORT_565_RGB: - case java_awt_image_BufferedImage_TYPE_USHORT_555_RGB: - colorOrder[0] = 0; - colorOrder[1] = 1; - colorOrder[2] = 2; - break; - case java_awt_image_BufferedImage_TYPE_BYTE_GRAY: - case java_awt_image_BufferedImage_TYPE_USHORT_GRAY: - case java_awt_image_BufferedImage_TYPE_BYTE_BINARY: - case java_awt_image_BufferedImage_TYPE_BYTE_INDEXED: - colorOrder[0] = 0; - break; - } - } } diff --git a/jdk/src/windows/native/sun/windows/awt_Mlib.h b/jdk/src/windows/native/sun/windows/awt_Mlib.h index f9b63d900bb..9ebee32a932 100644 --- a/jdk/src/windows/native/sun/windows/awt_Mlib.h +++ b/jdk/src/windows/native/sun/windows/awt_Mlib.h @@ -38,7 +38,6 @@ JNIEXPORT mlib_status awt_getImagingLib(JNIEnv *env, mlibFnS_t *sMlibFns, mlibSysFnS_t *sMlibSysFns); JNIEXPORT mlib_start_timer awt_setMlibStartTimer(); JNIEXPORT mlib_stop_timer awt_setMlibStopTimer(); -JNIEXPORT void awt_getBIColorOrder(int type, int *colorOrder); #ifdef __cplusplus }; /* end of extern "C" */ diff --git a/jdk/test/Makefile b/jdk/test/Makefile index 408aaaeed25..093d4649b21 100644 --- a/jdk/test/Makefile +++ b/jdk/test/Makefile @@ -342,8 +342,8 @@ prep: clean # Cleanup clean: - $(RM) -r $(ABS_TEST_OUTPUT_DIR) - $(RM) $(ARCHIVE_BUNDLE) + @$(RM) -r $(ABS_TEST_OUTPUT_DIR) + @$(RM) $(ARCHIVE_BUNDLE) ################################################################ @@ -401,7 +401,7 @@ $(EXCLUDELIST): $(PROBLEM_LISTS) $(TEST_DEPENDENCIES) ($(ECHO) "#") ;\ ) | $(SED) -e 's@^[\ ]*@@' \ | $(EGREP) -v '^#' > $@.temp1 - for tdir in $(TESTDIRS) SOLARIS_10_SH_BUG_NO_EMPTY_FORS ; do \ + @for tdir in $(TESTDIRS) SOLARIS_10_SH_BUG_NO_EMPTY_FORS ; do \ ( ( $(CAT) $@.temp1 | $(EGREP) "^$${tdir}" ) ; $(ECHO) "#" ) >> $@.temp2 ; \ done @$(ECHO) "# at least one line" >> $@.temp2 @@ -431,6 +431,7 @@ endef # ------------------------------------------------------------------ # Batches of tests (somewhat arbitrary assigments to jdk_* targets) +# NOTE: These *do not* run the same tests as make/jprt.properties JDK_DEFAULT_TARGETS = JDK_ALL_TARGETS = @@ -614,15 +615,24 @@ jdk_util: $(call TestDirs, java/util sun/util) # ------------------------------------------------------------------ # Run default tests +# note that this *does not* have the same meaning as jprt.properties :: jprt.make.rule.default.test.targets jdk_default: $(JDK_DEFAULT_TARGETS) @$(SummaryInfo) +# Run core tests +# please keep this in sync with jdk/make/jprt.properties :: jprt.make.rule.core.test.targets +jdk_core: jdk_lang jdk_math jdk_util jdk_io jdk_net jdk_nio \ + jdk_security1 jdk_security2 jdk_security3 jdk_rmi \ + jdk_management jdk_jmx jdk_text jdk_tools jdk_jfr jdk_other + @$(SummaryInfo) + # Run all tests +# note that this *does not* have the same meaning as jprt.properties :: jprt.make.rule.all.test.targets jdk_all: $(JDK_ALL_TARGETS) @$(SummaryInfo) # These are all phony targets -PHONY_LIST += $(JDK_ALL_TARGETS) +PHONY_LIST += $(JDK_ALL_TARGETS) jdk_default jdk_core jdk_all # ------------------------------------------------------------------ @@ -892,4 +902,3 @@ PHONY_LIST += jck_all _generic_jck_tests \ .PHONY: all clean prep $(PHONY_LIST) ################################################################ - diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index 5e181ac7e03..840a9274293 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -45,8 +45,8 @@ # as to why they are here and use a label: # generic-all Problems on all platforms # generic-ARCH Where ARCH is one of: sparc, sparcv9, x64, i586, etc. -# OSNAME-all Where OSNAME is one of: solaris, linux, windows -# OSNAME-ARCH Specific on to one OSNAME and ARCH, e.g. solaris-x64 +# OSNAME-all Where OSNAME is one of: solaris, linux, windows, macosx +# OSNAME-ARCH Specific on to one OSNAME and ARCH, e.g. solaris-amd64 # OSNAME-REV Specific on to one OSNAME and REV, e.g. solaris-5.8 # # More than one label is allowed but must be on the same line. @@ -317,16 +317,19 @@ sun/tools/jconsole/ImmutableResourceTest.sh generic-all # 7132203 sun/jvmstat/monitor/MonitoredVm/CR6672135.java generic-all -# Tests take too long, see 7143279 -tools/pack200/CommandLineTests.java generic-all -tools/pack200/Pack200Test.java generic-all - -# 8001163 -tools/pack200/AttributeTests.java generic-all +# Tests take too long, on sparcs see 7143279 +tools/pack200/CommandLineTests.java solaris-all, macosx-all +tools/pack200/Pack200Test.java solaris-all, macosx-all # 7150569 tools/launcher/UnicodeTest.java macosx-all +# 8006039 +tools/launcher/I18NJarTest.java macosx-all + +# 8007410 +tools/launcher/FXLauncherTest.java linux-all + ############################################################################ # jdk_jdi diff --git a/jdk/test/com/sun/jdi/RedefineAbstractClass.sh b/jdk/test/com/sun/jdi/RedefineAbstractClass.sh new file mode 100644 index 00000000000..9e6e484dc04 --- /dev/null +++ b/jdk/test/com/sun/jdi/RedefineAbstractClass.sh @@ -0,0 +1,153 @@ +#!/bin/sh + +# +# Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + + +# @test +# @bug 6805864 +# @summary Redefine an abstract class that is called via a concrete +# class and via two interface objects and verify that the right +# methods are called. +# @author Daniel D. Daugherty +# +# @run shell RedefineAbstractClass.sh + +compileOptions=-g + +# Uncomment this to see the JDI trace +#jdbOptions=-dbgtrace + +createJavaFile() +{ + cat < $1.java.1 + +public class $1 { + public static void main(String[] args) { + System.out.println("This is RedefineAbstractClass"); + + MyConcreteClass foo = new MyConcreteClass(); + // do the work once before redefine + foo.doWork(); + + System.out.println("stop here for redefine"); // @1 breakpoint + + // do the work again after redefine + foo.doWork(); + + System.out.println("stop here to check results"); // @2 breakpoint + } +} + +interface MyInterface1 { + public boolean checkFunc(); + public boolean isMyInterface1(); +} + +interface MyInterface2 { + public boolean checkFunc(); + public boolean isMyInterface2(); +} + +abstract class MyAbstractClass implements MyInterface1, MyInterface2 { + static int counter = 0; + public boolean checkFunc() { + counter++; + System.out.println("MyAbstractClass.checkFunc() called."); + // @1 uncomment System.out.println("This is call " + counter + " to checkFunc"); + return true; + } + public boolean isMyInterface1() { + System.out.println("MyAbstractClass.isMyInterface1() called."); + return true; + } + public boolean isMyInterface2() { + System.out.println("MyAbstractClass.isMyInterface2() called."); + return true; + } +} + +class MyConcreteClass extends MyAbstractClass { + public void doWork() { + // checkFunc() is called via invokevirtual here; MyConcreteClass + // inherits via MyAbstractClass + System.out.println("In doWork() calling checkFunc(): " + checkFunc()); + + MyInterface1 if1 = (MyInterface1) this; + // checkFunc() is called via invokeinterface here; this call will + // use the first itable entry + System.out.println("In doWork() calling if1.checkFunc(): " + if1.checkFunc()); + + MyInterface2 if2 = (MyInterface2) this; + // checkFunc() is called via invokeinterface here; this call will + // use the second itable entry + System.out.println("In doWork() calling if2.checkFunc(): " + if2.checkFunc()); + } +} + +EOF +} + +# This is called to feed cmds to jdb. +dojdbCmds() +{ + setBkpts @1 + setBkpts @2 + runToBkpt @1 + # modified version of redefineClass function + vers=2 + abs_class=MyAbstractClass + cmd redefine $pkgDot$abs_class $tmpFileDir/vers$vers/$abs_class.class + cp $tmpFileDir/$classname.java.$vers \ + $tmpFileDir/$classname.java + # end modified version of redefineClass function + + # this will continue to the second breakpoint + cmd cont +} + + +mysetup() +{ + if [ -z "$TESTSRC" ] ; then + TESTSRC=. + fi + + for ii in . $TESTSRC $TESTSRC/.. ; do + if [ -r "$ii/ShellScaffold.sh" ] ; then + . $ii/ShellScaffold.sh + break + fi + done +} + +# You could replace this next line with the contents +# of ShellScaffold.sh and this script will run just the same. +mysetup + +runit + +debuggeeFailIfNotPresent 'This is call 4 to checkFunc' +debuggeeFailIfNotPresent 'This is call 5 to checkFunc' +debuggeeFailIfNotPresent 'This is call 6 to checkFunc' +pass diff --git a/jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/AbsoluteComponentCenterCalculator.java b/jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/AbsoluteComponentCenterCalculator.java new file mode 100644 index 00000000000..6a9f630dec5 --- /dev/null +++ b/jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/AbsoluteComponentCenterCalculator.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.*; + +class AbsoluteComponentCenterCalculator { + private AbsoluteComponentCenterCalculator() { + } + + public static int calculateXCenterCoordinate(Component component) { + return (int) component.getLocationOnScreen().getX() + (component.getWidth() / 2); + } + + public static int calculateYCenterCoordinate(Component component) { + return (int) component.getLocationOnScreen().getY() + (component.getHeight() / 2); + } +} diff --git a/jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/DataFlavorSearcher.java b/jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/DataFlavorSearcher.java new file mode 100644 index 00000000000..2b46cf643ba --- /dev/null +++ b/jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/DataFlavorSearcher.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.FlavorTable; +import java.awt.datatransfer.SystemFlavorMap; +import java.util.Arrays; + +public class DataFlavorSearcher { + static public String[] HTML_NAMES = new String[]{"HTML", "HTML Format"}; + static public String[] RICH_TEXT_NAMES = new String[]{"RICH_TEXT", "Rich Text Format"}; + + static public DataFlavor getByteDataFlavorForNative(String[] nats) { + FlavorTable flavorTable = (FlavorTable) SystemFlavorMap.getDefaultFlavorMap(); + + for (String nat : nats) { + java.util.List flavors = flavorTable.getFlavorsForNative(nat); + for (DataFlavor flavor : flavors) { + if (flavor != null + && flavor.getRepresentationClass().equals(byte[].class)) { + return flavor; + } + } + } + throw new RuntimeException("No data flavor was found for natives: " + Arrays.toString(nats)); + } +} diff --git a/jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/InterprocessMessages.java b/jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/InterprocessMessages.java new file mode 100644 index 00000000000..d66982d0e31 --- /dev/null +++ b/jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/InterprocessMessages.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +interface InterprocessMessages { + final static int EXECUTION_IS_SUCCESSFULL = 0; + final static int DATA_IS_CORRUPTED = 212; +} + diff --git a/jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/MissedHtmlAndRtfBug.html b/jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/MissedHtmlAndRtfBug.html new file mode 100644 index 00000000000..03f470d2dec --- /dev/null +++ b/jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/MissedHtmlAndRtfBug.html @@ -0,0 +1,27 @@ + +\n\n" + + "Java Platform, Standard Edition - TimeZone information based on "; + private static final String header3 = + "-->\n<TITLE>\n" + + "Java Platform, Standard Edition TimeZone - "; + private static final String header4 = + "\n" + + "\n\n"; + + private static final String body1 = + "\n"; + private static final String body2 = + "\n"; + + private static final String footer = + "\n"; + + + // list of time zone name and zonefile name/real time zone name + // e.g. + // key (String) : value (String) + // "America/Denver" : "America/Denver.html" (real time zone) + // "America/Shiprock" : "America/Denver" (alias) + TreeMap timezoneList = new TreeMap(); + + // list of time zone's display name and time zone name + // e.g. + // key (String) : value (String) + // "Tokyo, Asia" : "Asia/Tokyo" + // "Marengo, Indiana, America" : "America/Indiana/Marengo" + // (aliases included) + TreeMap displayNameList = new TreeMap(); + + // list of top level regions + // e.g. + // key (String) : value (String) + // "America" : "America.html" + // (including entries in America/Indiana/, America/Kentucky/, ...) + TreeMap regionList = new TreeMap(); + + // mapping list from zone name to latitude & longitude + // This list is generated from zone.tab. + // e.g. + // key (String) : value (LatitudeAndLongitude object) + // "Asia/Tokyo" : latitude=35.3916, longitude=13.9444 + // (aliases not included) + HashMap mapList = null; + + // SortedMap of zone IDs sorted by their GMT offsets. If zone's GMT + // offset will change in the future, its last known offset is + // used. + SortedMap> zonesByOffset = new TreeMap>(); + + /** + * Generates HTML document for each zone. + * @param Timezone + * @return 0 if no errors, or 1 if error occurred. + */ + int processZoneinfo(Timezone tz) { + try { + int size; + int index; + String outputDir = Main.getOutputDir(); + String zonename = tz.getName(); + String zonefile = ZoneInfoFile.getFileName(zonename) + ".html"; + List stz = tz.getLastRules(); + timezoneList.put(zonename, zonefile); + displayNameList.put(transform(zonename), zonename); + + // Populate zonesByOffset. (Zones that will change their + // GMT offsets are also added to zonesByOffset here.) + int lastKnownOffset = tz.getRawOffset(); + Set set = zonesByOffset.get(lastKnownOffset); + if (set == null) { + set = new TreeSet(); + zonesByOffset.put(lastKnownOffset, set); + } + set.add(zonename); + + /* If outputDir doesn't end with file-separator, adds it. */ + if (!outputDir.endsWith(File.separator)) { + outputDir += File.separatorChar; + } + outputDir += docDir + File.separatorChar; + + index = zonename.indexOf('/'); + if (index != -1) { + regionList.put(zonename.substring(0, index), + zonename.substring(0, index) + ".html"); + } + + /* If zonefile includes file-separator, it's treated as part of + * pathname. And make directory if necessary. + */ + index = zonefile.lastIndexOf('/'); + if (index != -1) { + zonefile.replace('/', File.separatorChar); + outputDir += zonefile.substring(0, index+1); + } + File outD = new File(outputDir); + outD.mkdirs(); + + /* If mapfile is available, add a link to the appropriate map */ + if ((mapList == null) && (Main.getMapFile() != null)) { + FileReader fr = new FileReader(Main.getMapFile()); + BufferedReader in = new BufferedReader(fr); + mapList = new HashMap(); + String line; + while ((line = in.readLine()) != null) { + // skip blank and comment lines + if (line.length() == 0 || line.charAt(0) == '#') { + continue; + } + StringTokenizer tokens = new StringTokenizer(line); + String token = tokens.nextToken(); /* We don't use the first token. */ + token = tokens.nextToken(); + LatitudeAndLongitude location = new LatitudeAndLongitude(token); + token = tokens.nextToken(); + mapList.put(token, location); + } + in.close(); + } + + /* Open zoneinfo file to write. */ + FileWriter fw = new FileWriter(outputDir + zonefile.substring(index+1)); + BufferedWriter out = new BufferedWriter(fw); + + out.write(header1 + new Date() + header3 + zonename + header4); + out.write(body1 + "" + zonename + ""); + LatitudeAndLongitude location = mapList.get(zonename); + if (location != null) { + int deg, min, sec; + + deg = location.getLatDeg(); + min = location.getLatMin(); + sec = location.getLatSec(); + if (deg < 0) { + min = -min; + sec = -sec; + } else if (min < 0) { + sec = -sec; + } + out.write("   " + + "[map]"); + } + out.write("\n

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

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

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

       

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

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

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

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

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

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

      \n" + + "

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

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

      Directory layout

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

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

      File format

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

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

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

      1. ZoneInfo data file

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

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

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

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

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

      1.1 transition structure

      + *

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

      1.2 offset_table structure

      + *

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

      1.3 simpletimezone structure

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

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

      1.4 raw_offset structure

      + *

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

      1.5 dstsaving structure

      + * Value has dstSaving in seconds. + *

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

      1.6 checksum structure

      + *

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

      1.7 gmtoffsetwillchange structure

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

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

      2. ZoneInfoMappings file

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

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

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

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

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

      2.1 zone_id_table structure

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

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

      2.2 raw_offset_table structure

      + *
      + *

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

      2.3 raw_offset_index_table structure

      + *
      + *

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

      2.4 alias_table structure

      + *
      + *

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

      2.5 versionName structure

      + *
      + *

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

      2.6 excludeList structure

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

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

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

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

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

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

      + * Note: In general, clients should use + * {@link Calendar#ZONE_OFFSET Calendar.get(ZONE_OFFSET)} + + * {@link Calendar#DST_OFFSET Calendar.get(DST_OFFSET)} + * instead of calling this method. + * + * @param era The era of the given date. The value must be either + * GregorianCalendar.AD or GregorianCalendar.BC. + * @param year The year in the given date. + * @param month The month in the given date. Month is 0-based. e.g., + * 0 for January. + * @param day The day-in-month of the given date. + * @param dayOfWeek The day-of-week of the given date. + * @param millis The milliseconds in day in standard local time. + * @return The milliseconds to add to UTC to get local time. + */ + public int getOffset(int era, int year, int month, int day, + int dayOfWeek, int milliseconds) { + if (milliseconds < 0 || milliseconds >= DAY_IN_MILLIS) { + throw new IllegalArgumentException(); + } + + if (era == java.util.GregorianCalendar.BC) { // BC + year = 1 - year; + } else if (era != java.util.GregorianCalendar.AD) { + throw new IllegalArgumentException(); + } + + CalendarDate date = gcal.newCalendarDate(null); + date.setDate(year, month + 1, day); + if (gcal.validate(date) == false) { + throw new IllegalArgumentException(); + } + + // bug-for-bug compatible argument checking + if (dayOfWeek < java.util.GregorianCalendar.SUNDAY + || dayOfWeek > java.util.GregorianCalendar.SATURDAY) { + throw new IllegalArgumentException(); + } + + if (transitions == null) { + return getLastRawOffset(); + } + + long dateInMillis = gcal.getTime(date) + milliseconds; + dateInMillis -= (long) rawOffset; // make it UTC + return getOffsets(dateInMillis, null, UTC_TIME); + } + + /** + * Sets the base time zone offset from GMT. This operation + * modifies all the transitions of this ZoneInfoOld object, including + * historical ones, if applicable. + * + * @param offsetMillis the base time zone offset to GMT. + * @see getRawOffset + */ + public synchronized void setRawOffset(int offsetMillis) { + if (offsetMillis == rawOffset + rawOffsetDiff) { + return; + } + rawOffsetDiff = offsetMillis - rawOffset; + if (lastRule != null) { + lastRule.setRawOffset(offsetMillis); + } + dirty = true; + } + + /** + * Returns the GMT offset of the current date. This GMT offset + * value is not modified during Daylight Saving Time. + * + * @return the GMT offset value in milliseconds to add to UTC time + * to get local standard time + */ + public int getRawOffset() { + if (!willGMTOffsetChange) { + return rawOffset + rawOffsetDiff; + } + + int[] offsets = new int[2]; + getOffsets(System.currentTimeMillis(), offsets, UTC_TIME); + return offsets[0]; + } + + public boolean isDirty() { + return dirty; + } + + int getLastRawOffset() { + return rawOffset + rawOffsetDiff; + } + + /** + * Queries if this time zone uses Daylight Saving Time in the last known rule. + */ + public boolean useDaylightTime() { + return (simpleTimeZoneParams != null); + } + + @Override + public boolean observesDaylightTime() { + if (simpleTimeZoneParams != null) { + return true; + } + if (transitions == null) { + return false; + } + + // Look up the transition table to see if it's in DST right + // now or if there's any standard-to-daylight transition at + // any future. + long utc = System.currentTimeMillis() - rawOffsetDiff; + int index = getTransitionIndex(utc, UTC_TIME); + + // before transitions in the transition table + if (index < 0) { + return false; + } + + // the time is in the table range. + for (int i = index; i < transitions.length; i++) { + if ((transitions[i] & DST_MASK) != 0) { + return true; + } + } + // No further DST is observed. + return false; + } + + /** + * Queries if the specified date is in Daylight Saving Time. + */ + public boolean inDaylightTime(Date date) { + if (date == null) { + throw new NullPointerException(); + } + + if (transitions == null) { + return false; + } + + long utc = date.getTime() - rawOffsetDiff; + int index = getTransitionIndex(utc, UTC_TIME); + + // before transitions in the transition table + if (index < 0) { + return false; + } + + // the time is in the table range. + if (index < transitions.length) { + return (transitions[index] & DST_MASK) != 0; + } + + // beyond the transition table + SimpleTimeZone tz = getLastRule(); + if (tz != null) { + return tz.inDaylightTime(date); + } + return false; + } + + /** + * Returns the amount of time in milliseconds that the clock is advanced + * during daylight saving time is in effect in its last daylight saving time rule. + * + * @return the number of milliseconds the time is advanced with respect to + * standard time when daylight saving time is in effect. + */ + public int getDSTSavings() { + return dstSavings; + } + +// /** +// * @return the last year in the transition table or -1 if this +// * time zone doesn't observe any daylight saving time. +// */ +// public int getMaxTransitionYear() { +// if (transitions == null) { +// return -1; +// } +// long val = transitions[transitions.length - 1]; +// int offset = this.offsets[(int)(val & OFFSET_MASK)] + rawOffsetDiff; +// val = (val >> TRANSITION_NSHIFT) + offset; +// CalendarDate lastDate = Gregorian.getCalendarDate(val); +// return lastDate.getYear(); +// } + + /** + * Returns a string representation of this time zone. + * @return the string + */ + public String toString() { + return getClass().getName() + + "[id=\"" + getID() + "\"" + + ",offset=" + getLastRawOffset() + + ",dstSavings=" + dstSavings + + ",useDaylight=" + useDaylightTime() + + ",transitions=" + ((transitions != null) ? transitions.length : 0) + + ",lastRule=" + (lastRule == null ? getLastRuleInstance() : lastRule) + + "]"; + } + + /** + * Gets all available IDs supported in the Java run-time. + * + * @return an array of time zone IDs. + */ + public static String[] getAvailableIDs() { + List idList = ZoneInfoFile.getZoneIDs(); + List excluded = ZoneInfoFile.getExcludedZones(); + if (excluded != null) { + // List all zones from the idList and excluded lists + List list = new ArrayList<>(idList.size() + excluded.size()); + list.addAll(idList); + list.addAll(excluded); + idList = list; + } + String[] ids = new String[idList.size()]; + return idList.toArray(ids); + } + + /** + * Gets all available IDs that have the same value as the + * specified raw GMT offset. + * + * @param rawOffset the GMT offset in milliseconds. This + * value should not include any daylight saving time. + * + * @return an array of time zone IDs. + */ + public static String[] getAvailableIDs(int rawOffset) { + String[] result; + List matched = new ArrayList<>(); + List IDs = ZoneInfoFile.getZoneIDs(); + int[] rawOffsets = ZoneInfoFile.getRawOffsets(); + + loop: + for (int index = 0; index < rawOffsets.length; index++) { + if (rawOffsets[index] == rawOffset) { + byte[] indices = ZoneInfoFile.getRawOffsetIndices(); + for (int i = 0; i < indices.length; i++) { + if (indices[i] == index) { + matched.add(IDs.get(i++)); + while (i < indices.length && indices[i] == index) { + matched.add(IDs.get(i++)); + } + break loop; + } + } + } + } + + // We need to add any zones from the excluded zone list that + // currently have the same GMT offset as the specified + // rawOffset. The zones returned by this method may not be + // correct as of return to the caller if any GMT offset + // transition is happening during this GMT offset checking... + List excluded = ZoneInfoFile.getExcludedZones(); + if (excluded != null) { + for (String id : excluded) { + TimeZone zi = getTimeZone(id); + if (zi != null && zi.getRawOffset() == rawOffset) { + matched.add(id); + } + } + } + + result = new String[matched.size()]; + matched.toArray(result); + return result; + } + + /** + * Gets the ZoneInfoOld for the given ID. + * + * @param ID the ID for a ZoneInfoOld. See TimeZone for detail. + * + * @return the specified ZoneInfoOld object, or null if there is no + * time zone of the ID. + */ + public static TimeZone getTimeZone(String ID) { + String givenID = null; + + /* + * If old JDK compatibility is specified, get the old alias + * name. + */ + if (USE_OLDMAPPING) { + String compatibleID = TzIDOldMapping.MAP.get(ID); + if (compatibleID != null) { + givenID = ID; + ID = compatibleID; + } + } + + ZoneInfoOld zi = ZoneInfoFile.getZoneInfoOld(ID); + if (zi == null) { + // if we can't create an object for the ID, try aliases. + try { + Map map = getAliasTable(); + String alias = ID; + while ((alias = map.get(alias)) != null) { + zi = ZoneInfoFile.getZoneInfoOld(alias); + if (zi != null) { + zi.setID(ID); + zi = ZoneInfoFile.addToCache(ID, zi); + zi = (ZoneInfoOld) zi.clone(); + break; + } + } + } catch (Exception e) { + // ignore exceptions + } + } + + if (givenID != null && zi != null) { + zi.setID(givenID); + } + return zi; + } + + private transient SimpleTimeZone lastRule; + + /** + * Returns a SimpleTimeZone object representing the last GMT + * offset and DST schedule or null if this time zone doesn't + * observe DST. + */ + synchronized SimpleTimeZone getLastRule() { + if (lastRule == null) { + lastRule = getLastRuleInstance(); + } + return lastRule; + } + + /** + * Returns a SimpleTimeZone object that represents the last + * known daylight saving time rules. + * + * @return a SimpleTimeZone object or null if this time zone + * doesn't observe DST. + */ + public SimpleTimeZone getLastRuleInstance() { + if (simpleTimeZoneParams == null) { + return null; + } + if (simpleTimeZoneParams.length == 10) { + return new SimpleTimeZone(getLastRawOffset(), getID(), + simpleTimeZoneParams[0], + simpleTimeZoneParams[1], + simpleTimeZoneParams[2], + simpleTimeZoneParams[3], + simpleTimeZoneParams[4], + simpleTimeZoneParams[5], + simpleTimeZoneParams[6], + simpleTimeZoneParams[7], + simpleTimeZoneParams[8], + simpleTimeZoneParams[9], + dstSavings); + } + return new SimpleTimeZone(getLastRawOffset(), getID(), + simpleTimeZoneParams[0], + simpleTimeZoneParams[1], + simpleTimeZoneParams[2], + simpleTimeZoneParams[3], + simpleTimeZoneParams[4], + simpleTimeZoneParams[5], + simpleTimeZoneParams[6], + simpleTimeZoneParams[7], + dstSavings); + } + + /** + * Returns a copy of this ZoneInfoOld. + */ + public Object clone() { + ZoneInfoOld zi = (ZoneInfoOld) super.clone(); + zi.lastRule = null; + return zi; + } + + /** + * Returns a hash code value calculated from the GMT offset and + * transitions. + * @return a hash code of this time zone + */ + public int hashCode() { + return getLastRawOffset() ^ checksum; + } + + /** + * Compares the equity of two ZoneInfoOld objects. + * + * @param obj the object to be compared with + * @return true if given object is same as this ZoneInfoOld object, + * false otherwise. + */ + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof ZoneInfoOld)) { + return false; + } + ZoneInfoOld that = (ZoneInfoOld) obj; + return (getID().equals(that.getID()) + && (getLastRawOffset() == that.getLastRawOffset()) + && (checksum == that.checksum)); + } + + /** + * Returns true if this zone has the same raw GMT offset value and + * transition table as another zone info. If the specified + * TimeZone object is not a ZoneInfoOld instance, this method returns + * true if the specified TimeZone object has the same raw GMT + * offset value with no daylight saving time. + * + * @param other the ZoneInfoOld object to be compared with + * @return true if the given TimeZone has the same + * GMT offset and transition information; false, otherwise. + */ + public boolean hasSameRules(TimeZone other) { + if (this == other) { + return true; + } + if (other == null) { + return false; + } + if (!(other instanceof ZoneInfoOld)) { + if (getRawOffset() != other.getRawOffset()) { + return false; + } + // if both have the same raw offset and neither observes + // DST, they have the same rule. + if ((transitions == null) + && (useDaylightTime() == false) + && (other.useDaylightTime() == false)) { + return true; + } + return false; + } + if (getLastRawOffset() != ((ZoneInfoOld)other).getLastRawOffset()) { + return false; + } + return (checksum == ((ZoneInfoOld)other).checksum); + } + + private static SoftReference> aliasTable; + + static Map getCachedAliasTable() { + Map aliases = null; + + SoftReference> cache = aliasTable; + if (cache != null) { + aliases = cache.get(); + } + return aliases; + } + + /** + * Returns a Map from alias time zone IDs to their standard + * time zone IDs. + * + * @return the Map that holds the mappings from alias time zone IDs + * to their standard time zone IDs, or null if + * ZoneInfoOldMappings file is not available. + */ + public synchronized static Map getAliasTable() { + Map aliases = getCachedAliasTable(); + if (aliases == null) { + aliases = ZoneInfoFile.getZoneAliases(); + if (aliases != null) { + if (!USE_OLDMAPPING) { + // Remove the conflicting IDs from the alias table. + for (String key : conflictingIDs) { + aliases.remove(key); + } + } + aliasTable = new SoftReference>(aliases); + } + } + return aliases; + } + + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + stream.defaultReadObject(); + // We don't know how this object from 1.4.x or earlier has + // been mutated. So it should always be marked as `dirty'. + dirty = true; + } + + ////////////////////////////////////////////////////////////// + public boolean equalsTo(ZoneInfoOld other) { + return (getID().equals(other.getID()) + && (getLastRawOffset() == other.getLastRawOffset()) + && (dstSavings == other.dstSavings) + && (willGMTOffsetChange == other.willGMTOffsetChange) + && (checksum == other.checksum) + && equalsTransOffsets(other) + && (Arrays.equals(simpleTimeZoneParams, other.simpleTimeZoneParams) || + getLastRule().equals(other.getLastRule()))); + } + + private boolean equalsTransOffsets(ZoneInfoOld other) { + if (transitions == null) { + return (other.transitions == null && + Arrays.equals(offsets, other.offsets)); + } + if (other.transitions == null || + transitions.length != other.transitions.length) { + return false; + } + // if offsets and other.offsets have different order + // the last 4-bit in trans are different. + for (int i = 0; i < transitions.length; i++) { + long val = transitions[i]; + int dst = (int)((val >>> DST_NSHIFT) & 0xfL); + int save = (dst == 0) ? 0 : offsets[dst] / 1000; + int off = offsets[(int)(val & OFFSET_MASK)]/1000; + long second = (val >> TRANSITION_NSHIFT)/1000; + + val = other.transitions[i]; + int dstO = (int)((val >>> DST_NSHIFT) & 0xfL); + int saveO = (dstO == 0) ? 0 : other.offsets[dstO] / 1000; + int offO = other.offsets[(int)(val & OFFSET_MASK)]/1000; + long secondO = (val >> TRANSITION_NSHIFT)/1000; + if ((dst == 0) != (dstO == 0) || save != saveO || off != offO || second != secondO) + return false; + } + return true; + } + + private int transToString(long val, int off_old, int[] offsets, StringBuilder sb) { + int dst = (int)((val >>> DST_NSHIFT) & 0xfL); + int save = (dst == 0) ? 0 : offsets[dst] / 1000; + int off = offsets[(int)(val & OFFSET_MASK)]/1000; + long second = (val >> TRANSITION_NSHIFT)/1000; + ZoneOffset offset_old = ZoneOffset.ofTotalSeconds(off_old); + ZoneOffset offset = ZoneOffset.ofTotalSeconds(off); + sb.append(" " + LocalDateTime.ofEpochSecond(second, 0, offset_old)); + + sb.append(" [utc=" + second + + " raw=" + Long.toHexString(val >> TRANSITION_NSHIFT) + + ", offset=" + off + "/" + offset + ", saving=" + save + "]"); + return off; + } + + public String diffsTo(ZoneInfoOld other) { + + int rawOffset0 = other.rawOffset; + int checksum0 = other.checksum; + int dstSavings0 = other.dstSavings; + long[] transitions0 = other.transitions; + int[] offsets0 = other.offsets; + int[] simpleTimeZoneParams0 = other.simpleTimeZoneParams; + boolean willGMTOffsetChange0 = other.willGMTOffsetChange; + + + //return getClass().getName() + + StringBuilder sb = new StringBuilder(); + sb.append("******************************\n" + + getID() + " : " + other.getID()); + // ROC is excluded by ZoneInfoOld + if ("ROC".equals(getID())) { + return sb.toString(); + } + if (rawOffset != rawOffset0 || + dstSavings != dstSavings0 || + checksum != checksum0 || + willGMTOffsetChange != willGMTOffsetChange0 || + (simpleTimeZoneParams != null ) != (simpleTimeZoneParams0 != null) || + (transitions != null && transitions0 != null && + transitions.length != transitions0.length)) + { + sb.append("\n offset=" + getLastRawOffset() + + ",dstSavings=" + dstSavings + + ",useDaylight=" + useDaylightTime() + + ",transitions=" + ((transitions != null) ? transitions.length : 0) + + ",offsets=" + ((offsets != null) ? offsets.length : 0) + + ",checksum=" + checksum + + ",gmtChanged=" + willGMTOffsetChange) + .append("\n[NG]offset=" + rawOffset0 + + ",dstSavings=" + dstSavings0 + + ",useDaylight=" + (simpleTimeZoneParams != null) + + ",transitions=" + ((transitions0 != null) ? transitions0.length : 0) + + ",offsets=" + ((offsets0 != null) ? offsets0.length : 0) + + ",checksum=" + checksum0 + + ",gmtChanged=" + willGMTOffsetChange0 + + ""); + } + // offsets + if (!Arrays.equals(offsets, offsets0)) { + sb.append("\n offset.len=" + ((offsets != null)? offsets.length : "null") + + " " + ((offsets0 != null)? offsets0.length : "null")); + if (offsets != null && offsets0.length != 0) { + int len = Math.min(offsets.length, offsets0.length); + int i = 0; + for (i = 0; i < len; i++) { + sb.append("\n " + + ZoneOffset.ofTotalSeconds(offsets[i]/1000) + " " + + ZoneOffset.ofTotalSeconds(offsets0[i]/1000)); + } + for (; i < offsets0.length; i++) { + sb.append("\n " + ZoneOffset.ofTotalSeconds(offsets0[i]/1000)); + } + } + } + // trans + int offset = 0; + int offset0 = 0; + if (!equalsTransOffsets(other)) { + sb.append("\n -------------"); + if ((transitions == null) != (transitions0 == null)) { + sb.append("\n (NG) Different trans(null) :" + + transitions + ", " + transitions0); + if (transitions != null) { + for (int i = 0; i < transitions.length; i++) { + sb.append("\n (NG)"); + offset = transToString(transitions[i], offset, offsets, sb); + } + } + } else { + if (transitions.length != transitions0.length) { + sb.append("\n (NG) Different trans size :" + + transitions.length + ", " + transitions0.length); + } + int length = Math.min(transitions.length, transitions0.length); + for (int i = 0; i < length; i++) { + // sb.append("\n[" + i + "] "); + // offset = transToString(transitions[i], offset, offsets, sb); + long val = transitions[i]; + int dst = (int)((val >>> DST_NSHIFT) & 0xfL); + int save = (dst == 0) ? 0 : offsets[dst] / 1000; + int off = offsets[(int)(val & OFFSET_MASK)]/1000; + long second = (val >> TRANSITION_NSHIFT)/1000; + sb.append("\n "); + offset = transToString(transitions[i], offset, offsets, sb); + if (transitions0 == null || i >= transitions0.length) { + sb.append("\n "); + offset = transToString(transitions[i], offset, offsets, sb); + sb.append("\n (NG) trans0 is null or < trans.length"); + } else { + long val0 = transitions0[i]; + int dst0 = (int)((val0 >>> DST_NSHIFT) & 0xfL); + int save0 = (dst0 == 0) ? 0 : offsets0[dst0] / 1000; + int off0 = offsets0[(int)(val0 & OFFSET_MASK)]/1000; + long second0 = (val0 >> TRANSITION_NSHIFT)/1000; + if (save != save0 || off != off0 || second != second0) { + sb.append("\n (NG)"); + } else { + sb.append("\n (OK)"); + } + offset0 = transToString(transitions0[i], offset0, offsets0, sb); + sb.append("\n -----"); + } + } + } + } + SimpleTimeZone stz = getLastRuleInstance(); + if (stz != null) { + SimpleTimeZone stz0 = other.getLastRule(); + if (!stz.hasSameRules(stz0)) { + sb.append("\n -------------") + .append("\n SimpleTimeZone (NG)") + .append("\n stz=" + stz) + .append("\n stz0=" + stz0); + } + } + sb.append("\n -------------"); + return sb.toString(); + } +} diff --git a/jdk/test/sun/util/calendar/zi/ZoneRec.java b/jdk/test/sun/util/calendar/zi/ZoneRec.java new file mode 100644 index 00000000000..e96346f4e2a --- /dev/null +++ b/jdk/test/sun/util/calendar/zi/ZoneRec.java @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; + +/** + * ZoneRec hold information of time zone corresponding to each text + * line of the "Zone" part. + * + * @since 1.4 + */ +class ZoneRec { + private int gmtOffset; + private String ruleName; + private int directSave; + private Rule ruleRef; + private String format; + private boolean hasUntil; + private int untilYear; + private Month untilMonth; + private RuleDay untilDay; + private Time untilTime; + private long untilInMillis; + private String line; + + /** + * @return the "UNTIL" value in milliseconds + */ + Time getUntilTime() { + return untilTime; + } + + /** + * @return the GMT offset value in milliseconds + */ + int getGmtOffset() { + return gmtOffset; + } + + /** + * @return the rule name to which this zone record refers + */ + String getRuleName() { + return ruleName; + } + + /** + * @return the amount of saving time directly defined in the + * "RULES/SAVE" field. + */ + int getDirectSave() { + return directSave; + } + + /** + * @return true if this zone record has a reference to a rule + */ + boolean hasRuleReference() { + return ruleRef != null; + } + + /** + * Returns the "FORMAT" field string of this zone record. This + * @return the "FORMAT" field + */ + String getFormat() { + return format; + } + + /** + * @return the year in the "UNTIL" field + */ + int getUntilYear() { + return untilYear; + } + + /** + * Returns the "UNTIL" field value in milliseconds from Janurary + * 1, 1970 0:00 GMT. + * @param currentSave the amount of daylight saving in + * milliseconds that is used to adjust wall-clock time. + * @return the milliseconds value of the "UNTIL" field + */ + long getUntilTime(int currentSave) { + if (untilTime.isWall()) { + return untilInMillis - currentSave; + } + return untilInMillis; + } + + /** + * Returns the "UNTIL" time in milliseconds without adjusting GMT + * offsets or daylight saving. + * @return local "UNTIL" time in milliseconds + */ + long getLocalUntilTime() { + return Time.getLocalTime(untilYear, + untilMonth, + untilDay, + untilTime.getTime()); + } + + /** + * Returns the "UNTIL" time in milliseconds with adjusting GMT offsets and daylight saving. + * @return the "UNTIL" time after the adjustment + */ + long getLocalUntilTime(int save, int gmtOffset) { + return Time.getLocalTime(untilYear, + untilMonth, + untilDay, + save, + gmtOffset, + untilTime); + } + + /** + * @return the text line of this zone record + */ + String getLine() { + return line; + } + + /** + * Sets the specified text line to this zone record + */ + void setLine(String line) { + this.line = line; + } + + /** + * @return true if this zone record has the "UNTIL" field + */ + boolean hasUntil() { + return this.hasUntil; + } + + /** + * Adjusts the "UNTIL" time to GMT offset if this zone record has + * it. untilTime is not adjusted to daylight saving + * in this method. + */ + void adjustTime() { + if (!hasUntil()) { + return; + } + if (untilTime.isSTD() || untilTime.isWall()) { + // adjust to gmt offset only here. adjust to real + // wall-clock time when tracking rules + untilInMillis -= gmtOffset; + } + } + + /** + * @return the reference to the Rule object + */ + Rule getRuleRef() { + return ruleRef; + } + + /** + * Resolves the reference to a Rule and adjusts its "UNTIL" time + * to GMT offset. + */ + void resolve(Zoneinfo zi) { + if (ruleName != null && (!"-".equals(ruleName))) { + ruleRef = zi.getRule(ruleName); + } + adjustTime(); + } + + /** + * Parses a Zone text line that is described by a StringTokenizer. + * @param tokens represents tokens of a Zone text line + * @return the zone record produced by parsing the text + */ + static ZoneRec parse(StringTokenizer tokens) { + ZoneRec rec = new ZoneRec(); + try { + rec.gmtOffset = (int) Time.parse(tokens.nextToken()).getTime(); + String token = tokens.nextToken(); + char c = token.charAt(0); + if (c >= '0' && c <= '9') { + rec.directSave = (int) Time.parse(token).getTime(); + } else { + rec.ruleName = token; + } + rec.format = tokens.nextToken(); + if (tokens.hasMoreTokens()) { + rec.hasUntil = true; + rec.untilYear = Integer.parseInt(tokens.nextToken()); + if (tokens.hasMoreTokens()) { + rec.untilMonth = Month.parse(tokens.nextToken()); + } else { + rec.untilMonth = Month.JANUARY; + } + if (tokens.hasMoreTokens()) { + rec.untilDay = RuleDay.parse(tokens.nextToken()); + } else { + rec.untilDay = new RuleDay(1); + } + if (tokens.hasMoreTokens()) { + rec.untilTime = Time.parse(tokens.nextToken()); + } else { + rec.untilTime = Time.parse("0:00"); + } + rec.untilInMillis = rec.getLocalUntilTime(); + } + } catch (Exception e) { + // TODO: error reporting + e.printStackTrace(); + } + return rec; + } + + private static void panic(String msg) { + Main.panic(msg); + } +} diff --git a/jdk/test/sun/util/calendar/zi/Zoneinfo.java b/jdk/test/sun/util/calendar/zi/Zoneinfo.java new file mode 100644 index 00000000000..93242eb4013 --- /dev/null +++ b/jdk/test/sun/util/calendar/zi/Zoneinfo.java @@ -0,0 +1,567 @@ +/* + * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +/** + * Zoneinfo provides javazic compiler front-end functionality. + * @since 1.4 + */ +class Zoneinfo { + + private static final int minYear = 1900; + private static final int maxYear = 2037; + private static final long minTime = Time.getLocalTime(minYear, Month.JANUARY, 1, 0); + private static int startYear = minYear; + private static int endYear = maxYear; + + /** + * True if javazic should generate a list of SimpleTimeZone + * instances for the SimpleTimeZone-based time zone support. + */ + static boolean isYearForTimeZoneDataSpecified = false; + + /** + * Zone name to Zone mappings + */ + private Map zones; + + /** + * Rule name to Rule mappings + */ + private Map rules; + + /** + * Alias name to real name mappings + */ + private Map aliases; + + /** + * Constracts a Zoneinfo. + */ + Zoneinfo() { + zones = new HashMap(); + rules = new HashMap(); + aliases = new HashMap(); + } + + /** + * Adds the given zone to the list of Zones. + * @param zone Zone to be added to the list. + */ + void add(Zone zone) { + String name = zone.getName(); + zones.put(name, zone); + } + + /** + * Adds the given rule to the list of Rules. + * @param rule Rule to be added to the list. + */ + void add(Rule rule) { + String name = rule.getName(); + rules.put(name, rule); + } + + /** + * Puts the specifid name pair to the alias table. + * @param name1 an alias time zone name + * @param name2 the real time zone of the alias name + */ + void putAlias(String name1, String name2) { + aliases.put(name1, name2); + } + + /** + * Sets the given year for SimpleTimeZone list output. + * This method is called when the -S option is specified. + * @param year the year for which SimpleTimeZone list should be generated + */ + static void setYear(int year) { + setStartYear(year); + setEndYear(year); + isYearForTimeZoneDataSpecified = true; + } + + /** + * Sets the start year. + * @param year the start year value + * @throws IllegalArgumentException if the specified year value is + * smaller than the minimum year or greater than the end year. + */ + static void setStartYear(int year) { + if (year < minYear || year > endYear) { + throw new IllegalArgumentException("invalid start year specified: " + year); + } + startYear = year; + } + + /** + * @return the start year value + */ + static int getStartYear() { + return startYear; + } + + /** + * Sets the end year. + * @param year the end year value + * @throws IllegalArgumentException if the specified year value is + * smaller than the start year or greater than the maximum year. + */ + static void setEndYear(int year) { + if (year < startYear || year > maxYear) { + throw new IllegalArgumentException(); + } + endYear = year; + } + + /** + * @return the end year value + */ + static int getEndYear() { + return endYear; + } + + /** + * @return the minimum year value + */ + static int getMinYear() { + return minYear; + } + + /** + * @return the maximum year value + */ + static int getMaxYear() { + return maxYear; + } + + /** + * @return the alias table + */ + Map getAliases() { + return aliases; + } + + /** + * @return the Zone list + */ + Map getZones() { + return zones; + } + + /** + * @return a Zone specified by name. + * @param name a zone name + */ + Zone getZone(String name) { + return zones.get(name); + } + + /** + * @return a Rule specified by name. + * @param name a rule name + */ + Rule getRule(String name) { + return rules.get(name); + } + + private static String line; + + private static int lineNum; + + /** + * Parses the specified time zone data file and creates a Zoneinfo + * that has all Rules, Zones and Links (aliases) information. + * @param fname the time zone data file name + * @return a Zoneinfo object + */ + static Zoneinfo parse(String fname) { + BufferedReader in = null; + try { + FileReader fr = new FileReader(fname); + in = new BufferedReader(fr); + } catch (FileNotFoundException e) { + panic("can't open file: "+fname); + } + Zoneinfo zi = new Zoneinfo(); + boolean continued = false; + Zone zone = null; + String l; + lineNum = 0; + + try { + while ((line = in.readLine()) != null) { + lineNum++; + // skip blank and comment lines + if (line.length() == 0 || line.charAt(0) == '#') { + continue; + } + + // trim trailing comments + int rindex = line.lastIndexOf('#'); + if (rindex != -1) { + // take the data part of the line + l = line.substring(0, rindex); + } else { + l = line; + } + + StringTokenizer tokens = new StringTokenizer(l); + if (!tokens.hasMoreTokens()) { + continue; + } + String token = tokens.nextToken(); + + if (continued || "Zone".equals(token)) { + if (zone == null) { + if (!tokens.hasMoreTokens()) { + panic("syntax error: zone no more token"); + } + token = tokens.nextToken(); + // if the zone name is in "GMT+hh" or "GMT-hh" + // format, ignore it due to spec conflict. + if (token.startsWith("GMT+") || token.startsWith("GMT-")) { + continue; + } + zone = new Zone(token); + } else { + // no way to push the current token back... + tokens = new StringTokenizer(l); + } + + ZoneRec zrec = ZoneRec.parse(tokens); + zrec.setLine(line); + zone.add(zrec); + if ((continued = zrec.hasUntil()) == false) { + if (Zone.isTargetZone(zone.getName())) { + // zone.resolve(zi); + zi.add(zone); + } + zone = null; + } + } else if ("Rule".equals(token)) { + if (!tokens.hasMoreTokens()) { + panic("syntax error: rule no more token"); + } + token = tokens.nextToken(); + Rule rule = zi.getRule(token); + if (rule == null) { + rule = new Rule(token); + zi.add(rule); + } + RuleRec rrec = RuleRec.parse(tokens); + rrec.setLine(line); + rule.add(rrec); + } else if ("Link".equals(token)) { + // Link + try { + String name1 = tokens.nextToken(); + String name2 = tokens.nextToken(); + + // if the zone name is in "GMT+hh" or "GMT-hh" + // format, ignore it due to spec conflict with + // custom time zones. Also, ignore "ROC" for + // PC-ness. + if (name2.startsWith("GMT+") || name2.startsWith("GMT-") + || "ROC".equals(name2)) { + continue; + } + zi.putAlias(name2, name1); + } catch (Exception e) { + panic("syntax error: no more token for Link"); + } + } + } + in.close(); + } catch (IOException ex) { + panic("IO error: " + ex.getMessage()); + } + + return zi; + } + + /** + * Interprets a zone and constructs a Timezone object that + * contains enough information on GMT offsets and DST schedules to + * generate a zone info database. + * + * @param zoneName the zone name for which a Timezone object is + * constructed. + * + * @return a Timezone object that contains all GMT offsets and DST + * rules information. + */ + Timezone phase2(String zoneName) { + Timezone tz = new Timezone(zoneName); + Zone zone = getZone(zoneName); + zone.resolve(this); + + // TODO: merge phase2's for the regular and SimpleTimeZone ones. + if (isYearForTimeZoneDataSpecified) { + ZoneRec zrec = zone.get(zone.size()-1); + tz.setLastZoneRec(zrec); + tz.setRawOffset(zrec.getGmtOffset()); + if (zrec.hasRuleReference()) { + /* + * This part assumes that the specified year is covered by + * the rules referred to by the last zone record. + */ + List rrecs = zrec.getRuleRef().getRules(startYear); + + if (rrecs.size() == 2) { + // make sure that one is a start rule and the other is + // an end rule. + RuleRec r0 = rrecs.get(0); + RuleRec r1 = rrecs.get(1); + if (r0.getSave() == 0 && r1.getSave() > 0) { + rrecs.set(0, r1); + rrecs.set(1, r0); + } else if (!(r0.getSave() > 0 && r1.getSave() == 0)) { + rrecs = null; + Main.error(zoneName + ": rules for " + startYear + " not found."); + } + } else { + rrecs = null; + } + if (rrecs != null) { + tz.setLastRules(rrecs); + } + } + return tz; + } + + int gmtOffset; + int year = minYear; + int fromYear = year; + long fromTime = Time.getLocalTime(startYear, + Month.JANUARY, + 1, 0); + + // take the index 0 for the GMT offset of the last zone record + ZoneRec zrec = zone.get(zone.size()-1); + tz.getOffsetIndex(zrec.getGmtOffset()); + + int currentSave = 0; + boolean usedZone; + for (int zindex = 0; zindex < zone.size(); zindex++) { + zrec = zone.get(zindex); + usedZone = false; + gmtOffset = zrec.getGmtOffset(); + int stdOffset = zrec.getDirectSave(); + + // If this is the last zone record, take the last rule info. + if (!zrec.hasUntil()) { + tz.setRawOffset(gmtOffset, fromTime); + if (zrec.hasRuleReference()) { + tz.setLastRules(zrec.getRuleRef().getLastRules()); + } else if (stdOffset != 0) { + // in case the last rule is all year round DST-only + // (Asia/Amman once announced this rule.) + tz.setLastDSTSaving(stdOffset); + } + } + if (!zrec.hasRuleReference()) { + if (!zrec.hasUntil() || zrec.getUntilTime(stdOffset) >= fromTime) { + tz.addTransition(fromTime, + tz.getOffsetIndex(gmtOffset+stdOffset), + tz.getDstOffsetIndex(stdOffset)); + usedZone = true; + } + currentSave = stdOffset; + // optimization in case the last rule is fixed. + if (!zrec.hasUntil()) { + if (tz.getNTransitions() > 0) { + if (stdOffset == 0) { + tz.setDSTType(Timezone.X_DST); + } else { + tz.setDSTType(Timezone.LAST_DST); + } + long time = Time.getLocalTime(maxYear, + Month.JANUARY, 1, 0); + time -= zrec.getGmtOffset(); + tz.addTransition(time, + tz.getOffsetIndex(gmtOffset+stdOffset), + tz.getDstOffsetIndex(stdOffset)); + tz.addUsedRec(zrec); + } else { + tz.setDSTType(Timezone.NO_DST); + } + break; + } + } else { + Rule rule = zrec.getRuleRef(); + boolean fromTimeUsed = false; + currentSave = 0; + year_loop: + for (year = getMinYear(); year <= endYear; year++) { + if (zrec.hasUntil() && year > zrec.getUntilYear()) { + break; + } + List rules = rule.getRules(year); + if (rules.size() > 0) { + for (int i = 0; i < rules.size(); i++) { + RuleRec rrec = rules.get(i); + long transition = rrec.getTransitionTime(year, + gmtOffset, + currentSave); + if (zrec.hasUntil()) { + if (transition >= zrec.getUntilTime(currentSave)) { + break year_loop; + } + } + + if (fromTimeUsed == false) { + if (fromTime <= transition) { + fromTimeUsed = true; + + if (fromTime != minTime) { + int prevsave; + + ZoneRec prevzrec = zone.get(zindex - 1); + + // See if until time in the previous + // ZoneRec is the same thing as the + // local time in the next rule. + // (examples are Asia/Ashkhabad in 1991, + // Europe/Riga in 1989) + + if (i > 0) { + prevsave = rules.get(i-1).getSave(); + } else { + List prevrules = rule.getRules(year-1); + + if (prevrules.size() > 0) { + prevsave = prevrules.get(prevrules.size()-1).getSave(); + } else { + prevsave = 0; + } + } + + if (rrec.isSameTransition(prevzrec, prevsave, gmtOffset)) { + currentSave = rrec.getSave(); + tz.addTransition(fromTime, + tz.getOffsetIndex(gmtOffset+currentSave), + tz.getDstOffsetIndex(currentSave)); + tz.addUsedRec(rrec); + usedZone = true; + continue; + } + if (!prevzrec.hasRuleReference() + || rule != prevzrec.getRuleRef() + || (rule == prevzrec.getRuleRef() + && gmtOffset != prevzrec.getGmtOffset())) { + int save = (fromTime == transition) ? rrec.getSave() : currentSave; + tz.addTransition(fromTime, + tz.getOffsetIndex(gmtOffset+save), + tz.getDstOffsetIndex(save)); + tz.addUsedRec(rrec); + usedZone = true; + } + } else { // fromTime == minTime + int save = rrec.getSave(); + tz.addTransition(minTime, + tz.getOffsetIndex(gmtOffset), + tz.getDstOffsetIndex(0)); + + tz.addTransition(transition, + tz.getOffsetIndex(gmtOffset+save), + tz.getDstOffsetIndex(save)); + + tz.addUsedRec(rrec); + usedZone = true; + } + } else if (year == fromYear && i == rules.size()-1) { + int save = rrec.getSave(); + tz.addTransition(fromTime, + tz.getOffsetIndex(gmtOffset+save), + tz.getDstOffsetIndex(save)); + } + } + + currentSave = rrec.getSave(); + if (fromTime < transition) { + tz.addTransition(transition, + tz.getOffsetIndex(gmtOffset+currentSave), + tz.getDstOffsetIndex(currentSave)); + tz.addUsedRec(rrec); + usedZone = true; + } + } + } else { + if (year == fromYear) { + tz.addTransition(fromTime, + tz.getOffsetIndex(gmtOffset+currentSave), + tz.getDstOffsetIndex(currentSave)); + fromTimeUsed = true; + } + if (year == endYear && !zrec.hasUntil()) { + if (tz.getNTransitions() > 0) { + // Assume that this Zone stopped DST + tz.setDSTType(Timezone.X_DST); + long time = Time.getLocalTime(maxYear, Month.JANUARY, + 1, 0); + time -= zrec.getGmtOffset(); + tz.addTransition(time, + tz.getOffsetIndex(gmtOffset), + tz.getDstOffsetIndex(0)); + usedZone = true; + } else { + tz.setDSTType(Timezone.NO_DST); + } + } + } + } + } + if (usedZone) { + tz.addUsedRec(zrec); + } + if (zrec.hasUntil() && zrec.getUntilTime(currentSave) > fromTime) { + fromTime = zrec.getUntilTime(currentSave); + fromYear = zrec.getUntilYear(); + year = zrec.getUntilYear(); + } + } + + if (tz.getDSTType() == Timezone.UNDEF_DST) { + tz.setDSTType(Timezone.DST); + } + tz.optimize(); + tz.checksum(); + return tz; + } + + private static void panic(String msg) { + Main.panic(msg); + } +} diff --git a/hotspot/make/solaris/makefiles/kernel.make b/jdk/test/sun/util/calendar/zi/tzdata/VERSION similarity index 74% rename from hotspot/make/solaris/makefiles/kernel.make rename to jdk/test/sun/util/calendar/zi/tzdata/VERSION index 40728e669f1..85db871ccf3 100644 --- a/hotspot/make/solaris/makefiles/kernel.make +++ b/jdk/test/sun/util/calendar/zi/tzdata/VERSION @@ -1,11 +1,12 @@ # -# Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# +# # This code is free software; you can redistribute 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 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License @@ -15,18 +16,9 @@ # You should have received a copy of the GNU General Public License version # 2 along with this work; if not, write to the Free Software Foundation, # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# +# # Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA # or visit www.oracle.com if you need additional information or have any # questions. -# # -# -# Sets make macros for making kernel version of VM. -# This target on solaris is just tempoarily for debugging the kernel build. - -TYPE=KERNEL - -VM_SUBDIR = client - -CFLAGS += -DKERNEL +tzdata2012i diff --git a/jdk/test/sun/util/calendar/zi/tzdata/africa b/jdk/test/sun/util/calendar/zi/tzdata/africa new file mode 100644 index 00000000000..7db9b3d269d --- /dev/null +++ b/jdk/test/sun/util/calendar/zi/tzdata/africa @@ -0,0 +1,1186 @@ +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +#

      +# This file is in the public domain, so clarified as of
      +# 2009-05-17 by Arthur David Olson.
      +
      +# This data is by no means authoritative; if you think you know better,
      +# go ahead and edit the file (and please send any changes to
      +# tz@elsie.nci.nih.gov for general use in the future).
      +
      +# From Paul Eggert (2006-03-22):
      +#
      +# A good source for time zone historical data outside the U.S. is
      +# Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition),
      +# San Diego: ACS Publications, Inc. (2003).
      +#
      +# Gwillim Law writes that a good source
      +# for recent time zone data is the International Air Transport
      +# Association's Standard Schedules Information Manual (IATA SSIM),
      +# published semiannually.  Law sent in several helpful summaries
      +# of the IATA's data after 1990.
      +#
      +# Except where otherwise noted, Shanks & Pottenger is the source for
      +# entries through 1990, and IATA SSIM is the source for entries afterwards.
      +#
      +# Another source occasionally used is Edward W. Whitman, World Time Differences,
      +# Whitman Publishing Co, 2 Niagara Av, Ealing, London (undated), which
      +# I found in the UCLA library.
      +#
      +# A reliable and entertaining source about time zones is
      +# Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
      +#
      +# Previous editions of this database used WAT, CAT, SAT, and EAT
      +# for +0:00 through +3:00, respectively,
      +# but Mark R V Murray reports that
      +# `SAST' is the official abbreviation for +2:00 in the country of South Africa,
      +# `CAT' is commonly used for +2:00 in countries north of South Africa, and
      +# `WAT' is probably the best name for +1:00, as the common phrase for
      +# the area that includes Nigeria is ``West Africa''.
      +# He has heard of ``Western Sahara Time'' for +0:00 but can find no reference.
      +#
      +# To make things confusing, `WAT' seems to have been used for -1:00 long ago;
      +# I'd guess that this was because people needed _some_ name for -1:00,
      +# and at the time, far west Africa was the only major land area in -1:00.
      +# This usage is now obsolete, as the last use of -1:00 on the African
      +# mainland seems to have been 1976 in Western Sahara.
      +#
      +# To summarize, the following abbreviations seem to have some currency:
      +#	-1:00	WAT	West Africa Time (no longer used)
      +#	 0:00	GMT	Greenwich Mean Time
      +#	 2:00	CAT	Central Africa Time
      +#	 2:00	SAST	South Africa Standard Time
      +# and Murray suggests the following abbreviation:
      +#	 1:00	WAT	West Africa Time
      +# I realize that this leads to `WAT' being used for both -1:00 and 1:00
      +# for times before 1976, but this is the best I can think of
      +# until we get more information.
      +#
      +# I invented the following abbreviations; corrections are welcome!
      +#	 2:00	WAST	West Africa Summer Time
      +#	 2:30	BEAT	British East Africa Time (no longer used)
      +#	 2:45	BEAUT	British East Africa Unified Time (no longer used)
      +#	 3:00	CAST	Central Africa Summer Time (no longer used)
      +#	 3:00	SAST	South Africa Summer Time (no longer used)
      +#	 3:00	EAT	East Africa Time
      +#	 4:00	EAST	East Africa Summer Time (no longer used)
      +
      +# Algeria
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Algeria	1916	only	-	Jun	14	23:00s	1:00	S
      +Rule	Algeria	1916	1919	-	Oct	Sun>=1	23:00s	0	-
      +Rule	Algeria	1917	only	-	Mar	24	23:00s	1:00	S
      +Rule	Algeria	1918	only	-	Mar	 9	23:00s	1:00	S
      +Rule	Algeria	1919	only	-	Mar	 1	23:00s	1:00	S
      +Rule	Algeria	1920	only	-	Feb	14	23:00s	1:00	S
      +Rule	Algeria	1920	only	-	Oct	23	23:00s	0	-
      +Rule	Algeria	1921	only	-	Mar	14	23:00s	1:00	S
      +Rule	Algeria	1921	only	-	Jun	21	23:00s	0	-
      +Rule	Algeria	1939	only	-	Sep	11	23:00s	1:00	S
      +Rule	Algeria	1939	only	-	Nov	19	 1:00	0	-
      +Rule	Algeria	1944	1945	-	Apr	Mon>=1	 2:00	1:00	S
      +Rule	Algeria	1944	only	-	Oct	 8	 2:00	0	-
      +Rule	Algeria	1945	only	-	Sep	16	 1:00	0	-
      +Rule	Algeria	1971	only	-	Apr	25	23:00s	1:00	S
      +Rule	Algeria	1971	only	-	Sep	26	23:00s	0	-
      +Rule	Algeria	1977	only	-	May	 6	 0:00	1:00	S
      +Rule	Algeria	1977	only	-	Oct	21	 0:00	0	-
      +Rule	Algeria	1978	only	-	Mar	24	 1:00	1:00	S
      +Rule	Algeria	1978	only	-	Sep	22	 3:00	0	-
      +Rule	Algeria	1980	only	-	Apr	25	 0:00	1:00	S
      +Rule	Algeria	1980	only	-	Oct	31	 2:00	0	-
      +# Shanks & Pottenger give 0:09:20 for Paris Mean Time; go with Howse's
      +# more precise 0:09:21.
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Algiers	0:12:12 -	LMT	1891 Mar 15 0:01
      +			0:09:21	-	PMT	1911 Mar 11    # Paris Mean Time
      +			0:00	Algeria	WE%sT	1940 Feb 25 2:00
      +			1:00	Algeria	CE%sT	1946 Oct  7
      +			0:00	-	WET	1956 Jan 29
      +			1:00	-	CET	1963 Apr 14
      +			0:00	Algeria	WE%sT	1977 Oct 21
      +			1:00	Algeria	CE%sT	1979 Oct 26
      +			0:00	Algeria	WE%sT	1981 May
      +			1:00	-	CET
      +
      +# Angola
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Luanda	0:52:56	-	LMT	1892
      +			0:52:04	-	AOT	1911 May 26 # Angola Time
      +			1:00	-	WAT
      +
      +# Benin
      +# Whitman says they switched to 1:00 in 1946, not 1934;
      +# go with Shanks & Pottenger.
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Africa/Porto-Novo	0:10:28	-	LMT	1912
      +			0:00	-	GMT	1934 Feb 26
      +			1:00	-	WAT
      +
      +# Botswana
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Gaborone	1:43:40 -	LMT	1885
      +			2:00	-	CAT	1943 Sep 19 2:00
      +			2:00	1:00	CAST	1944 Mar 19 2:00
      +			2:00	-	CAT
      +
      +# Burkina Faso
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Africa/Ouagadougou	-0:06:04 -	LMT	1912
      +			 0:00	-	GMT
      +
      +# Burundi
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Africa/Bujumbura	1:57:28	-	LMT	1890
      +			2:00	-	CAT
      +
      +# Cameroon
      +# Whitman says they switched to 1:00 in 1920; go with Shanks & Pottenger.
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Douala	0:38:48	-	LMT	1912
      +			1:00	-	WAT
      +
      +# Cape Verde
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Atlantic/Cape_Verde -1:34:04 -	LMT	1907			# Praia
      +			-2:00	-	CVT	1942 Sep
      +			-2:00	1:00	CVST	1945 Oct 15
      +			-2:00	-	CVT	1975 Nov 25 2:00
      +			-1:00	-	CVT
      +
      +# Central African Republic
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Bangui	1:14:20	-	LMT	1912
      +			1:00	-	WAT
      +
      +# Chad
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Ndjamena	1:00:12 -	LMT	1912
      +			1:00	-	WAT	1979 Oct 14
      +			1:00	1:00	WAST	1980 Mar  8
      +			1:00	-	WAT
      +
      +# Comoros
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Indian/Comoro	2:53:04 -	LMT	1911 Jul   # Moroni, Gran Comoro
      +			3:00	-	EAT
      +
      +# Democratic Republic of Congo
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Africa/Kinshasa	1:01:12 -	LMT	1897 Nov 9
      +			1:00	-	WAT
      +Zone Africa/Lubumbashi	1:49:52 -	LMT	1897 Nov 9
      +			2:00	-	CAT
      +
      +# Republic of the Congo
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Africa/Brazzaville	1:01:08 -	LMT	1912
      +			1:00	-	WAT
      +
      +# Cote D'Ivoire
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Abidjan	-0:16:08 -	LMT	1912
      +			 0:00	-	GMT
      +
      +# Djibouti
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Djibouti	2:52:36 -	LMT	1911 Jul
      +			3:00	-	EAT
      +
      +###############################################################################
      +
      +# Egypt
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Egypt	1940	only	-	Jul	15	0:00	1:00	S
      +Rule	Egypt	1940	only	-	Oct	 1	0:00	0	-
      +Rule	Egypt	1941	only	-	Apr	15	0:00	1:00	S
      +Rule	Egypt	1941	only	-	Sep	16	0:00	0	-
      +Rule	Egypt	1942	1944	-	Apr	 1	0:00	1:00	S
      +Rule	Egypt	1942	only	-	Oct	27	0:00	0	-
      +Rule	Egypt	1943	1945	-	Nov	 1	0:00	0	-
      +Rule	Egypt	1945	only	-	Apr	16	0:00	1:00	S
      +Rule	Egypt	1957	only	-	May	10	0:00	1:00	S
      +Rule	Egypt	1957	1958	-	Oct	 1	0:00	0	-
      +Rule	Egypt	1958	only	-	May	 1	0:00	1:00	S
      +Rule	Egypt	1959	1981	-	May	 1	1:00	1:00	S
      +Rule	Egypt	1959	1965	-	Sep	30	3:00	0	-
      +Rule	Egypt	1966	1994	-	Oct	 1	3:00	0	-
      +Rule	Egypt	1982	only	-	Jul	25	1:00	1:00	S
      +Rule	Egypt	1983	only	-	Jul	12	1:00	1:00	S
      +Rule	Egypt	1984	1988	-	May	 1	1:00	1:00	S
      +Rule	Egypt	1989	only	-	May	 6	1:00	1:00	S
      +Rule	Egypt	1990	1994	-	May	 1	1:00	1:00	S
      +# IATA (after 1990) says transitions are at 0:00.
      +# Go with IATA starting in 1995, except correct 1995 entry from 09-30 to 09-29.
      +
      +# From Alexander Krivenyshev (2011-04-20):
      +# "...Egypt's interim cabinet decided on Wednesday to cancel daylight
      +# saving time after a poll posted on its website showed the majority of
      +# Egyptians would approve the cancellation."
      +#
      +# Egypt to cancel daylight saving time
      +# 
      +# http://www.almasryalyoum.com/en/node/407168
      +# 
      +# or
      +# 
      +# http://www.worldtimezone.com/dst_news/dst_news_egypt04.html
      +# 
      +Rule	Egypt	1995	2010	-	Apr	lastFri	 0:00s	1:00	S
      +Rule	Egypt	1995	2005	-	Sep	lastThu	23:00s	0	-
      +# From Steffen Thorsen (2006-09-19):
      +# The Egyptian Gazette, issue 41,090 (2006-09-18), page 1, reports:
      +# Egypt will turn back clocks by one hour at the midnight of Thursday
      +# after observing the daylight saving time since May.
      +# http://news.gom.com.eg/gazette/pdf/2006/09/18/01.pdf
      +Rule	Egypt	2006	only	-	Sep	21	23:00s	0	-
      +# From Dirk Losch (2007-08-14):
      +# I received a mail from an airline which says that the daylight
      +# saving time in Egypt will end in the night of 2007-09-06 to 2007-09-07.
      +# From Jesper Norgaard Welen (2007-08-15): [The following agree:]
      +# http://www.nentjes.info/Bill/bill5.htm
      +# http://www.timeanddate.com/worldclock/city.html?n=53
      +# From Steffen Thorsen (2007-09-04): The official information...:
      +# http://www.sis.gov.eg/En/EgyptOnline/Miscellaneous/000002/0207000000000000001580.htm
      +Rule	Egypt	2007	only	-	Sep	Thu>=1	23:00s	0	-
      +# From Abdelrahman Hassan (2007-09-06):
      +# Due to the Hijri (lunar Islamic calendar) year being 11 days shorter
      +# than the year of the Gregorian calendar, Ramadan shifts earlier each
      +# year. This year it will be observed September 13 (September is quite
      +# hot in Egypt), and the idea is to make fasting easier for workers by
      +# shifting business hours one hour out of daytime heat. Consequently,
      +# unless discontinued, next DST may end Thursday 28 August 2008.
      +# From Paul Eggert (2007-08-17):
      +# For lack of better info, assume the new rule is last Thursday in August.
      +
      +# From Petr Machata (2009-04-06):
      +# The following appeared in Red Hat bugzilla[1] (edited):
      +#
      +# > $ zdump -v /usr/share/zoneinfo/Africa/Cairo | grep 2009
      +# > /usr/share/zoneinfo/Africa/Cairo  Thu Apr 23 21:59:59 2009 UTC = Thu =
      +# Apr 23
      +# > 23:59:59 2009 EET isdst=0 gmtoff=7200
      +# > /usr/share/zoneinfo/Africa/Cairo  Thu Apr 23 22:00:00 2009 UTC = Fri =
      +# Apr 24
      +# > 01:00:00 2009 EEST isdst=1 gmtoff=10800
      +# > /usr/share/zoneinfo/Africa/Cairo  Thu Aug 27 20:59:59 2009 UTC = Thu =
      +# Aug 27
      +# > 23:59:59 2009 EEST isdst=1 gmtoff=10800
      +# > /usr/share/zoneinfo/Africa/Cairo  Thu Aug 27 21:00:00 2009 UTC = Thu =
      +# Aug 27
      +# > 23:00:00 2009 EET isdst=0 gmtoff=7200
      +#
      +# > end date should be Thu Sep 24 2009 (Last Thursday in September at 23:59=
      +# :59)
      +# > http://support.microsoft.com/kb/958729/
      +#
      +# timeanddate[2] and another site I've found[3] also support that.
      +#
      +# [1] 
      +# https://bugzilla.redhat.com/show_bug.cgi?id=492263
      +# 
      +# [2] 
      +# http://www.timeanddate.com/worldclock/clockchange.html?n=53
      +# 
      +# [3] 
      +# http://wwp.greenwichmeantime.com/time-zone/africa/egypt/
      +# 
      +
      +# From Arthur David Olson (2009-04-20):
      +# In 2009 (and for the next several years), Ramadan ends before the fourth
      +# Thursday in September; Egypt is expected to revert to the last Thursday
      +# in September.
      +
      +# From Steffen Thorsen (2009-08-11):
      +# We have been able to confirm the August change with the Egyptian Cabinet
      +# Information and Decision Support Center:
      +# 
      +# http://www.timeanddate.com/news/time/egypt-dst-ends-2009.html
      +# 
      +#
      +# The Middle East News Agency
      +# 
      +# http://www.mena.org.eg/index.aspx
      +# 
      +# also reports "Egypt starts winter time on August 21"
      +# today in article numbered "71, 11/08/2009 12:25 GMT."
      +# Only the title above is available without a subscription to their service,
      +# and can be found by searching for "winter" in their search engine
      +# (at least today).
      +
      +# From Alexander Krivenyshev (2010-07-20):
      +# According to News from Egypt -  Al-Masry Al-Youm Egypt's cabinet has
      +# decided that Daylight Saving Time will not be used in Egypt during
      +# Ramadan.
      +#
      +# Arabic translation:
      +# "Clocks to go back during Ramadan--and then forward again"
      +# 
      +# http://www.almasryalyoum.com/en/news/clocks-go-back-during-ramadan-and-then-forward-again
      +# 
      +# or
      +# 
      +# http://www.worldtimezone.com/dst_news/dst_news_egypt02.html
      +# 
      +
      +Rule	Egypt	2008	only	-	Aug	lastThu	23:00s	0	-
      +Rule	Egypt	2009	only	-	Aug	20	23:00s	0	-
      +Rule	Egypt	2010	only	-	Aug	11	0:00	0	-
      +Rule	Egypt	2010	only	-	Sep	10	0:00	1:00	S
      +Rule	Egypt	2010	only	-	Sep	lastThu	23:00s	0	-
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Cairo	2:05:00 -	LMT	1900 Oct
      +			2:00	Egypt	EE%sT
      +
      +# Equatorial Guinea
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Malabo	0:35:08 -	LMT	1912
      +			0:00	-	GMT	1963 Dec 15
      +			1:00	-	WAT
      +
      +# Eritrea
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Asmara	2:35:32 -	LMT	1870
      +			2:35:32	-	AMT	1890	      # Asmara Mean Time
      +			2:35:20	-	ADMT	1936 May 5    # Adis Dera MT
      +			3:00	-	EAT
      +
      +# Ethiopia
      +# From Paul Eggert (2006-03-22):
      +# Shanks & Pottenger write that Ethiopia had six narrowly-spaced time zones
      +# between 1870 and 1890, and that they merged to 38E50 (2:35:20) in 1890.
      +# We'll guess that 38E50 is for Adis Dera.
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Africa/Addis_Ababa	2:34:48 -	LMT	1870
      +			2:35:20	-	ADMT	1936 May 5    # Adis Dera MT
      +			3:00	-	EAT
      +
      +# Gabon
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Africa/Libreville	0:37:48 -	LMT	1912
      +			1:00	-	WAT
      +
      +# Gambia
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Banjul	-1:06:36 -	LMT	1912
      +			-1:06:36 -	BMT	1935	# Banjul Mean Time
      +			-1:00	-	WAT	1964
      +			 0:00	-	GMT
      +
      +# Ghana
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +# Whitman says DST was observed from 1931 to ``the present'';
      +# go with Shanks & Pottenger.
      +Rule	Ghana	1936	1942	-	Sep	 1	0:00	0:20	GHST
      +Rule	Ghana	1936	1942	-	Dec	31	0:00	0	GMT
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Accra	-0:00:52 -	LMT	1918
      +			 0:00	Ghana	%s
      +
      +# Guinea
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Conakry	-0:54:52 -	LMT	1912
      +			 0:00	-	GMT	1934 Feb 26
      +			-1:00	-	WAT	1960
      +			 0:00	-	GMT
      +
      +# Guinea-Bissau
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Bissau	-1:02:20 -	LMT	1911 May 26
      +			-1:00	-	WAT	1975
      +			 0:00	-	GMT
      +
      +# Kenya
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Nairobi	2:27:16	-	LMT	1928 Jul
      +			3:00	-	EAT	1930
      +			2:30	-	BEAT	1940
      +			2:45	-	BEAUT	1960
      +			3:00	-	EAT
      +
      +# Lesotho
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Maseru	1:50:00 -	LMT	1903 Mar
      +			2:00	-	SAST	1943 Sep 19 2:00
      +			2:00	1:00	SAST	1944 Mar 19 2:00
      +			2:00	-	SAST
      +
      +# Liberia
      +# From Paul Eggert (2006-03-22):
      +# In 1972 Liberia was the last country to switch
      +# from a UTC offset that was not a multiple of 15 or 20 minutes.
      +# Howse reports that it was in honor of their president's birthday.
      +# Shank & Pottenger report the date as May 1, whereas Howse reports Jan;
      +# go with Shanks & Pottenger.
      +# For Liberia before 1972, Shanks & Pottenger report -0:44, whereas Howse and
      +# Whitman each report -0:44:30; go with the more precise figure.
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Monrovia	-0:43:08 -	LMT	1882
      +			-0:43:08 -	MMT	1919 Mar # Monrovia Mean Time
      +			-0:44:30 -	LRT	1972 May # Liberia Time
      +			 0:00	-	GMT
      +
      +###############################################################################
      +
      +# Libya
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Libya	1951	only	-	Oct	14	2:00	1:00	S
      +Rule	Libya	1952	only	-	Jan	 1	0:00	0	-
      +Rule	Libya	1953	only	-	Oct	 9	2:00	1:00	S
      +Rule	Libya	1954	only	-	Jan	 1	0:00	0	-
      +Rule	Libya	1955	only	-	Sep	30	0:00	1:00	S
      +Rule	Libya	1956	only	-	Jan	 1	0:00	0	-
      +Rule	Libya	1982	1984	-	Apr	 1	0:00	1:00	S
      +Rule	Libya	1982	1985	-	Oct	 1	0:00	0	-
      +Rule	Libya	1985	only	-	Apr	 6	0:00	1:00	S
      +Rule	Libya	1986	only	-	Apr	 4	0:00	1:00	S
      +Rule	Libya	1986	only	-	Oct	 3	0:00	0	-
      +Rule	Libya	1987	1989	-	Apr	 1	0:00	1:00	S
      +Rule	Libya	1987	1989	-	Oct	 1	0:00	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Tripoli	0:52:44 -	LMT	1920
      +			1:00	Libya	CE%sT	1959
      +			2:00	-	EET	1982
      +			1:00	Libya	CE%sT	1990 May  4
      +# The following entries are from Shanks & Pottenger;
      +# the IATA SSIM data contain some obvious errors.
      +			2:00	-	EET	1996 Sep 30
      +			1:00	-	CET	1997 Apr  4
      +			1:00	1:00	CEST	1997 Oct  4
      +			2:00	-	EET
      +
      +# Madagascar
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Indian/Antananarivo 3:10:04 -	LMT	1911 Jul
      +			3:00	-	EAT	1954 Feb 27 23:00s
      +			3:00	1:00	EAST	1954 May 29 23:00s
      +			3:00	-	EAT
      +
      +# Malawi
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Blantyre	2:20:00 -	LMT	1903 Mar
      +			2:00	-	CAT
      +
      +# Mali
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Bamako	-0:32:00 -	LMT	1912
      +			 0:00	-	GMT	1934 Feb 26
      +			-1:00	-	WAT	1960 Jun 20
      +			 0:00	-	GMT
      +
      +# Mauritania
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Africa/Nouakchott	-1:03:48 -	LMT	1912
      +			 0:00	-	GMT	1934 Feb 26
      +			-1:00	-	WAT	1960 Nov 28
      +			 0:00	-	GMT
      +
      +# Mauritius
      +
      +# From Steffen Thorsen (2008-06-25):
      +# Mauritius plans to observe DST from 2008-11-01 to 2009-03-31 on a trial
      +# basis....
      +# It seems that Mauritius observed daylight saving time from 1982-10-10 to
      +# 1983-03-20 as well, but that was not successful....
      +# http://www.timeanddate.com/news/time/mauritius-daylight-saving-time.html
      +
      +# From Alex Krivenyshev (2008-06-25):
      +# http://economicdevelopment.gov.mu/portal/site/Mainhomepage/menuitem.a42b24128104d9845dabddd154508a0c/?content_id=0a7cee8b5d69a110VgnVCM1000000a04a8c0RCRD
      +
      +# From Arthur David Olson (2008-06-30):
      +# The www.timeanddate.com article cited by Steffen Thorsen notes that "A
      +# final decision has yet to be made on the times that daylight saving
      +# would begin and end on these dates." As a place holder, use midnight.
      +
      +# From Paul Eggert (2008-06-30):
      +# Follow Thorsen on DST in 1982/1983, instead of Shanks & Pottenger.
      +
      +# From Steffen Thorsen (2008-07-10):
      +# According to
      +# 
      +# http://www.lexpress.mu/display_article.php?news_id=111216
      +# 
      +# (in French), Mauritius will start and end their DST a few days earlier
      +# than previously announced (2008-11-01 to 2009-03-31).  The new start
      +# date is 2008-10-26 at 02:00 and the new end date is 2009-03-27 (no time
      +# given, but it is probably at either 2 or 3 wall clock time).
      +#
      +# A little strange though, since the article says that they moved the date
      +# to align itself with Europe and USA which also change time on that date,
      +# but that means they have not paid attention to what happened in
      +# USA/Canada last year (DST ends first Sunday in November). I also wonder
      +# why that they end on a Friday, instead of aligning with Europe which
      +# changes two days later.
      +
      +# From Alex Krivenyshev (2008-07-11):
      +# Seems that English language article "The revival of daylight saving
      +# time:  Energy conservation?"-# No. 16578 (07/11/2008) was originally
      +# published on Monday, June 30, 2008...
      +#
      +# I guess that article in French "Le gouvernement avance l'introduction
      +# de l'heure d'ete" stating that DST in Mauritius starting on October 26
      +# and ending on March 27, 2009 is the most recent one.
      +# ...
      +# 
      +# http://www.worldtimezone.com/dst_news/dst_news_mauritius02.html
      +# 
      +
      +# From Riad M. Hossen Ally (2008-08-03):
      +# The Government of Mauritius weblink
      +# 
      +# http://www.gov.mu/portal/site/pmosite/menuitem.4ca0efdee47462e7440a600248a521ca/?content_id=4728ca68b2a5b110VgnVCM1000000a04a8c0RCRD
      +# 
      +# Cabinet Decision of July 18th, 2008 states as follows:
      +#
      +# 4. ...Cabinet has agreed to the introduction into the National Assembly
      +# of the Time Bill which provides for the introduction of summer time in
      +# Mauritius. The summer time period which will be of one hour ahead of
      +# the standard time, will be aligned with that in Europe and the United
      +# States of America. It will start at two o'clock in the morning on the
      +# last Sunday of October and will end at two o'clock in the morning on
      +# the last Sunday of March the following year. The summer time for the
      +# year 2008 - 2009 will, therefore, be effective as from 26 October 2008
      +# and end on 29 March 2009.
      +
      +# From Ed Maste (2008-10-07):
      +# THE TIME BILL (No. XXVII of 2008) Explanatory Memorandum states the
      +# beginning / ending of summer time is 2 o'clock standard time in the
      +# morning of the last Sunday of October / last Sunday of March.
      +# 
      +# http://www.gov.mu/portal/goc/assemblysite/file/bill2708.pdf
      +# 
      +
      +# From Steffen Thorsen (2009-06-05):
      +# According to several sources, Mauritius will not continue to observe
      +# DST the coming summer...
      +#
      +# Some sources, in French:
      +# 
      +# http://www.defimedia.info/news/946/Rashid-Beebeejaun-:-%C2%AB-L%E2%80%99heure-d%E2%80%99%C3%A9t%C3%A9-ne-sera-pas-appliqu%C3%A9e-cette-ann%C3%A9e-%C2%BB
      +# 
      +# 
      +# http://lexpress.mu/Story/3398~Beebeejaun---Les-objectifs-d-%C3%A9conomie-d-%C3%A9nergie-de-l-heure-d-%C3%A9t%C3%A9-ont-%C3%A9t%C3%A9-atteints-
      +# 
      +#
      +# Our wrap-up:
      +# 
      +# http://www.timeanddate.com/news/time/mauritius-dst-will-not-repeat.html
      +# 
      +
      +# From Arthur David Olson (2009-07-11):
      +# The "mauritius-dst-will-not-repeat" wrapup includes this:
      +# "The trial ended on March 29, 2009, when the clocks moved back by one hour
      +# at 2am (or 02:00) local time..."
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule Mauritius	1982	only	-	Oct	10	0:00	1:00	S
      +Rule Mauritius	1983	only	-	Mar	21	0:00	0	-
      +Rule Mauritius	2008	only	-	Oct	lastSun	2:00	1:00	S
      +Rule Mauritius	2009	only	-	Mar	lastSun	2:00	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Indian/Mauritius	3:50:00 -	LMT	1907		# Port Louis
      +			4:00 Mauritius	MU%sT	# Mauritius Time
      +# Agalega Is, Rodriguez
      +# no information; probably like Indian/Mauritius
      +
      +# Mayotte
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Indian/Mayotte	3:00:56 -	LMT	1911 Jul	# Mamoutzou
      +			3:00	-	EAT
      +
      +# Morocco
      +# See the `europe' file for Spanish Morocco (Africa/Ceuta).
      +
      +# From Alex Krivenyshev (2008-05-09):
      +# Here is an article that Morocco plan to introduce Daylight Saving Time between
      +# 1 June, 2008 and 27 September, 2008.
      +#
      +# "... Morocco is to save energy by adjusting its clock during summer so it will
      +# be one hour ahead of GMT between 1 June and 27 September, according to
      +# Communication Minister and Gov ernment Spokesman, Khalid Naciri...."
      +#
      +# 
      +# http://www.worldtimezone.net/dst_news/dst_news_morocco01.html
      +# 
      +# OR
      +# 
      +# http://en.afrik.com/news11892.html
      +# 
      +
      +# From Alex Krivenyshev (2008-05-09):
      +# The Morocco time change can be confirmed on Morocco web site Maghreb Arabe Presse:
      +# 
      +# http://www.map.ma/eng/sections/box3/morocco_shifts_to_da/view
      +# 
      +#
      +# Morocco shifts to daylight time on June 1st through September 27, Govt.
      +# spokesman.
      +
      +# From Patrice Scattolin (2008-05-09):
      +# According to this article:
      +# 
      +# http://www.avmaroc.com/actualite/heure-dete-comment-a127896.html
      +# 
      +# (and republished here:
      +# 
      +# http://www.actu.ma/heure-dete-comment_i127896_0.html
      +# 
      +# )
      +# the changes occurs at midnight:
      +#
      +# saturday night may 31st at midnight (which in french is to be
      +# intrepreted as the night between saturday and sunday)
      +# sunday night the 28th  at midnight
      +#
      +# Seeing that the 28th is monday, I am guessing that she intends to say
      +# the midnight of the 28th which is the midnight between sunday and
      +# monday, which jives with other sources that say that it's inclusive
      +# june1st to sept 27th.
      +#
      +# The decision was taken by decree *2-08-224 *but I can't find the decree
      +# published on the web.
      +#
      +# It's also confirmed here:
      +# 
      +# http://www.maroc.ma/NR/exeres/FACF141F-D910-44B0-B7FA-6E03733425D1.htm
      +# 
      +# on a government portal as being  between june 1st and sept 27th (not yet
      +# posted in english).
      +#
      +# The following google query will generate many relevant hits:
      +# 
      +# http://www.google.com/search?hl=en&q=Conseil+de+gouvernement+maroc+heure+avance&btnG=Search
      +# 
      +
      +# From Alex Krivenyshev (2008-05-09):
      +# Is Western Sahara (part which administrated by Morocco) going to follow
      +# Morocco DST changes?  Any information?  What about other part of
      +# Western Sahara - under administration of POLISARIO Front (also named
      +# SADR Saharawi Arab Democratic Republic)?
      +
      +# From Arthur David Olson (2008-05-09):
      +# XXX--guess that it is only Morocco for now; guess only 2008 for now.
      +
      +# From Steffen Thorsen (2008-08-27):
      +# Morocco will change the clocks back on the midnight between August 31
      +# and September 1. They originally planned to observe DST to near the end
      +# of September:
      +#
      +# One article about it (in French):
      +# 
      +# http://www.menara.ma/fr/Actualites/Maroc/Societe/ci.retour_a_l_heure_gmt_a_partir_du_dimanche_31_aout_a_minuit_officiel_.default
      +# 
      +#
      +# We have some further details posted here:
      +# 
      +# http://www.timeanddate.com/news/time/morocco-ends-dst-early-2008.html
      +# 
      +
      +# From Steffen Thorsen (2009-03-17):
      +# Morocco will observe DST from 2009-06-01 00:00 to 2009-08-21 00:00 according
      +# to many sources, such as
      +# 
      +# http://news.marweb.com/morocco/entertainment/morocco-daylight-saving.html
      +# 
      +# 
      +# http://www.medi1sat.ma/fr/depeche.aspx?idp=2312
      +# 
      +# (French)
      +#
      +# Our summary:
      +# 
      +# http://www.timeanddate.com/news/time/morocco-starts-dst-2009.html
      +# 
      +
      +# From Alexander Krivenyshev (2009-03-17):
      +# Here is a link to official document from Royaume du Maroc Premier Ministre,
      +# Ministere de la Modernisation des Secteurs Publics
      +#
      +# Under Article 1 of Royal Decree No. 455-67 of Act 23 safar 1387 (2 june 1967)
      +# concerning the amendment of the legal time, the Ministry of Modernization of
      +# Public Sectors announced that the official time in the Kingdom will be
      +# advanced 60 minutes from Sunday 31 May 2009 at midnight.
      +#
      +# 
      +# http://www.mmsp.gov.ma/francais/Actualites_fr/PDF_Actualites_Fr/HeureEte_FR.pdf
      +# 
      +#
      +# 
      +# http://www.worldtimezone.com/dst_news/dst_news_morocco03.html
      +# 
      +
      +# From Steffen Thorsen (2010-04-13):
      +# Several news media in Morocco report that the Ministry of Modernization
      +# of Public Sectors has announced that Morocco will have DST from
      +# 2010-05-02 to 2010-08-08.
      +#
      +# Example:
      +# 
      +# http://www.lavieeco.com/actualites/4099-le-maroc-passera-a-l-heure-d-ete-gmt1-le-2-mai.html
      +# 
      +# (French)
      +# Our page:
      +# 
      +# http://www.timeanddate.com/news/time/morocco-starts-dst-2010.html
      +# 
      +
      +# From Dan Abitol (2011-03-30):
      +# ...Rules for Africa/Casablanca are the following (24h format)
      +# The 3rd april 2011 at 00:00:00, [it] will be 3rd april 1:00:00
      +# The 31th july 2011 at 00:59:59,  [it] will be 31th July 00:00:00
      +# ...Official links of change in morocco
      +# The change was broadcast on the FM Radio
      +# I ve called ANRT (telecom regulations in Morocco) at
      +# +212.537.71.84.00
      +# 
      +# http://www.anrt.net.ma/fr/
      +# 
      +# They said that
      +# 
      +# http://www.map.ma/fr/sections/accueil/l_heure_legale_au_ma/view
      +# 
      +# is the official publication to look at.
      +# They said that the decision was already taken.
      +#
      +# More articles in the press
      +# 
      +# http://www.yabiladi.com/articles/details/5058/secret-l-heure-d-ete-maroc-lev
      +# 
      +# e.html
      +# 
      +# http://www.lematin.ma/Actualite/Express/Article.asp?id=148923
      +# 
      +# 
      +# http://www.lavieeco.com/actualite/Le-Maroc-passe-sur-GMT%2B1-a-partir-de-dim
      +# anche-prochain-5538.html
      +# 
      +
      +# From Petr Machata (2011-03-30):
      +# They have it written in English here:
      +# 
      +# http://www.map.ma/eng/sections/home/morocco_to_spring_fo/view
      +# 
      +#
      +# It says there that "Morocco will resume its standard time on July 31,
      +# 2011 at midnight." Now they don't say whether they mean midnight of
      +# wall clock time (i.e. 11pm UTC), but that's what I would assume. It has
      +# also been like that in the past.
      +
      +# From Alexander Krivenyshev (2012-03-09):
      +# According to Infomédiaire web site from Morocco (infomediaire.ma),
      +# on March 9, 2012, (in French) Heure légale:
      +# Le Maroc adopte officiellement l'heure d'été
      +# 
      +# http://www.infomediaire.ma/news/maroc/heure-l%C3%A9gale-le-maroc-adopte-officiellement-lheure-d%C3%A9t%C3%A9
      +# 
      +# Governing Council adopted draft decree, that Morocco DST starts on
      +# the last Sunday of March (March 25, 2012) and ends on
      +# last Sunday of September (September 30, 2012)
      +# except the month of Ramadan.
      +# or (brief)
      +# 
      +# http://www.worldtimezone.com/dst_news/dst_news_morocco06.html
      +# 
      +
      +# From Arthur David Olson (2012-03-10):
      +# The infomediaire.ma source indicates that the system is to be in
      +# effect every year. It gives 03H00 as the "fall back" time of day;
      +# it lacks a "spring forward" time of day; assume 2:00 XXX.
      +# Wait on specifying the Ramadan exception for details about
      +# start date, start time of day, end date, and end time of day XXX.
      +
      +# From Christophe Tropamer (2012-03-16):
      +# Seen Morocco change again:
      +# 
      +# http://www.le2uminutes.com/actualite.php
      +# 
      +# "...à partir du dernier dimance d'avril et non fins mars,
      +# comme annoncé précédemment."
      +
      +# From Milamber Space Network (2012-07-17):
      +# The official return to GMT is announced by the Moroccan government:
      +# 
      +# http://www.mmsp.gov.ma/fr/actualites.aspx?id=288 [in French]
      +# 
      +#
      +# Google translation, lightly edited:
      +# Back to the standard time of the Kingdom (GMT)
      +# Pursuant to Decree No. 2-12-126 issued on 26 Jumada (I) 1433 (April 18,
      +# 2012) and in accordance with the order of Mr. President of the
      +# Government No. 3-47-12 issued on 24 Sha'ban (11 July 2012), the Ministry
      +# of Public Service and Administration Modernization announces the return
      +# of the legal time of the Kingdom (GMT) from Friday, July 20, 2012 until
      +# Monday, August 20, 2012.  So the time will be delayed by 60 minutes from
      +# 3:00 am Friday, July 20, 2012 and will again be advanced by 60 minutes
      +# August 20, 2012 from 2:00 am.
      +
      +# RULE	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +
      +Rule	Morocco	1939	only	-	Sep	12	 0:00	1:00	S
      +Rule	Morocco	1939	only	-	Nov	19	 0:00	0	-
      +Rule	Morocco	1940	only	-	Feb	25	 0:00	1:00	S
      +Rule	Morocco	1945	only	-	Nov	18	 0:00	0	-
      +Rule	Morocco	1950	only	-	Jun	11	 0:00	1:00	S
      +Rule	Morocco	1950	only	-	Oct	29	 0:00	0	-
      +Rule	Morocco	1967	only	-	Jun	 3	12:00	1:00	S
      +Rule	Morocco	1967	only	-	Oct	 1	 0:00	0	-
      +Rule	Morocco	1974	only	-	Jun	24	 0:00	1:00	S
      +Rule	Morocco	1974	only	-	Sep	 1	 0:00	0	-
      +Rule	Morocco	1976	1977	-	May	 1	 0:00	1:00	S
      +Rule	Morocco	1976	only	-	Aug	 1	 0:00	0	-
      +Rule	Morocco	1977	only	-	Sep	28	 0:00	0	-
      +Rule	Morocco	1978	only	-	Jun	 1	 0:00	1:00	S
      +Rule	Morocco	1978	only	-	Aug	 4	 0:00	0	-
      +Rule	Morocco	2008	only	-	Jun	 1	 0:00	1:00	S
      +Rule	Morocco	2008	only	-	Sep	 1	 0:00	0	-
      +Rule	Morocco	2009	only	-	Jun	 1	 0:00	1:00	S
      +Rule	Morocco	2009	only	-	Aug	 21	 0:00	0	-
      +Rule	Morocco	2010	only	-	May	 2	 0:00	1:00	S
      +Rule	Morocco	2010	only	-	Aug	 8	 0:00	0	-
      +Rule	Morocco	2011	only	-	Apr	 3	 0:00	1:00	S
      +Rule	Morocco	2011	only	-	Jul	 31	 0	0	-
      +Rule	Morocco	2012	max	-	Apr	 lastSun 2:00	1:00	S
      +Rule	Morocco	2012	max	-	Sep	 lastSun 3:00	0	-
      +Rule	Morocco	2012	only	-	Jul	 20	 3:00	0	-
      +Rule	Morocco	2012	only	-	Aug	 20	 2:00	1:00	S
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Africa/Casablanca	-0:30:20 -	LMT	1913 Oct 26
      +			 0:00	Morocco	WE%sT	1984 Mar 16
      +			 1:00	-	CET	1986
      +			 0:00	Morocco	WE%sT
      +# Western Sahara
      +Zone Africa/El_Aaiun	-0:52:48 -	LMT	1934 Jan
      +			-1:00	-	WAT	1976 Apr 14
      +			 0:00	-	WET
      +
      +# Mozambique
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Maputo	2:10:20 -	LMT	1903 Mar
      +			2:00	-	CAT
      +
      +# Namibia
      +# The 1994-04-03 transition is from Shanks & Pottenger.
      +# Shanks & Pottenger report no DST after 1998-04; go with IATA.
      +
      +# From Petronella Sibeene (2007-03-30) in
      +# :
      +# While the entire country changes its time, Katima Mulilo and other
      +# settlements in Caprivi unofficially will not because the sun there
      +# rises and sets earlier compared to other regions.  Chief of
      +# Forecasting Riaan van Zyl explained that the far eastern parts of
      +# the country are close to 40 minutes earlier in sunrise than the rest
      +# of the country.
      +#
      +# From Paul Eggert (2007-03-31):
      +# Apparently the Caprivi Strip informally observes Botswana time, but
      +# we have no details.  In the meantime people there can use Africa/Gaborone.
      +
      +# RULE	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Namibia	1994	max	-	Sep	Sun>=1	2:00	1:00	S
      +Rule	Namibia	1995	max	-	Apr	Sun>=1	2:00	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Windhoek	1:08:24 -	LMT	1892 Feb 8
      +			1:30	-	SWAT	1903 Mar	# SW Africa Time
      +			2:00	-	SAST	1942 Sep 20 2:00
      +			2:00	1:00	SAST	1943 Mar 21 2:00
      +			2:00	-	SAST	1990 Mar 21 # independence
      +			2:00	-	CAT	1994 Apr  3
      +			1:00	Namibia	WA%sT
      +
      +# Niger
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Niamey	 0:08:28 -	LMT	1912
      +			-1:00	-	WAT	1934 Feb 26
      +			 0:00	-	GMT	1960
      +			 1:00	-	WAT
      +
      +# Nigeria
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Lagos	0:13:36 -	LMT	1919 Sep
      +			1:00	-	WAT
      +
      +# Reunion
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Indian/Reunion	3:41:52 -	LMT	1911 Jun	# Saint-Denis
      +			4:00	-	RET	# Reunion Time
      +#
      +# Scattered Islands (Iles Eparses) administered from Reunion are as follows.
      +# The following information about them is taken from
      +# Iles Eparses (www.outre-mer.gouv.fr/domtom/ile.htm, 1997-07-22, in French;
      +# no longer available as of 1999-08-17).
      +# We have no info about their time zone histories.
      +#
      +# Bassas da India - uninhabited
      +# Europa Island - inhabited from 1905 to 1910 by two families
      +# Glorioso Is - inhabited until at least 1958
      +# Juan de Nova - uninhabited
      +# Tromelin - inhabited until at least 1958
      +
      +# Rwanda
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Kigali	2:00:16 -	LMT	1935 Jun
      +			2:00	-	CAT
      +
      +# St Helena
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Atlantic/St_Helena	-0:22:48 -	LMT	1890		# Jamestown
      +			-0:22:48 -	JMT	1951	# Jamestown Mean Time
      +			 0:00	-	GMT
      +# The other parts of the St Helena territory are similar:
      +#	Tristan da Cunha: on GMT, say Whitman and the CIA
      +#	Ascension: on GMT, says usno1995 and the CIA
      +#	Gough (scientific station since 1955; sealers wintered previously):
      +#		on GMT, says the CIA
      +#	Inaccessible, Nightingale: no information, but probably GMT
      +
      +# Sao Tome and Principe
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Sao_Tome	 0:26:56 -	LMT	1884
      +			-0:36:32 -	LMT	1912	# Lisbon Mean Time
      +			 0:00	-	GMT
      +
      +# Senegal
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Dakar	-1:09:44 -	LMT	1912
      +			-1:00	-	WAT	1941 Jun
      +			 0:00	-	GMT
      +
      +# Seychelles
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Indian/Mahe	3:41:48 -	LMT	1906 Jun	# Victoria
      +			4:00	-	SCT	# Seychelles Time
      +# From Paul Eggert (2001-05-30):
      +# Aldabra, Farquhar, and Desroches, originally dependencies of the
      +# Seychelles, were transferred to the British Indian Ocean Territory
      +# in 1965 and returned to Seychelles control in 1976.  We don't know
      +# whether this affected their time zone, so omit this for now.
      +# Possibly the islands were uninhabited.
      +
      +# Sierra Leone
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +# Whitman gives Mar 31 - Aug 31 for 1931 on; go with Shanks & Pottenger.
      +Rule	SL	1935	1942	-	Jun	 1	0:00	0:40	SLST
      +Rule	SL	1935	1942	-	Oct	 1	0:00	0	WAT
      +Rule	SL	1957	1962	-	Jun	 1	0:00	1:00	SLST
      +Rule	SL	1957	1962	-	Sep	 1	0:00	0	GMT
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Freetown	-0:53:00 -	LMT	1882
      +			-0:53:00 -	FMT	1913 Jun # Freetown Mean Time
      +			-1:00	SL	%s	1957
      +			 0:00	SL	%s
      +
      +# Somalia
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Africa/Mogadishu	3:01:28 -	LMT	1893 Nov
      +			3:00	-	EAT	1931
      +			2:30	-	BEAT	1957
      +			3:00	-	EAT
      +
      +# South Africa
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	SA	1942	1943	-	Sep	Sun>=15	2:00	1:00	-
      +Rule	SA	1943	1944	-	Mar	Sun>=15	2:00	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Africa/Johannesburg 1:52:00 -	LMT	1892 Feb 8
      +			1:30	-	SAST	1903 Mar
      +			2:00	SA	SAST
      +# Marion and Prince Edward Is
      +# scientific station since 1947
      +# no information
      +
      +# Sudan
      +#
      +# From 
      +# Sudan News Agency (2000-01-13)
      +# , also reported by Michael De Beukelaer-Dossche via Steffen Thorsen:
      +# Clocks will be moved ahead for 60 minutes all over the Sudan as of noon
      +# Saturday....  This was announced Thursday by Caretaker State Minister for
      +# Manpower Abdul-Rahman Nur-Eddin.
      +#
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Sudan	1970	only	-	May	 1	0:00	1:00	S
      +Rule	Sudan	1970	1985	-	Oct	15	0:00	0	-
      +Rule	Sudan	1971	only	-	Apr	30	0:00	1:00	S
      +Rule	Sudan	1972	1985	-	Apr	lastSun	0:00	1:00	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Khartoum	2:10:08 -	LMT	1931
      +			2:00	Sudan	CA%sT	2000 Jan 15 12:00
      +			3:00	-	EAT
      +
      +# South Sudan
      +Zone	Africa/Juba	2:06:24 -	LMT	1931
      +			2:00	Sudan	CA%sT	2000 Jan 15 12:00
      +			3:00	-	EAT
      +
      +# Swaziland
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Mbabane	2:04:24 -	LMT	1903 Mar
      +			2:00	-	SAST
      +
      +# Tanzania
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Africa/Dar_es_Salaam 2:37:08 -	LMT	1931
      +			3:00	-	EAT	1948
      +			2:45	-	BEAUT	1961
      +			3:00	-	EAT
      +
      +# Togo
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Lome	0:04:52 -	LMT	1893
      +			0:00	-	GMT
      +
      +# Tunisia
      +
      +# From Gwillim Law (2005-04-30):
      +# My correspondent, Risto Nykanen, has alerted me to another adoption of DST,
      +# this time in Tunisia.  According to Yahoo France News
      +# , in a story attributed to AP
      +# and dated 2005-04-26, "Tunisia has decided to advance its official time by
      +# one hour, starting on Sunday, May 1.  Henceforth, Tunisian time will be
      +# UTC+2 instead of UTC+1.  The change will take place at 23:00 UTC next
      +# Saturday."  (My translation)
      +#
      +# From Oscar van Vlijmen (2005-05-02):
      +# LaPresse, the first national daily newspaper ...
      +# 
      +# ... DST for 2005: on: Sun May 1 0h standard time, off: Fri Sept. 30,
      +# 1h standard time.
      +#
      +# From Atef Loukil (2006-03-28):
      +# The daylight saving time will be the same each year:
      +# Beginning      : the last Sunday of March at 02:00
      +# Ending         : the last Sunday of October at 03:00 ...
      +# http://www.tap.info.tn/en/index.php?option=com_content&task=view&id=1188&Itemid=50
      +
      +# From Steffen Thorsen (2009-03-16):
      +# According to several news sources, Tunisia will not observe DST this year.
      +# (Arabic)
      +# 
      +# http://www.elbashayer.com/?page=viewn&nid=42546
      +# 
      +# 
      +# http://www.babnet.net/kiwidetail-15295.asp
      +# 
      +#
      +# We have also confirmed this with the US embassy in Tunisia.
      +# We have a wrap-up about this on the following page:
      +# 
      +# http://www.timeanddate.com/news/time/tunisia-cancels-dst-2009.html
      +# 
      +
      +# From Alexander Krivenyshev (2009-03-17):
      +# Here is a link to Tunis Afrique Presse News Agency
      +#
      +# Standard time to be kept the whole year long (tap.info.tn):
      +#
      +# (in English)
      +# 
      +# http://www.tap.info.tn/en/index.php?option=com_content&task=view&id=26813&Itemid=157
      +# 
      +#
      +# (in Arabic)
      +# 
      +# http://www.tap.info.tn/ar/index.php?option=com_content&task=view&id=61240&Itemid=1
      +# 
      +
      +# From Arthur David Olson (2009--3-18):
      +# The Tunis Afrique Presse News Agency notice contains this: "This measure is due to the fact
      +# that the fasting month of ramadan coincides with the period concerned by summer time.
      +# Therefore, the standard time will be kept unchanged the whole year long."
      +# So foregoing DST seems to be an exception (albeit one that may be repeated in the  future).
      +
      +# From Alexander Krivenyshev (2010-03-27):
      +# According to some news reports Tunis confirmed not to use DST in 2010
      +#
      +# (translation):
      +# "The Tunisian government has decided to abandon DST, which was scheduled on
      +# Sunday...
      +# Tunisian authorities had suspended the DST for the first time last year also
      +# coincided with the month of Ramadan..."
      +#
      +# (in Arabic)
      +# 
      +# http://www.moheet.com/show_news.aspx?nid=358861&pg=1
      +# 
      +# http://www.almadenahnews.com/newss/news.php?c=118&id=38036
      +# or
      +# 
      +# http://www.worldtimezone.com/dst_news/dst_news_tunis02.html
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Tunisia	1939	only	-	Apr	15	23:00s	1:00	S
      +Rule	Tunisia	1939	only	-	Nov	18	23:00s	0	-
      +Rule	Tunisia	1940	only	-	Feb	25	23:00s	1:00	S
      +Rule	Tunisia	1941	only	-	Oct	 6	 0:00	0	-
      +Rule	Tunisia	1942	only	-	Mar	 9	 0:00	1:00	S
      +Rule	Tunisia	1942	only	-	Nov	 2	 3:00	0	-
      +Rule	Tunisia	1943	only	-	Mar	29	 2:00	1:00	S
      +Rule	Tunisia	1943	only	-	Apr	17	 2:00	0	-
      +Rule	Tunisia	1943	only	-	Apr	25	 2:00	1:00	S
      +Rule	Tunisia	1943	only	-	Oct	 4	 2:00	0	-
      +Rule	Tunisia	1944	1945	-	Apr	Mon>=1	 2:00	1:00	S
      +Rule	Tunisia	1944	only	-	Oct	 8	 0:00	0	-
      +Rule	Tunisia	1945	only	-	Sep	16	 0:00	0	-
      +Rule	Tunisia	1977	only	-	Apr	30	 0:00s	1:00	S
      +Rule	Tunisia	1977	only	-	Sep	24	 0:00s	0	-
      +Rule	Tunisia	1978	only	-	May	 1	 0:00s	1:00	S
      +Rule	Tunisia	1978	only	-	Oct	 1	 0:00s	0	-
      +Rule	Tunisia	1988	only	-	Jun	 1	 0:00s	1:00	S
      +Rule	Tunisia	1988	1990	-	Sep	lastSun	 0:00s	0	-
      +Rule	Tunisia	1989	only	-	Mar	26	 0:00s	1:00	S
      +Rule	Tunisia	1990	only	-	May	 1	 0:00s	1:00	S
      +Rule	Tunisia	2005	only	-	May	 1	 0:00s	1:00	S
      +Rule	Tunisia	2005	only	-	Sep	30	 1:00s	0	-
      +Rule	Tunisia	2006	2008	-	Mar	lastSun	 2:00s	1:00	S
      +Rule	Tunisia	2006	2008	-	Oct	lastSun	 2:00s	0	-
      +
      +# Shanks & Pottenger give 0:09:20 for Paris Mean Time; go with Howse's
      +# more precise 0:09:21.
      +# Shanks & Pottenger say the 1911 switch was on Mar 9; go with Howse's Mar 11.
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Tunis	0:40:44 -	LMT	1881 May 12
      +			0:09:21	-	PMT	1911 Mar 11    # Paris Mean Time
      +			1:00	Tunisia	CE%sT
      +
      +# Uganda
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Kampala	2:09:40 -	LMT	1928 Jul
      +			3:00	-	EAT	1930
      +			2:30	-	BEAT	1948
      +			2:45	-	BEAUT	1957
      +			3:00	-	EAT
      +
      +# Zambia
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Lusaka	1:53:08 -	LMT	1903 Mar
      +			2:00	-	CAT
      +
      +# Zimbabwe
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Africa/Harare	2:04:12 -	LMT	1903 Mar
      +			2:00	-	CAT
      diff --git a/jdk/test/sun/util/calendar/zi/tzdata/antarctica b/jdk/test/sun/util/calendar/zi/tzdata/antarctica
      new file mode 100644
      index 00000000000..64b71d5c052
      --- /dev/null
      +++ b/jdk/test/sun/util/calendar/zi/tzdata/antarctica
      @@ -0,0 +1,436 @@
      +#
      +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      +#  
      +# This code is free software; you can redistribute it and/or modify it
      +# under the terms of the GNU General Public License version 2 only, as
      +# published by the Free Software Foundation.  Oracle designates this
      +# particular file as subject to the "Classpath" exception as provided
      +# by Oracle in the LICENSE file that accompanied this code.
      +#  
      +# This code is distributed in the hope that it will be useful, but WITHOUT
      +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      +# version 2 for more details (a copy is included in the LICENSE file that
      +# accompanied this code).
      +#  
      +# You should have received a copy of the GNU General Public License version
      +# 2 along with this work; if not, write to the Free Software Foundation,
      +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      +#  
      +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      +# or visit www.oracle.com if you need additional information or have any
      +# questions.
      +#
      +# 
      +# This file is in the public domain, so clarified as of
      +# 2009-05-17 by Arthur David Olson.
      +
      +# From Paul Eggert (1999-11-15):
      +# To keep things manageable, we list only locations occupied year-round; see
      +# 
      +# COMNAP - Stations and Bases
      +# 
      +# and
      +# 
      +# Summary of the Peri-Antarctic Islands (1998-07-23)
      +# 
      +# for information.
      +# Unless otherwise specified, we have no time zone information.
      +#
      +# Except for the French entries,
      +# I made up all time zone abbreviations mentioned here; corrections welcome!
      +# FORMAT is `zzz' and GMTOFF is 0 for locations while uninhabited.
      +
      +# These rules are stolen from the `southamerica' file.
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	ArgAQ	1964	1966	-	Mar	 1	0:00	0	-
      +Rule	ArgAQ	1964	1966	-	Oct	15	0:00	1:00	S
      +Rule	ArgAQ	1967	only	-	Apr	 2	0:00	0	-
      +Rule	ArgAQ	1967	1968	-	Oct	Sun>=1	0:00	1:00	S
      +Rule	ArgAQ	1968	1969	-	Apr	Sun>=1	0:00	0	-
      +Rule	ArgAQ	1974	only	-	Jan	23	0:00	1:00	S
      +Rule	ArgAQ	1974	only	-	May	 1	0:00	0	-
      +Rule	ChileAQ	1972	1986	-	Mar	Sun>=9	3:00u	0	-
      +Rule	ChileAQ	1974	1987	-	Oct	Sun>=9	4:00u	1:00	S
      +Rule	ChileAQ	1987	only	-	Apr	12	3:00u	0	-
      +Rule	ChileAQ	1988	1989	-	Mar	Sun>=9	3:00u	0	-
      +Rule	ChileAQ	1988	only	-	Oct	Sun>=1	4:00u	1:00	S
      +Rule	ChileAQ	1989	only	-	Oct	Sun>=9	4:00u	1:00	S
      +Rule	ChileAQ	1990	only	-	Mar	18	3:00u	0	-
      +Rule	ChileAQ	1990	only	-	Sep	16	4:00u	1:00	S
      +Rule	ChileAQ	1991	1996	-	Mar	Sun>=9	3:00u	0	-
      +Rule	ChileAQ	1991	1997	-	Oct	Sun>=9	4:00u	1:00	S
      +Rule	ChileAQ	1997	only	-	Mar	30	3:00u	0	-
      +Rule	ChileAQ	1998	only	-	Mar	Sun>=9	3:00u	0	-
      +Rule	ChileAQ	1998	only	-	Sep	27	4:00u	1:00	S
      +Rule	ChileAQ	1999	only	-	Apr	 4	3:00u	0	-
      +Rule	ChileAQ	1999	2010	-	Oct	Sun>=9	4:00u	1:00	S
      +Rule	ChileAQ	2000	2007	-	Mar	Sun>=9	3:00u	0	-
      +# N.B.: the end of March 29 in Chile is March 30 in Universal time,
      +# which is used below in specifying the transition.
      +Rule	ChileAQ	2008	only	-	Mar	30	3:00u	0	-
      +Rule	ChileAQ	2009	only	-	Mar	Sun>=9	3:00u	0	-
      +Rule	ChileAQ	2010	only	-	Apr	Sun>=1	3:00u	0	-
      +Rule	ChileAQ	2011	only	-	May	Sun>=2	3:00u	0	-
      +Rule	ChileAQ	2011	only	-	Aug	Sun>=16	4:00u	1:00	S
      +Rule	ChileAQ	2012	only	-	Apr	Sun>=23	3:00u	0	-
      +Rule	ChileAQ	2012	only	-	Sep	Sun>=2	4:00u	1:00	S
      +Rule	ChileAQ	2013	max	-	Mar	Sun>=9	3:00u	0	-
      +Rule	ChileAQ	2013	max	-	Oct	Sun>=9	4:00u	1:00	S
      +
      +# These rules are stolen from the `australasia' file.
      +Rule	AusAQ	1917	only	-	Jan	 1	0:01	1:00	-
      +Rule	AusAQ	1917	only	-	Mar	25	2:00	0	-
      +Rule	AusAQ	1942	only	-	Jan	 1	2:00	1:00	-
      +Rule	AusAQ	1942	only	-	Mar	29	2:00	0	-
      +Rule	AusAQ	1942	only	-	Sep	27	2:00	1:00	-
      +Rule	AusAQ	1943	1944	-	Mar	lastSun	2:00	0	-
      +Rule	AusAQ	1943	only	-	Oct	 3	2:00	1:00	-
      +Rule	ATAQ	1967	only	-	Oct	Sun>=1	2:00s	1:00	-
      +Rule	ATAQ	1968	only	-	Mar	lastSun	2:00s	0	-
      +Rule	ATAQ	1968	1985	-	Oct	lastSun	2:00s	1:00	-
      +Rule	ATAQ	1969	1971	-	Mar	Sun>=8	2:00s	0	-
      +Rule	ATAQ	1972	only	-	Feb	lastSun	2:00s	0	-
      +Rule	ATAQ	1973	1981	-	Mar	Sun>=1	2:00s	0	-
      +Rule	ATAQ	1982	1983	-	Mar	lastSun	2:00s	0	-
      +Rule	ATAQ	1984	1986	-	Mar	Sun>=1	2:00s	0	-
      +Rule	ATAQ	1986	only	-	Oct	Sun>=15	2:00s	1:00	-
      +Rule	ATAQ	1987	1990	-	Mar	Sun>=15	2:00s	0	-
      +Rule	ATAQ	1987	only	-	Oct	Sun>=22	2:00s	1:00	-
      +Rule	ATAQ	1988	1990	-	Oct	lastSun	2:00s	1:00	-
      +Rule	ATAQ	1991	1999	-	Oct	Sun>=1	2:00s	1:00	-
      +Rule	ATAQ	1991	2005	-	Mar	lastSun	2:00s	0	-
      +Rule	ATAQ	2000	only	-	Aug	lastSun	2:00s	1:00	-
      +Rule	ATAQ	2001	max	-	Oct	Sun>=1	2:00s	1:00	-
      +Rule	ATAQ	2006	only	-	Apr	Sun>=1	2:00s	0	-
      +Rule	ATAQ	2007	only	-	Mar	lastSun	2:00s	0	-
      +Rule	ATAQ	2008	max	-	Apr	Sun>=1	2:00s	0	-
      +
      +# Argentina - year-round bases
      +# Belgrano II, Confin Coast, -770227-0343737, since 1972-02-05
      +# Esperanza, San Martin Land, -6323-05659, since 1952-12-17
      +# Jubany, Potter Peninsula, King George Island, -6414-0602320, since 1982-01
      +# Marambio, Seymour I, -6414-05637, since 1969-10-29
      +# Orcadas, Laurie I, -6016-04444, since 1904-02-22
      +# San Martin, Debenham I, -6807-06708, since 1951-03-21
      +#	(except 1960-03 / 1976-03-21)
      +
      +# Australia - territories
      +# Heard Island, McDonald Islands (uninhabited)
      +#	previously sealers and scientific personnel wintered
      +#	
      +#	Margaret Turner reports
      +#	 (1999-09-30) that they're UTC+5, with no DST;
      +#	presumably this is when they have visitors.
      +#
      +# year-round bases
      +# Casey, Bailey Peninsula, -6617+11032, since 1969
      +# Davis, Vestfold Hills, -6835+07759, since 1957-01-13
      +#	(except 1964-11 - 1969-02)
      +# Mawson, Holme Bay, -6736+06253, since 1954-02-13
      +
      +# From Steffen Thorsen (2009-03-11):
      +# Three Australian stations in Antarctica have changed their time zone:
      +# Casey moved from UTC+8 to UTC+11
      +# Davis moved from UTC+7 to UTC+5
      +# Mawson moved from UTC+6 to UTC+5
      +# The changes occurred on 2009-10-18 at 02:00 (local times).
      +#
      +# Government source: (Australian Antarctic Division)
      +# 
      +# http://www.aad.gov.au/default.asp?casid=37079
      +# 
      +#
      +# We have more background information here:
      +# 
      +# http://www.timeanddate.com/news/time/antarctica-new-times.html
      +# 
      +
      +# From Steffen Thorsen (2010-03-10):
      +# We got these changes from the Australian Antarctic Division:
      +# - Macquarie Island will stay on UTC+11 for winter and therefore not
      +# switch back from daylight savings time when other parts of Australia do
      +# on 4 April.
      +#
      +# - Casey station reverted to its normal time of UTC+8 on 5 March 2010.
      +# The change to UTC+11 is being considered as a regular summer thing but
      +# has not been decided yet.
      +#
      +# - Davis station will revert to its normal time of UTC+7 at 10 March 2010
      +# 20:00 UTC.
      +#
      +# - Mawson station stays on UTC+5.
      +#
      +# In addition to the Rule changes for Casey/Davis, it means that Macquarie
      +# will no longer be like Hobart and will have to have its own Zone created.
      +#
      +# Background:
      +# 
      +# http://www.timeanddate.com/news/time/antartica-time-changes-2010.html
      +# 
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Antarctica/Casey	0	-	zzz	1969
      +			8:00	-	WST	2009 Oct 18 2:00
      +						# Western (Aus) Standard Time
      +			11:00	-	CAST	2010 Mar 5 2:00
      +						# Casey Time
      +			8:00	-	WST	2011 Oct 28 2:00
      +			11:00	-	CAST	2012 Feb 21 17:00u
      +			8:00	-	WST
      +Zone Antarctica/Davis	0	-	zzz	1957 Jan 13
      +			7:00	-	DAVT	1964 Nov # Davis Time
      +			0	-	zzz	1969 Feb
      +			7:00	-	DAVT	2009 Oct 18 2:00
      +			5:00	-	DAVT	2010 Mar 10 20:00u
      +			7:00	-	DAVT	2011 Oct 28 2:00
      +			5:00	-	DAVT	2012 Feb 21 20:00u
      +			7:00	-	DAVT
      +Zone Antarctica/Mawson	0	-	zzz	1954 Feb 13
      +			6:00	-	MAWT	2009 Oct 18 2:00
      +						# Mawson Time
      +			5:00	-	MAWT
      +Zone Antarctica/Macquarie 0	-	zzz	1911
      +			10:00	-	EST	1916 Oct 1 2:00
      +			10:00	1:00	EST	1917 Feb
      +			10:00	AusAQ	EST	1967
      +			10:00	ATAQ	EST	2010 Apr 4 3:00
      +			11:00	-	MIST	# Macquarie Island Time
      +# References:
      +# 
      +# Casey Weather (1998-02-26)
      +# 
      +# 
      +# Davis Station, Antarctica (1998-02-26)
      +# 
      +# 
      +# Mawson Station, Antarctica (1998-02-25)
      +# 
      +
      +# Brazil - year-round base
      +# Comandante Ferraz, King George Island, -6205+05824, since 1983/4
      +
      +# Chile - year-round bases and towns
      +# Escudero, South Shetland Is, -621157-0585735, since 1994
      +# Presidente Eduadro Frei, King George Island, -6214-05848, since 1969-03-07
      +# General Bernardo O'Higgins, Antarctic Peninsula, -6319-05704, since 1948-02
      +# Capitan Arturo Prat, -6230-05941
      +# Villa Las Estrellas (a town), around the Frei base, since 1984-04-09
      +# These locations have always used Santiago time; use TZ='America/Santiago'.
      +
      +# China - year-round bases
      +# Great Wall, King George Island, -6213-05858, since 1985-02-20
      +# Zhongshan, Larsemann Hills, Prydz Bay, -6922+07623, since 1989-02-26
      +
      +# France - year-round bases
      +#
      +# From Antoine Leca (1997-01-20):
      +# Time data are from Nicole Pailleau at the IFRTP
      +# (French Institute for Polar Research and Technology).
      +# She confirms that French Southern Territories and Terre Adelie bases
      +# don't observe daylight saving time, even if Terre Adelie supplies came
      +# from Tasmania.
      +#
      +# French Southern Territories with year-round inhabitants
      +#
      +# Martin-de-Vivies Base, Amsterdam Island, -374105+0773155, since 1950
      +# Alfred-Faure Base, Crozet Islands, -462551+0515152, since 1964
      +# Port-aux-Francais, Kerguelen Islands, -492110+0701303, since 1951;
      +#	whaling & sealing station operated 1908/1914, 1920/1929, and 1951/1956
      +#
      +# St Paul Island - near Amsterdam, uninhabited
      +#	fishing stations operated variously 1819/1931
      +#
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Indian/Kerguelen	0	-	zzz	1950	# Port-aux-Francais
      +			5:00	-	TFT	# ISO code TF Time
      +#
      +# year-round base in the main continent
      +# Dumont-d'Urville, Ile des Petrels, -6640+14001, since 1956-11
      +#
      +# Another base at Port-Martin, 50km east, began operation in 1947.
      +# It was destroyed by fire on 1952-01-14.
      +#
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Antarctica/DumontDUrville 0 -	zzz	1947
      +			10:00	-	PMT	1952 Jan 14 # Port-Martin Time
      +			0	-	zzz	1956 Nov
      +			10:00	-	DDUT	# Dumont-d'Urville Time
      +# Reference:
      +# 
      +# Dumont d'Urville Station (2005-12-05)
      +# 
      +
      +# Germany - year-round base
      +# Georg von Neumayer, -7039-00815
      +
      +# India - year-round base
      +# Dakshin Gangotri, -7005+01200
      +
      +# Japan - year-round bases
      +# Dome Fuji, -7719+03942
      +# Syowa, -690022+0393524
      +#
      +# From Hideyuki Suzuki (1999-02-06):
      +# In all Japanese stations, +0300 is used as the standard time.
      +#
      +# Syowa station, which is the first antarctic station of Japan,
      +# was established on 1957-01-29.  Since Syowa station is still the main
      +# station of Japan, it's appropriate for the principal location.
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Antarctica/Syowa	0	-	zzz	1957 Jan 29
      +			3:00	-	SYOT	# Syowa Time
      +# See:
      +# 
      +# NIPR Antarctic Research Activities (1999-08-17)
      +# 
      +
      +# S Korea - year-round base
      +# King Sejong, King George Island, -6213-05847, since 1988
      +
      +# New Zealand - claims
      +# Balleny Islands (never inhabited)
      +# Scott Island (never inhabited)
      +#
      +# year-round base
      +# Scott, Ross Island, since 1957-01, is like Antarctica/McMurdo.
      +#
      +# These rules for New Zealand are stolen from the `australasia' file.
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	NZAQ	1974	only	-	Nov	 3	2:00s	1:00	D
      +Rule	NZAQ	1975	1988	-	Oct	lastSun	2:00s	1:00	D
      +Rule	NZAQ	1989	only	-	Oct	 8	2:00s	1:00	D
      +Rule	NZAQ	1990	2006	-	Oct	Sun>=1	2:00s	1:00	D
      +Rule	NZAQ	1975	only	-	Feb	23	2:00s	0	S
      +Rule	NZAQ	1976	1989	-	Mar	Sun>=1	2:00s	0	S
      +Rule	NZAQ	1990	2007	-	Mar	Sun>=15	2:00s	0	S
      +Rule	NZAQ	2007	max	-	Sep	lastSun	2:00s	1:00	D
      +Rule	NZAQ	2008	max	-	Apr	Sun>=1	2:00s	0	S
      +
      +# Norway - territories
      +# Bouvet (never inhabited)
      +#
      +# claims
      +# Peter I Island (never inhabited)
      +
      +# Poland - year-round base
      +# Arctowski, King George Island, -620945-0582745, since 1977
      +
      +# Russia - year-round bases
      +# Bellingshausen, King George Island, -621159-0585337, since 1968-02-22
      +# Mirny, Davis coast, -6633+09301, since 1956-02
      +# Molodezhnaya, Alasheyev Bay, -6740+04551,
      +#	year-round from 1962-02 to 1999-07-01
      +# Novolazarevskaya, Queen Maud Land, -7046+01150,
      +#	year-round from 1960/61 to 1992
      +
      +# Vostok, since 1957-12-16, temporarily closed 1994-02/1994-11
      +# 
      +# From Craig Mundell (1994-12-15):
      +# Vostok, which is one of the Russian stations, is set on the same
      +# time as Moscow, Russia.
      +#
      +# From Lee Hotz (2001-03-08):
      +# I queried the folks at Columbia who spent the summer at Vostok and this is
      +# what they had to say about time there:
      +# ``in the US Camp (East Camp) we have been on New Zealand (McMurdo)
      +# time, which is 12 hours ahead of GMT. The Russian Station Vostok was
      +# 6 hours behind that (although only 2 miles away, i.e. 6 hours ahead
      +# of GMT). This is a time zone I think two hours east of Moscow. The
      +# natural time zone is in between the two: 8 hours ahead of GMT.''
      +#
      +# From Paul Eggert (2001-05-04):
      +# This seems to be hopelessly confusing, so I asked Lee Hotz about it
      +# in person.  He said that some Antartic locations set their local
      +# time so that noon is the warmest part of the day, and that this
      +# changes during the year and does not necessarily correspond to mean
      +# solar noon.  So the Vostok time might have been whatever the clocks
      +# happened to be during their visit.  So we still don't really know what time
      +# it is at Vostok.  But we'll guess UTC+6.
      +#
      +Zone Antarctica/Vostok	0	-	zzz	1957 Dec 16
      +			6:00	-	VOST	# Vostok time
      +
      +# S Africa - year-round bases
      +# Marion Island, -4653+03752
      +# Sanae, -7141-00250
      +
      +# UK
      +#
      +# British Antarctic Territories (BAT) claims
      +# South Orkney Islands
      +#	scientific station from 1903
      +#	whaling station at Signy I 1920/1926
      +# South Shetland Islands
      +#
      +# year-round bases
      +# Bird Island, South Georgia, -5400-03803, since 1983
      +# Deception Island, -6259-06034, whaling station 1912/1931,
      +#	scientific station 1943/1967,
      +#	previously sealers and a scientific expedition wintered by accident,
      +#	and a garrison was deployed briefly
      +# Halley, Coates Land, -7535-02604, since 1956-01-06
      +#	Halley is on a moving ice shelf and is periodically relocated
      +#	so that it is never more than 10km from its nominal location.
      +# Rothera, Adelaide Island, -6734-6808, since 1976-12-01
      +#
      +# From Paul Eggert (2002-10-22)
      +#  says Rothera is -03 all year.
      +#
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Antarctica/Rothera	0	-	zzz	1976 Dec  1
      +			-3:00	-	ROTT	# Rothera time
      +
      +# Uruguay - year round base
      +# Artigas, King George Island, -621104-0585107
      +
      +# USA - year-round bases
      +#
      +# Palmer, Anvers Island, since 1965 (moved 2 miles in 1968)
      +#
      +# From Ethan Dicks (1996-10-06):
      +# It keeps the same time as Punta Arenas, Chile, because, just like us
      +# and the South Pole, that's the other end of their supply line....
      +# I verified with someone who was there that since 1980,
      +# Palmer has followed Chile.  Prior to that, before the Falklands War,
      +# Palmer used to be supplied from Argentina.
      +#
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Antarctica/Palmer	0	-	zzz	1965
      +			-4:00	ArgAQ	AR%sT	1969 Oct 5
      +			-3:00	ArgAQ	AR%sT	1982 May
      +			-4:00	ChileAQ	CL%sT
      +#
      +#
      +# McMurdo, Ross Island, since 1955-12
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Antarctica/McMurdo	0	-	zzz	1956
      +			12:00	NZAQ	NZ%sT
      +#
      +# Amundsen-Scott, South Pole, continuously occupied since 1956-11-20
      +#
      +# From Paul Eggert (1996-09-03):
      +# Normally it wouldn't have a separate entry, since it's like the
      +# larger Antarctica/McMurdo since 1970, but it's too famous to omit.
      +#
      +# From Chris Carrier (1996-06-27):
      +# Siple, the first commander of the South Pole station,
      +# stated that he would have liked to have kept GMT at the station,
      +# but that he found it more convenient to keep GMT+12
      +# as supplies for the station were coming from McMurdo Sound,
      +# which was on GMT+12 because New Zealand was on GMT+12 all year
      +# at that time (1957).  (Source: Siple's book 90 degrees SOUTH.)
      +#
      +# From Susan Smith
      +# http://www.cybertours.com/whs/pole10.html
      +# (1995-11-13 16:24:56 +1300, no longer available):
      +# We use the same time as McMurdo does.
      +# And they use the same time as Christchurch, NZ does....
      +# One last quirk about South Pole time.
      +# All the electric clocks are usually wrong.
      +# Something about the generators running at 60.1hertz or something
      +# makes all of the clocks run fast.  So every couple of days,
      +# we have to go around and set them back 5 minutes or so.
      +# Maybe if we let them run fast all of the time, we'd get to leave here sooner!!
      +#
      +Link	Antarctica/McMurdo	Antarctica/South_Pole
      diff --git a/jdk/test/sun/util/calendar/zi/tzdata/asia b/jdk/test/sun/util/calendar/zi/tzdata/asia
      new file mode 100644
      index 00000000000..9ef3ef8df54
      --- /dev/null
      +++ b/jdk/test/sun/util/calendar/zi/tzdata/asia
      @@ -0,0 +1,2738 @@
      +#
      +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      +#  
      +# This code is free software; you can redistribute it and/or modify it
      +# under the terms of the GNU General Public License version 2 only, as
      +# published by the Free Software Foundation.  Oracle designates this
      +# particular file as subject to the "Classpath" exception as provided
      +# by Oracle in the LICENSE file that accompanied this code.
      +#  
      +# This code is distributed in the hope that it will be useful, but WITHOUT
      +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      +# version 2 for more details (a copy is included in the LICENSE file that
      +# accompanied this code).
      +#  
      +# You should have received a copy of the GNU General Public License version
      +# 2 along with this work; if not, write to the Free Software Foundation,
      +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      +#  
      +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      +# or visit www.oracle.com if you need additional information or have any
      +# questions.
      +#
      +# 
      +# This file is in the public domain, so clarified as of
      +# 2009-05-17 by Arthur David Olson.
      +
      +# This data is by no means authoritative; if you think you know better,
      +# go ahead and edit the file (and please send any changes to
      +# tz@elsie.nci.nih.gov for general use in the future).
      +
      +# From Paul Eggert (2006-03-22):
      +#
      +# A good source for time zone historical data outside the U.S. is
      +# Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition),
      +# San Diego: ACS Publications, Inc. (2003).
      +#
      +# Gwillim Law writes that a good source
      +# for recent time zone data is the International Air Transport
      +# Association's Standard Schedules Information Manual (IATA SSIM),
      +# published semiannually.  Law sent in several helpful summaries
      +# of the IATA's data after 1990.
      +#
      +# Except where otherwise noted, Shanks & Pottenger is the source for
      +# entries through 1990, and IATA SSIM is the source for entries afterwards.
      +#
      +# Another source occasionally used is Edward W. Whitman, World Time Differences,
      +# Whitman Publishing Co, 2 Niagara Av, Ealing, London (undated), which
      +# I found in the UCLA library.
      +#
      +# A reliable and entertaining source about time zones is
      +# Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
      +#
      +# I invented the abbreviations marked `*' in the following table;
      +# the rest are from earlier versions of this file, or from other sources.
      +# Corrections are welcome!
      +#	     std  dst
      +#	     LMT	Local Mean Time
      +#	2:00 EET  EEST	Eastern European Time
      +#	2:00 IST  IDT	Israel
      +#	3:00 AST  ADT	Arabia*
      +#	3:30 IRST IRDT	Iran
      +#	4:00 GST	Gulf*
      +#	5:30 IST	India
      +#	7:00 ICT	Indochina*
      +#	7:00 WIT	west Indonesia
      +#	8:00 CIT	central Indonesia
      +#	8:00 CST	China
      +#	9:00 CJT	Central Japanese Time (1896/1937)*
      +#	9:00 EIT	east Indonesia
      +#	9:00 JST  JDT	Japan
      +#	9:00 KST  KDT	Korea
      +#	9:30 CST	(Australian) Central Standard Time
      +#
      +# See the `europe' file for Russia and Turkey in Asia.
      +
      +# From Guy Harris:
      +# Incorporates data for Singapore from Robert Elz' asia 1.1, as well as
      +# additional information from Tom Yap, Sun Microsystems Intercontinental
      +# Technical Support (including a page from the Official Airline Guide -
      +# Worldwide Edition).  The names for time zones are guesses.
      +
      +###############################################################################
      +
      +# These rules are stolen from the `europe' file.
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	EUAsia	1981	max	-	Mar	lastSun	 1:00u	1:00	S
      +Rule	EUAsia	1979	1995	-	Sep	lastSun	 1:00u	0	-
      +Rule	EUAsia	1996	max	-	Oct	lastSun	 1:00u	0	-
      +Rule E-EurAsia	1981	max	-	Mar	lastSun	 0:00	1:00	S
      +Rule E-EurAsia	1979	1995	-	Sep	lastSun	 0:00	0	-
      +Rule E-EurAsia	1996	max	-	Oct	lastSun	 0:00	0	-
      +Rule RussiaAsia	1981	1984	-	Apr	1	 0:00	1:00	S
      +Rule RussiaAsia	1981	1983	-	Oct	1	 0:00	0	-
      +Rule RussiaAsia	1984	1991	-	Sep	lastSun	 2:00s	0	-
      +Rule RussiaAsia	1985	1991	-	Mar	lastSun	 2:00s	1:00	S
      +Rule RussiaAsia	1992	only	-	Mar	lastSat	23:00	1:00	S
      +Rule RussiaAsia	1992	only	-	Sep	lastSat	23:00	0	-
      +Rule RussiaAsia	1993	max	-	Mar	lastSun	 2:00s	1:00	S
      +Rule RussiaAsia	1993	1995	-	Sep	lastSun	 2:00s	0	-
      +Rule RussiaAsia	1996	max	-	Oct	lastSun	 2:00s	0	-
      +
      +# Afghanistan
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Kabul	4:36:48 -	LMT	1890
      +			4:00	-	AFT	1945
      +			4:30	-	AFT
      +
      +# Armenia
      +# From Paul Eggert (2006-03-22):
      +# Shanks & Pottenger have Yerevan switching to 3:00 (with Russian DST)
      +# in spring 1991, then to 4:00 with no DST in fall 1995, then
      +# readopting Russian DST in 1997.  Go with Shanks & Pottenger, even
      +# when they disagree with others.  Edgar Der-Danieliantz
      +# reported (1996-05-04) that Yerevan probably wouldn't use DST
      +# in 1996, though it did use DST in 1995.  IATA SSIM (1991/1998) reports that
      +# Armenia switched from 3:00 to 4:00 in 1998 and observed DST after 1991,
      +# but started switching at 3:00s in 1998.
      +
      +# From Arthur David Olson (2011-06-15):
      +# While Russia abandoned DST in 2011, Armenia may choose to
      +# follow Russia's "old" rules.
      +
      +# From Alexander Krivenyshev (2012-02-10):
      +# According to News Armenia, on Feb 9, 2012,
      +# http://newsarmenia.ru/society/20120209/42609695.html
      +#
      +# The Armenia National Assembly adopted final reading of Amendments to the
      +# Law "On procedure of calculation time on the territory of the Republic of
      +# Armenia" according to which Armenia [is] abolishing Daylight Saving Time.
      +# or
      +# (brief)
      +# http://www.worldtimezone.com/dst_news/dst_news_armenia03.html
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Yerevan	2:58:00 -	LMT	1924 May  2
      +			3:00	-	YERT	1957 Mar    # Yerevan Time
      +			4:00 RussiaAsia YER%sT	1991 Mar 31 2:00s
      +			3:00	1:00	YERST	1991 Sep 23 # independence
      +			3:00 RussiaAsia	AM%sT	1995 Sep 24 2:00s
      +			4:00	-	AMT	1997
      +			4:00 RussiaAsia	AM%sT	2012 Mar 25 2:00s
      +			4:00	-	AMT
      +
      +# Azerbaijan
      +# From Rustam Aliyev of the Azerbaijan Internet Forum (2005-10-23):
      +# According to the resolution of Cabinet of Ministers, 1997
      +# Resolution available at: http://aif.az/docs/daylight_res.pdf
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Azer	1997	max	-	Mar	lastSun	 4:00	1:00	S
      +Rule	Azer	1997	max	-	Oct	lastSun	 5:00	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Baku	3:19:24 -	LMT	1924 May  2
      +			3:00	-	BAKT	1957 Mar    # Baku Time
      +			4:00 RussiaAsia BAK%sT	1991 Mar 31 2:00s
      +			3:00	1:00	BAKST	1991 Aug 30 # independence
      +			3:00 RussiaAsia	AZ%sT	1992 Sep lastSat 23:00
      +			4:00	-	AZT	1996 # Azerbaijan time
      +			4:00	EUAsia	AZ%sT	1997
      +			4:00	Azer	AZ%sT
      +
      +# Bahrain
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Bahrain	3:22:20 -	LMT	1920		# Al Manamah
      +			4:00	-	GST	1972 Jun
      +			3:00	-	AST
      +
      +# Bangladesh
      +# From Alexander Krivenyshev (2009-05-13):
      +# According to newspaper Asian Tribune (May 6, 2009) Bangladesh may introduce
      +# Daylight Saving Time from June 16 to Sept 30
      +#
      +# Bangladesh to introduce daylight saving time likely from June 16
      +# 
      +# http://www.asiantribune.com/?q=node/17288
      +# 
      +# or
      +# 
      +# http://www.worldtimezone.com/dst_news/dst_news_bangladesh02.html
      +# 
      +#
      +# "... Bangladesh government has decided to switch daylight saving time from
      +# June
      +# 16 till September 30 in a bid to ensure maximum use of daylight to cope with
      +# crippling power crisis. "
      +#
      +# The switch will remain in effect from June 16 to Sept 30 (2009) but if
      +# implemented the next year, it will come in force from April 1, 2010
      +
      +# From Steffen Thorsen (2009-06-02):
      +# They have finally decided now, but changed the start date to midnight between
      +# the 19th and 20th, and they have not set the end date yet.
      +#
      +# Some sources:
      +# 
      +# http://in.reuters.com/article/southAsiaNews/idINIndia-40017620090601
      +# 
      +# 
      +# http://bdnews24.com/details.php?id=85889&cid=2
      +# 
      +#
      +# Our wrap-up:
      +# 
      +# http://www.timeanddate.com/news/time/bangladesh-daylight-saving-2009.html
      +# 
      +
      +# From A. N. M. Kamrus Saadat (2009-06-15):
      +# Finally we've got the official mail regarding DST start time where DST start
      +# time is mentioned as Jun 19 2009, 23:00 from BTRC (Bangladesh
      +# Telecommunication Regulatory Commission).
      +#
      +# No DST end date has been announced yet.
      +
      +# From Alexander Krivenyshev (2009-09-25):
      +# Bangladesh won't go back to Standard Time from October 1, 2009,
      +# instead it will continue DST measure till the cabinet makes a fresh decision.
      +#
      +# Following report by same newspaper-"The Daily Star Friday":
      +# "DST change awaits cabinet decision-Clock won't go back by 1-hr from Oct 1"
      +# 
      +# http://www.thedailystar.net/newDesign/news-details.php?nid=107021
      +# 
      +# or
      +# 
      +# http://www.worldtimezone.com/dst_news/dst_news_bangladesh04.html
      +# 
      +
      +# From Steffen Thorsen (2009-10-13):
      +# IANS (Indo-Asian News Service) now reports:
      +# Bangladesh has decided that the clock advanced by an hour to make
      +# maximum use of daylight hours as an energy saving measure would
      +# "continue for an indefinite period."
      +#
      +# One of many places where it is published:
      +# 
      +# http://www.thaindian.com/newsportal/business/bangladesh-to-continue-indefinitely-with-advanced-time_100259987.html
      +# 
      +
      +# From Alexander Krivenyshev (2009-12-24):
      +# According to Bangladesh newspaper "The Daily Star,"
      +# Bangladesh will change its clock back to Standard Time on Dec 31, 2009.
      +#
      +# Clock goes back 1-hr on Dec 31 night.
      +# 
      +# http://www.thedailystar.net/newDesign/news-details.php?nid=119228
      +# 
      +# and
      +# 
      +# http://www.worldtimezone.com/dst_news/dst_news_bangladesh05.html
      +# 
      +#
      +# "...The government yesterday decided to put the clock back by one hour
      +# on December 31 midnight and the new time will continue until March 31,
      +# 2010 midnight. The decision came at a cabinet meeting at the Prime
      +# Minister's Office last night..."
      +
      +# From Alexander Krivenyshev (2010-03-22):
      +# According to Bangladesh newspaper "The Daily Star,"
      +# Cabinet cancels Daylight Saving Time
      +# 
      +# http://www.thedailystar.net/newDesign/latest_news.php?nid=22817
      +# 
      +# or
      +# 
      +# http://www.worldtimezone.com/dst_news/dst_news_bangladesh06.html
      +# 
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Dhaka	2009	only	-	Jun	19	23:00	1:00	S
      +Rule	Dhaka	2009	only	-	Dec	31	23:59	0	-
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Dhaka	6:01:40 -	LMT	1890
      +			5:53:20	-	HMT	1941 Oct    # Howrah Mean Time?
      +			6:30	-	BURT	1942 May 15 # Burma Time
      +			5:30	-	IST	1942 Sep
      +			6:30	-	BURT	1951 Sep 30
      +			6:00	-	DACT	1971 Mar 26 # Dacca Time
      +			6:00	-	BDT	2009
      +			6:00	Dhaka	BD%sT
      +
      +# Bhutan
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Thimphu	5:58:36 -	LMT	1947 Aug 15 # or Thimbu
      +			5:30	-	IST	1987 Oct
      +			6:00	-	BTT	# Bhutan Time
      +
      +# British Indian Ocean Territory
      +# Whitman and the 1995 CIA time zone map say 5:00, but the
      +# 1997 and later maps say 6:00.  Assume the switch occurred in 1996.
      +# We have no information as to when standard time was introduced;
      +# assume it occurred in 1907, the same year as Mauritius (which
      +# then contained the Chagos Archipelago).
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Indian/Chagos	4:49:40	-	LMT	1907
      +			5:00	-	IOT	1996 # BIOT Time
      +			6:00	-	IOT
      +
      +# Brunei
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Brunei	7:39:40 -	LMT	1926 Mar   # Bandar Seri Begawan
      +			7:30	-	BNT	1933
      +			8:00	-	BNT
      +
      +# Burma / Myanmar
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Rangoon	6:24:40 -	LMT	1880		# or Yangon
      +			6:24:36	-	RMT	1920	   # Rangoon Mean Time?
      +			6:30	-	BURT	1942 May   # Burma Time
      +			9:00	-	JST	1945 May 3
      +			6:30	-	MMT		   # Myanmar Time
      +
      +# Cambodia
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Phnom_Penh	6:59:40 -	LMT	1906 Jun  9
      +			7:06:20	-	SMT	1911 Mar 11 0:01 # Saigon MT?
      +			7:00	-	ICT	1912 May
      +			8:00	-	ICT	1931 May
      +			7:00	-	ICT
      +
      +# China
      +
      +# From Guy Harris:
      +# People's Republic of China.  Yes, they really have only one time zone.
      +
      +# From Bob Devine (1988-01-28):
      +# No they don't.  See TIME mag, 1986-02-17 p.52.  Even though
      +# China is across 4 physical time zones, before Feb 1, 1986 only the
      +# Peking (Bejing) time zone was recognized.  Since that date, China
      +# has two of 'em -- Peking's and Urumqi (named after the capital of
      +# the Xinjiang Uyghur Autonomous Region).  I don't know about DST for it.
      +#
      +# . . .I just deleted the DST table and this editor makes it too
      +# painful to suck in another copy..  So, here is what I have for
      +# DST start/end dates for Peking's time zone (info from AP):
      +#
      +#     1986 May 4 - Sept 14
      +#     1987 mid-April - ??
      +
      +# From U. S. Naval Observatory (1989-01-19):
      +# CHINA               8 H  AHEAD OF UTC  ALL OF CHINA, INCL TAIWAN
      +# CHINA               9 H  AHEAD OF UTC  APR 17 - SEP 10
      +
      +# From Paul Eggert (2006-03-22):
      +# Shanks & Pottenger write that China (except for Hong Kong and Macau)
      +# has had a single time zone since 1980 May 1, observing summer DST
      +# from 1986 through 1991; this contradicts Devine's
      +# note about Time magazine, though apparently _something_ happened in 1986.
      +# Go with Shanks & Pottenger for now.  I made up names for the other
      +# pre-1980 time zones.
      +
      +# From Shanks & Pottenger:
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Shang	1940	only	-	Jun	 3	0:00	1:00	D
      +Rule	Shang	1940	1941	-	Oct	 1	0:00	0	S
      +Rule	Shang	1941	only	-	Mar	16	0:00	1:00	D
      +Rule	PRC	1986	only	-	May	 4	0:00	1:00	D
      +Rule	PRC	1986	1991	-	Sep	Sun>=11	0:00	0	S
      +Rule	PRC	1987	1991	-	Apr	Sun>=10	0:00	1:00	D
      +
      +# From Anthony Fok (2001-12-20):
      +# BTW, I did some research on-line and found some info regarding these five
      +# historic timezones from some Taiwan websites.  And yes, there are official
      +# Chinese names for these locales (before 1949).
      +#
      +# From Jesper Norgaard Welen (2006-07-14):
      +# I have investigated the timezones around 1970 on the
      +# http://www.astro.com/atlas site [with provinces and county
      +# boundaries summarized below]....  A few other exceptions were two
      +# counties on the Sichuan side of the Xizang-Sichuan border,
      +# counties Dege and Baiyu which lies on the Sichuan side and are
      +# therefore supposed to be GMT+7, Xizang region being GMT+6, but Dege
      +# county is GMT+8 according to astro.com while Baiyu county is GMT+6
      +# (could be true), for the moment I am assuming that those two
      +# counties are mistakes in the astro.com data.
      +
      +# From Paul Eggert (2008-02-11):
      +# I just now checked Google News for western news sources that talk
      +# about China's single time zone, and couldn't find anything before 1986
      +# talking about China being in one time zone.  (That article was: Jim
      +# Mann, "A clumsy embrace for another western custom: China on daylight
      +# time--sort of", Los Angeles Times, 1986-05-05.  By the way, this
      +# article confirms the tz database's data claiming that China began
      +# observing daylight saving time in 1986.
      +#
      +# From Thomas S. Mullaney (2008-02-11):
      +# I think you're combining two subjects that need to treated
      +# separately: daylight savings (which, you're correct, wasn't
      +# implemented until the 1980s) and the unified time zone centered near
      +# Beijing (which was implemented in 1949). Briefly, there was also a
      +# "Lhasa Time" in Tibet and "Urumqi Time" in Xinjiang. The first was
      +# ceased, and the second eventually recognized (again, in the 1980s).
      +#
      +# From Paul Eggert (2008-06-30):
      +# There seems to be a good chance China switched to a single time zone in 1949
      +# rather than in 1980 as Shanks & Pottenger have it, but we don't have a
      +# reliable documentary source saying so yet, so for now we still go with
      +# Shanks & Pottenger.
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +# Changbai Time ("Long-white Time", Long-white = Heilongjiang area)
      +# Heilongjiang (except Mohe county), Jilin
      +Zone	Asia/Harbin	8:26:44	-	LMT	1928 # or Haerbin
      +			8:30	-	CHAT	1932 Mar # Changbai Time
      +			8:00	-	CST	1940
      +			9:00	-	CHAT	1966 May
      +			8:30	-	CHAT	1980 May
      +			8:00	PRC	C%sT
      +# Zhongyuan Time ("Central plain Time")
      +# most of China
      +Zone	Asia/Shanghai	8:05:52	-	LMT	1928
      +			8:00	Shang	C%sT	1949
      +			8:00	PRC	C%sT
      +# Long-shu Time (probably due to Long and Shu being two names of that area)
      +# Guangxi, Guizhou, Hainan, Ningxia, Sichuan, Shaanxi, and Yunnan;
      +# most of Gansu; west Inner Mongolia; west Qinghai; and the Guangdong
      +# counties Deqing, Enping, Kaiping, Luoding, Taishan, Xinxing,
      +# Yangchun, Yangjiang, Yu'nan, and Yunfu.
      +Zone	Asia/Chongqing	7:06:20	-	LMT	1928 # or Chungking
      +			7:00	-	LONT	1980 May # Long-shu Time
      +			8:00	PRC	C%sT
      +# Xin-zang Time ("Xinjiang-Tibet Time")
      +# The Gansu counties Aksay, Anxi, Dunhuang, Subei; west Qinghai;
      +# the Guangdong counties  Xuwen, Haikang, Suixi, Lianjiang,
      +# Zhanjiang, Wuchuan, Huazhou, Gaozhou, Maoming, Dianbai, and Xinyi;
      +# east Tibet, including Lhasa, Chamdo, Shigaise, Jimsar, Shawan and Hutubi;
      +# east Xinjiang, including Urumqi, Turpan, Karamay, Korla, Minfeng, Jinghe,
      +# Wusu, Qiemo, Xinyan, Wulanwusu, Jinghe, Yumin, Tacheng, Tuoli, Emin,
      +# Shihezi, Changji, Yanqi, Heshuo, Tuokexun, Tulufan, Shanshan, Hami,
      +# Fukang, Kuitun, Kumukuli, Miquan, Qitai, and Turfan.
      +Zone	Asia/Urumqi	5:50:20	-	LMT	1928 # or Urumchi
      +			6:00	-	URUT	1980 May # Urumqi Time
      +			8:00	PRC	C%sT
      +# Kunlun Time
      +# West Tibet, including Pulan, Aheqi, Shufu, Shule;
      +# West Xinjiang, including Aksu, Atushi, Yining, Hetian, Cele, Luopu, Nileke,
      +# Zhaosu, Tekesi, Gongliu, Chabuchaer, Huocheng, Bole, Pishan, Suiding,
      +# and Yarkand.
      +
      +# From Luther Ma (2009-10-17):
      +# Almost all (>99.9%) ethnic Chinese (properly ethnic Han) living in
      +# Xinjiang use Chinese Standard Time. Some are aware of Xinjiang time,
      +# but have no need of it. All planes, trains, and schools function on
      +# what is called "Beijing time." When Han make an appointment in Chinese
      +# they implicitly use Beijing time.
      +#
      +# On the other hand, ethnic Uyghurs, who make up about half the
      +# population of Xinjiang, typically use "Xinjiang time" which is two
      +# hours behind Beijing time, or UTC +0600. The government of the Xinjiang
      +# Uyghur Autonomous Region, (XAUR, or just Xinjiang for short) as well as
      +# local governments such as the Urumqi city government use both times in
      +# publications, referring to what is popularly called Xinjiang time as
      +# "Urumqi time." When Uyghurs make an appointment in the Uyghur language
      +# they almost invariably use Xinjiang time.
      +#
      +# (Their ethnic Han compatriots would typically have no clue of its
      +# widespread use, however, because so extremely few of them are fluent in
      +# Uyghur, comparable to the number of Anglo-Americans fluent in Navajo.)
      +#
      +# (...As with the rest of China there was a brief interval ending in 1990
      +# or 1991 when summer time was in use.  The confusion was severe, with
      +# the province not having dual times but four times in use at the same
      +# time. Some areas remained on standard Xinjiang time or Beijing time and
      +# others moving their clocks ahead.)
      +#
      +# ...an example of an official website using of Urumqi time.
      +#
      +# The first few lines of the Google translation of
      +# 
      +# http://www.fjysgl.gov.cn/show.aspx?id=2379&cid=39
      +# 
      +# (retrieved 2009-10-13)
      +# > Urumqi fire seven people are missing the alleged losses of at least
      +# > 500 million yuan
      +# >
      +# > (Reporter Dong Liu) the day before 20:20 or so (Urumqi Time 18:20),
      +# > Urumqi City Department of International Plaza Luther Qiantang River
      +# > burst fire. As of yesterday, 18:30, Urumqi City Fire officers and men
      +# > have worked continuously for 22 hours...
      +
      +# From Luther Ma (2009-11-19):
      +# With the risk of being redundant to previous answers these are the most common
      +# English "transliterations" (w/o using non-English symbols):
      +#
      +# 1. Wulumuqi...
      +# 2. Kashi...
      +# 3. Urumqi...
      +# 4. Kashgar...
      +# ...
      +# 5. It seems that Uyghurs in Urumqi has been using Xinjiang since at least the
      +# 1960's. I know of one Han, now over 50, who grew up in the surrounding
      +# countryside and used Xinjiang time as a child.
      +#
      +# 6. Likewise for Kashgar and the rest of south Xinjiang I don't know of any
      +# start date for Xinjiang time.
      +#
      +# Without having access to local historical records, nor the ability to legally
      +# publish them, I would go with October 1, 1949, when Xinjiang became the Uyghur
      +# Autonomous Region under the PRC. (Before that Uyghurs, of course, would also
      +# not be using Beijing time, but some local time.)
      +
      +Zone	Asia/Kashgar	5:03:56	-	LMT	1928 # or Kashi or Kaxgar
      +			5:30	-	KAST	1940	 # Kashgar Time
      +			5:00	-	KAST	1980 May
      +			8:00	PRC	C%sT
      +
      +
      +# From Lee Yiu Chung (2009-10-24):
      +# I found there are some mistakes for the...DST rule for Hong
      +# Kong. [According] to the DST record from Hong Kong Observatory (actually,
      +# it is not [an] observatory, but the official meteorological agency of HK,
      +# and also serves as the official timing agency), there are some missing
      +# and incorrect rules. Although the exact switch over time is missing, I
      +# think 3:30 is correct. The official DST record for Hong Kong can be
      +# obtained from
      +# 
      +# http://www.hko.gov.hk/gts/time/Summertime.htm
      +# .
      +
      +# From Arthur David Olson (2009-10-28):
      +# Here are the dates given at
      +# 
      +# http://www.hko.gov.hk/gts/time/Summertime.htm
      +# 
      +# as of 2009-10-28:
      +# Year        Period
      +# 1941        1 Apr to 30 Sep
      +# 1942        Whole year
      +# 1943        Whole year
      +# 1944        Whole year
      +# 1945        Whole year
      +# 1946        20 Apr to 1 Dec
      +# 1947        13 Apr to 30 Dec
      +# 1948        2 May to 31 Oct
      +# 1949        3 Apr to 30 Oct
      +# 1950        2 Apr to 29 Oct
      +# 1951        1 Apr to 28 Oct
      +# 1952        6 Apr to 25 Oct
      +# 1953        5 Apr to 1 Nov
      +# 1954        21 Mar to 31 Oct
      +# 1955        20 Mar to 6 Nov
      +# 1956        18 Mar to 4 Nov
      +# 1957        24 Mar to 3 Nov
      +# 1958        23 Mar to 2 Nov
      +# 1959        22 Mar to 1 Nov
      +# 1960        20 Mar to 6 Nov
      +# 1961        19 Mar to 5 Nov
      +# 1962        18 Mar to 4 Nov
      +# 1963        24 Mar to 3 Nov
      +# 1964        22 Mar to 1 Nov
      +# 1965        18 Apr to 17 Oct
      +# 1966        17 Apr to 16 Oct
      +# 1967        16 Apr to 22 Oct
      +# 1968        21 Apr to 20 Oct
      +# 1969        20 Apr to 19 Oct
      +# 1970        19 Apr to 18 Oct
      +# 1971        18 Apr to 17 Oct
      +# 1972        16 Apr to 22 Oct
      +# 1973        22 Apr to 21 Oct
      +# 1973/74     30 Dec 73 to 20 Oct 74
      +# 1975        20 Apr to 19 Oct
      +# 1976        18 Apr to 17 Oct
      +# 1977        Nil
      +# 1978        Nil
      +# 1979        13 May to 21 Oct
      +# 1980 to Now Nil
      +# The page does not give start or end times of day.
      +# The page does not give a start date for 1942.
      +# The page does not givw an end date for 1945.
      +# The Japanese occupation of Hong Kong began on 1941-12-25.
      +# The Japanese surrender of Hong Kong was signed 1945-09-15.
      +# For lack of anything better, use start of those days as the transition times.
      +
      +# Hong Kong (Xianggang)
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	HK	1941	only	-	Apr	1	3:30	1:00	S
      +Rule	HK	1941	only	-	Sep	30	3:30	0	-
      +Rule	HK	1946	only	-	Apr	20	3:30	1:00	S
      +Rule	HK	1946	only	-	Dec	1	3:30	0	-
      +Rule	HK	1947	only	-	Apr	13	3:30	1:00	S
      +Rule	HK	1947	only	-	Dec	30	3:30	0	-
      +Rule	HK	1948	only	-	May	2	3:30	1:00	S
      +Rule	HK	1948	1951	-	Oct	lastSun	3:30	0	-
      +Rule	HK	1952	only	-	Oct	25	3:30	0	-
      +Rule	HK	1949	1953	-	Apr	Sun>=1	3:30	1:00	S
      +Rule	HK	1953	only	-	Nov	1	3:30	0	-
      +Rule	HK	1954	1964	-	Mar	Sun>=18	3:30	1:00	S
      +Rule	HK	1954	only	-	Oct	31	3:30	0	-
      +Rule	HK	1955	1964	-	Nov	Sun>=1	3:30	0	-
      +Rule	HK	1965	1976	-	Apr	Sun>=16	3:30	1:00	S
      +Rule	HK	1965	1976	-	Oct	Sun>=16	3:30	0	-
      +Rule	HK	1973	only	-	Dec	30	3:30	1:00	S
      +Rule	HK	1979	only	-	May	Sun>=8	3:30	1:00	S
      +Rule	HK	1979	only	-	Oct	Sun>=16	3:30	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Hong_Kong	7:36:36 -	LMT	1904 Oct 30
      +			8:00	HK	HK%sT	1941 Dec 25
      +			9:00	-	JST	1945 Sep 15
      +			8:00	HK	HK%sT
      +
      +###############################################################################
      +
      +# Taiwan
      +
      +# Shanks & Pottenger write that Taiwan observed DST during 1945, when it
      +# was still controlled by Japan.  This is hard to believe, but we don't
      +# have any other information.
      +
      +# From smallufo (2010-04-03):
      +# According to Taiwan's CWB,
      +# 
      +# http://www.cwb.gov.tw/V6/astronomy/cdata/summert.htm
      +# 
      +# Taipei has DST in 1979 between July 1st and Sep 30.
      +
      +# From Arthur David Olson (2010-04-07):
      +# Here's Google's translation of the table at the bottom of the "summert.htm" page:
      +# Decade 	                                                    Name                      Start and end date
      +# Republic of China 34 years to 40 years (AD 1945-1951 years) Summer Time               May 1 to September 30
      +# 41 years of the Republic of China (AD 1952)                 Daylight Saving Time      March 1 to October 31
      +# Republic of China 42 years to 43 years (AD 1953-1954 years) Daylight Saving Time      April 1 to October 31
      +# In the 44 years to 45 years (AD 1955-1956 years)            Daylight Saving Time      April 1 to September 30
      +# Republic of China 46 years to 48 years (AD 1957-1959)       Summer Time               April 1 to September 30
      +# Republic of China 49 years to 50 years (AD 1960-1961)       Summer Time               June 1 to September 30
      +# Republic of China 51 years to 62 years (AD 1962-1973 years) Stop Summer Time
      +# Republic of China 63 years to 64 years (1974-1975 AD)       Daylight Saving Time      April 1 to September 30
      +# Republic of China 65 years to 67 years (1976-1978 AD)       Stop Daylight Saving Time
      +# Republic of China 68 years (AD 1979)                        Daylight Saving Time      July 1 to September 30
      +# Republic of China since 69 years (AD 1980)                  Stop Daylight Saving Time
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Taiwan	1945	1951	-	May	1	0:00	1:00	D
      +Rule	Taiwan	1945	1951	-	Oct	1	0:00	0	S
      +Rule	Taiwan	1952	only	-	Mar	1	0:00	1:00	D
      +Rule	Taiwan	1952	1954	-	Nov	1	0:00	0	S
      +Rule	Taiwan	1953	1959	-	Apr	1	0:00	1:00	D
      +Rule	Taiwan	1955	1961	-	Oct	1	0:00	0	S
      +Rule	Taiwan	1960	1961	-	Jun	1	0:00	1:00	D
      +Rule	Taiwan	1974	1975	-	Apr	1	0:00	1:00	D
      +Rule	Taiwan	1974	1975	-	Oct	1	0:00	0	S
      +Rule	Taiwan	1979	only	-	Jun	30	0:00	1:00	D
      +Rule	Taiwan	1979	only	-	Sep	30	0:00	0	S
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Taipei	8:06:00 -	LMT	1896 # or Taibei or T'ai-pei
      +			8:00	Taiwan	C%sT
      +
      +# Macau (Macao, Aomen)
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Macau	1961	1962	-	Mar	Sun>=16	3:30	1:00	S
      +Rule	Macau	1961	1964	-	Nov	Sun>=1	3:30	0	-
      +Rule	Macau	1963	only	-	Mar	Sun>=16	0:00	1:00	S
      +Rule	Macau	1964	only	-	Mar	Sun>=16	3:30	1:00	S
      +Rule	Macau	1965	only	-	Mar	Sun>=16	0:00	1:00	S
      +Rule	Macau	1965	only	-	Oct	31	0:00	0	-
      +Rule	Macau	1966	1971	-	Apr	Sun>=16	3:30	1:00	S
      +Rule	Macau	1966	1971	-	Oct	Sun>=16	3:30	0	-
      +Rule	Macau	1972	1974	-	Apr	Sun>=15	0:00	1:00	S
      +Rule	Macau	1972	1973	-	Oct	Sun>=15	0:00	0	-
      +Rule	Macau	1974	1977	-	Oct	Sun>=15	3:30	0	-
      +Rule	Macau	1975	1977	-	Apr	Sun>=15	3:30	1:00	S
      +Rule	Macau	1978	1980	-	Apr	Sun>=15	0:00	1:00	S
      +Rule	Macau	1978	1980	-	Oct	Sun>=15	0:00	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Macau	7:34:20 -	LMT	1912
      +			8:00	Macau	MO%sT	1999 Dec 20 # return to China
      +			8:00	PRC	C%sT
      +
      +
      +###############################################################################
      +
      +# Cyprus
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Cyprus	1975	only	-	Apr	13	0:00	1:00	S
      +Rule	Cyprus	1975	only	-	Oct	12	0:00	0	-
      +Rule	Cyprus	1976	only	-	May	15	0:00	1:00	S
      +Rule	Cyprus	1976	only	-	Oct	11	0:00	0	-
      +Rule	Cyprus	1977	1980	-	Apr	Sun>=1	0:00	1:00	S
      +Rule	Cyprus	1977	only	-	Sep	25	0:00	0	-
      +Rule	Cyprus	1978	only	-	Oct	2	0:00	0	-
      +Rule	Cyprus	1979	1997	-	Sep	lastSun	0:00	0	-
      +Rule	Cyprus	1981	1998	-	Mar	lastSun	0:00	1:00	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Nicosia	2:13:28 -	LMT	1921 Nov 14
      +			2:00	Cyprus	EE%sT	1998 Sep
      +			2:00	EUAsia	EE%sT
      +# IATA SSIM (1998-09) has Cyprus using EU rules for the first time.
      +
      +# Classically, Cyprus belongs to Asia; e.g. see Herodotus, Histories, I.72.
      +# However, for various reasons many users expect to find it under Europe.
      +Link	Asia/Nicosia	Europe/Nicosia
      +
      +# Georgia
      +# From Paul Eggert (1994-11-19):
      +# Today's _Economist_ (p 60) reports that Georgia moved its clocks forward
      +# an hour recently, due to a law proposed by Zurab Murvanidze,
      +# an MP who went on a hunger strike for 11 days to force discussion about it!
      +# We have no details, but we'll guess they didn't move the clocks back in fall.
      +#
      +# From Mathew Englander, quoting AP (1996-10-23 13:05-04):
      +# Instead of putting back clocks at the end of October, Georgia
      +# will stay on daylight savings time this winter to save energy,
      +# President Eduard Shevardnadze decreed Wednesday.
      +#
      +# From the BBC via Joseph S. Myers (2004-06-27):
      +#
      +# Georgia moved closer to Western Europe on Sunday...  The former Soviet
      +# republic has changed its time zone back to that of Moscow.  As a result it
      +# is now just four hours ahead of Greenwich Mean Time, rather than five hours
      +# ahead.  The switch was decreed by the pro-Western president of Georgia,
      +# Mikhail Saakashvili, who said the change was partly prompted by the process
      +# of integration into Europe.
      +
      +# From Teimuraz Abashidze (2005-11-07):
      +# Government of Georgia ... decided to NOT CHANGE daylight savings time on
      +# [Oct.] 30, as it was done before during last more than 10 years.
      +# Currently, we are in fact GMT +4:00, as before 30 October it was GMT
      +# +3:00.... The problem is, there is NO FORMAL LAW or governmental document
      +# about it.  As far as I can find, I was told, that there is no document,
      +# because we just DIDN'T ISSUE document about switching to winter time....
      +# I don't know what can be done, especially knowing that some years ago our
      +# DST rules where changed THREE TIMES during one month.
      +
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Tbilisi	2:59:16 -	LMT	1880
      +			2:59:16	-	TBMT	1924 May  2 # Tbilisi Mean Time
      +			3:00	-	TBIT	1957 Mar    # Tbilisi Time
      +			4:00 RussiaAsia TBI%sT	1991 Mar 31 2:00s
      +			3:00	1:00	TBIST	1991 Apr  9 # independence
      +			3:00 RussiaAsia GE%sT	1992 # Georgia Time
      +			3:00 E-EurAsia	GE%sT	1994 Sep lastSun
      +			4:00 E-EurAsia	GE%sT	1996 Oct lastSun
      +			4:00	1:00	GEST	1997 Mar lastSun
      +			4:00 E-EurAsia	GE%sT	2004 Jun 27
      +			3:00 RussiaAsia	GE%sT	2005 Mar lastSun 2:00
      +			4:00	-	GET
      +
      +# East Timor
      +
      +# See Indonesia for the 1945 transition.
      +
      +# From Joao Carrascalao, brother of the former governor of East Timor, in
      +# 
      +# East Timor may be late for its millennium
      +#  (1999-12-26/31):
      +# Portugal tried to change the time forward in 1974 because the sun
      +# rises too early but the suggestion raised a lot of problems with the
      +# Timorese and I still don't think it would work today because it
      +# conflicts with their way of life.
      +
      +# From Paul Eggert (2000-12-04):
      +# We don't have any record of the above attempt.
      +# Most likely our records are incomplete, but we have no better data.
      +
      +# 
      +# From Manoel de Almeida e Silva, Deputy Spokesman for the UN Secretary-General
      +# (2000-08-16):
      +# The Cabinet of the East Timor Transition Administration decided
      +# today to advance East Timor's time by one hour.  The time change,
      +# which will be permanent, with no seasonal adjustment, will happen at
      +# midnight on Saturday, September 16.
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Dili	8:22:20 -	LMT	1912
      +			8:00	-	TLT	1942 Feb 21 23:00 # E Timor Time
      +			9:00	-	JST	1945 Sep 23
      +			9:00	-	TLT	1976 May  3
      +			8:00	-	CIT	2000 Sep 17 00:00
      +			9:00	-	TLT
      +
      +# India
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Kolkata	5:53:28 -	LMT	1880	# Kolkata
      +			5:53:20	-	HMT	1941 Oct    # Howrah Mean Time?
      +			6:30	-	BURT	1942 May 15 # Burma Time
      +			5:30	-	IST	1942 Sep
      +			5:30	1:00	IST	1945 Oct 15
      +			5:30	-	IST
      +# The following are like Asia/Kolkata:
      +#	Andaman Is
      +#	Lakshadweep (Laccadive, Minicoy and Amindivi Is)
      +#	Nicobar Is
      +
      +# Indonesia
      +#
      +# From Gwillim Law (2001-05-28), overriding Shanks & Pottenger:
      +# 
      +# says that Indonesia's time zones changed on 1988-01-01.  Looking at some
      +# time zone maps, I think that must refer to Western Borneo (Kalimantan Barat
      +# and Kalimantan Tengah) switching from UTC+8 to UTC+7.
      +#
      +# From Paul Eggert (2007-03-10):
      +# Here is another correction to Shanks & Pottenger.
      +# JohnTWB writes that Japanese forces did not surrender control in
      +# Indonesia until 1945-09-01 00:00 at the earliest (in Jakarta) and
      +# other formal surrender ceremonies were September 9, 11, and 13, plus
      +# September 12 for the regional surrender to Mountbatten in Singapore.
      +# These would be the earliest possible times for a change.
      +# Regimes horaires pour le monde entier, by Henri Le Corre, (Editions
      +# Traditionnelles, 1987, Paris) says that Java and Madura switched
      +# from JST to UTC+07:30 on 1945-09-23, and gives 1944-09-01 for Jayapura
      +# (Hollandia).  For now, assume all Indonesian locations other than Jayapura
      +# switched on 1945-09-23.
      +#
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Asia/Jakarta	7:07:12 -	LMT	1867 Aug 10
      +# Shanks & Pottenger say the next transition was at 1924 Jan 1 0:13,
      +# but this must be a typo.
      +			7:07:12	-	JMT	1923 Dec 31 23:47:12 # Jakarta
      +			7:20	-	JAVT	1932 Nov	 # Java Time
      +			7:30	-	WIT	1942 Mar 23
      +			9:00	-	JST	1945 Sep 23
      +			7:30	-	WIT	1948 May
      +			8:00	-	WIT	1950 May
      +			7:30	-	WIT	1964
      +			7:00	-	WIT
      +Zone Asia/Pontianak	7:17:20	-	LMT	1908 May
      +			7:17:20	-	PMT	1932 Nov    # Pontianak MT
      +			7:30	-	WIT	1942 Jan 29
      +			9:00	-	JST	1945 Sep 23
      +			7:30	-	WIT	1948 May
      +			8:00	-	WIT	1950 May
      +			7:30	-	WIT	1964
      +			8:00	-	CIT	1988 Jan  1
      +			7:00	-	WIT
      +Zone Asia/Makassar	7:57:36 -	LMT	1920
      +			7:57:36	-	MMT	1932 Nov    # Macassar MT
      +			8:00	-	CIT	1942 Feb  9
      +			9:00	-	JST	1945 Sep 23
      +			8:00	-	CIT
      +Zone Asia/Jayapura	9:22:48 -	LMT	1932 Nov
      +			9:00	-	EIT	1944 Sep  1
      +			9:30	-	CST	1964
      +			9:00	-	EIT
      +
      +# Iran
      +
      +# From Roozbeh Pournader (2003-03-15):
      +# This is an English translation of what I just found (originally in Persian).
      +# The Gregorian dates in brackets are mine:
      +#
      +#	Official Newspaper No. 13548-1370/6/25 [1991-09-16]
      +#	No. 16760/T233 H				1370/6/10 [1991-09-01]
      +#
      +#	The Rule About Change of the Official Time of the Country
      +#
      +#	The Board of Ministers, in the meeting dated 1370/5/23 [1991-08-14],
      +#	based on the suggestion number 2221/D dated 1370/4/22 [1991-07-13]
      +#	of the Country's Organization for Official and Employment Affairs,
      +#	and referring to the law for equating the working hours of workers
      +#	and officers in the whole country dated 1359/4/23 [1980-07-14], and
      +#	for synchronizing the official times of the country, agreed that:
      +#
      +#	The official time of the country will should move forward one hour
      +#	at the 24[:00] hours of the first day of Farvardin and should return
      +#	to its previous state at the 24[:00] hours of the 30th day of
      +#	Shahrivar.
      +#
      +#	First Deputy to the President - Hassan Habibi
      +#
      +# From personal experience, that agrees with what has been followed
      +# for at least the last 5 years.  Before that, for a few years, the
      +# date used was the first Thursday night of Farvardin and the last
      +# Thursday night of Shahrivar, but I can't give exact dates....
      +# I have also changed the abbreviations to what is considered correct
      +# here in Iran, IRST for regular time and IRDT for daylight saving time.
      +#
      +# From Roozbeh Pournader (2005-04-05):
      +# The text of the Iranian law, in effect since 1925, clearly mentions
      +# that the true solar year is the measure, and there is no arithmetic
      +# leap year calculation involved.  There has never been any serious
      +# plan to change that law....
      +#
      +# From Paul Eggert (2006-03-22):
      +# Go with Shanks & Pottenger before Sept. 1991, and with Pournader thereafter.
      +# I used Ed Reingold's cal-persia in GNU Emacs 21.2 to check Persian dates,
      +# stopping after 2037 when 32-bit time_t's overflow.
      +# That cal-persia used Birashk's approximation, which disagrees with the solar
      +# calendar predictions for the year 2025, so I corrected those dates by hand.
      +#
      +# From Oscar van Vlijmen (2005-03-30), writing about future
      +# discrepancies between cal-persia and the Iranian calendar:
      +# For 2091 solar-longitude-after yields 2091-03-20 08:40:07.7 UT for
      +# the vernal equinox and that gets so close to 12:00 some local
      +# Iranian time that the definition of the correct location needs to be
      +# known exactly, amongst other factors.  2157 is even closer:
      +# 2157-03-20 08:37:15.5 UT.  But the Gregorian year 2025 should give
      +# no interpretation problem whatsoever.  By the way, another instant
      +# in the near future where there will be a discrepancy between
      +# arithmetical and astronomical Iranian calendars will be in 2058:
      +# vernal equinox on 2058-03-20 09:03:05.9 UT.  The Java version of
      +# Reingold's/Dershowitz' calculator gives correctly the Gregorian date
      +# 2058-03-21 for 1 Farvardin 1437 (astronomical).
      +#
      +# From Steffen Thorsen (2006-03-22):
      +# Several of my users have reported that Iran will not observe DST anymore:
      +# http://www.irna.ir/en/news/view/line-17/0603193812164948.htm
      +#
      +# From Reuters (2007-09-16), with a heads-up from Jesper Norgaard Welen:
      +# ... the Guardian Council ... approved a law on Sunday to re-introduce
      +# daylight saving time ...
      +# http://uk.reuters.com/article/oilRpt/idUKBLA65048420070916
      +#
      +# From Roozbeh Pournader (2007-11-05):
      +# This is quoted from Official Gazette of the Islamic Republic of
      +# Iran, Volume 63, Number 18242, dated Tuesday 1386/6/24
      +# [2007-10-16]. I am doing the best translation I can:...
      +# The official time of the country will be moved forward for one hour
      +# on the 24 hours of the first day of the month of Farvardin and will
      +# be changed back to its previous state on the 24 hours of the
      +# thirtieth day of Shahrivar.
      +#
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Iran	1978	1980	-	Mar	21	0:00	1:00	D
      +Rule	Iran	1978	only	-	Oct	21	0:00	0	S
      +Rule	Iran	1979	only	-	Sep	19	0:00	0	S
      +Rule	Iran	1980	only	-	Sep	23	0:00	0	S
      +Rule	Iran	1991	only	-	May	 3	0:00	1:00	D
      +Rule	Iran	1992	1995	-	Mar	22	0:00	1:00	D
      +Rule	Iran	1991	1995	-	Sep	22	0:00	0	S
      +Rule	Iran	1996	only	-	Mar	21	0:00	1:00	D
      +Rule	Iran	1996	only	-	Sep	21	0:00	0	S
      +Rule	Iran	1997	1999	-	Mar	22	0:00	1:00	D
      +Rule	Iran	1997	1999	-	Sep	22	0:00	0	S
      +Rule	Iran	2000	only	-	Mar	21	0:00	1:00	D
      +Rule	Iran	2000	only	-	Sep	21	0:00	0	S
      +Rule	Iran	2001	2003	-	Mar	22	0:00	1:00	D
      +Rule	Iran	2001	2003	-	Sep	22	0:00	0	S
      +Rule	Iran	2004	only	-	Mar	21	0:00	1:00	D
      +Rule	Iran	2004	only	-	Sep	21	0:00	0	S
      +Rule	Iran	2005	only	-	Mar	22	0:00	1:00	D
      +Rule	Iran	2005	only	-	Sep	22	0:00	0	S
      +Rule	Iran	2008	only	-	Mar	21	0:00	1:00	D
      +Rule	Iran	2008	only	-	Sep	21	0:00	0	S
      +Rule	Iran	2009	2011	-	Mar	22	0:00	1:00	D
      +Rule	Iran	2009	2011	-	Sep	22	0:00	0	S
      +Rule	Iran	2012	only	-	Mar	21	0:00	1:00	D
      +Rule	Iran	2012	only	-	Sep	21	0:00	0	S
      +Rule	Iran	2013	2015	-	Mar	22	0:00	1:00	D
      +Rule	Iran	2013	2015	-	Sep	22	0:00	0	S
      +Rule	Iran	2016	only	-	Mar	21	0:00	1:00	D
      +Rule	Iran	2016	only	-	Sep	21	0:00	0	S
      +Rule	Iran	2017	2019	-	Mar	22	0:00	1:00	D
      +Rule	Iran	2017	2019	-	Sep	22	0:00	0	S
      +Rule	Iran	2020	only	-	Mar	21	0:00	1:00	D
      +Rule	Iran	2020	only	-	Sep	21	0:00	0	S
      +Rule	Iran	2021	2023	-	Mar	22	0:00	1:00	D
      +Rule	Iran	2021	2023	-	Sep	22	0:00	0	S
      +Rule	Iran	2024	only	-	Mar	21	0:00	1:00	D
      +Rule	Iran	2024	only	-	Sep	21	0:00	0	S
      +Rule	Iran	2025	2027	-	Mar	22	0:00	1:00	D
      +Rule	Iran	2025	2027	-	Sep	22	0:00	0	S
      +Rule	Iran	2028	2029	-	Mar	21	0:00	1:00	D
      +Rule	Iran	2028	2029	-	Sep	21	0:00	0	S
      +Rule	Iran	2030	2031	-	Mar	22	0:00	1:00	D
      +Rule	Iran	2030	2031	-	Sep	22	0:00	0	S
      +Rule	Iran	2032	2033	-	Mar	21	0:00	1:00	D
      +Rule	Iran	2032	2033	-	Sep	21	0:00	0	S
      +Rule	Iran	2034	2035	-	Mar	22	0:00	1:00	D
      +Rule	Iran	2034	2035	-	Sep	22	0:00	0	S
      +Rule	Iran	2036	2037	-	Mar	21	0:00	1:00	D
      +Rule	Iran	2036	2037	-	Sep	21	0:00	0	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Tehran	3:25:44	-	LMT	1916
      +			3:25:44	-	TMT	1946	# Tehran Mean Time
      +			3:30	-	IRST	1977 Nov
      +			4:00	Iran	IR%sT	1979
      +			3:30	Iran	IR%sT
      +
      +
      +# Iraq
      +#
      +# From Jonathan Lennox (2000-06-12):
      +# An article in this week's Economist ("Inside the Saddam-free zone", p. 50 in
      +# the U.S. edition) on the Iraqi Kurds contains a paragraph:
      +# "The three northern provinces ... switched their clocks this spring and
      +# are an hour ahead of Baghdad."
      +#
      +# But Rives McDow (2000-06-18) quotes a contact in Iraqi-Kurdistan as follows:
      +# In the past, some Kurdish nationalists, as a protest to the Iraqi
      +# Government, did not adhere to daylight saving time.  They referred
      +# to daylight saving as Saddam time.  But, as of today, the time zone
      +# in Iraqi-Kurdistan is on standard time with Baghdad, Iraq.
      +#
      +# So we'll ignore the Economist's claim.
      +
      +# From Steffen Thorsen (2008-03-10):
      +# The cabinet in Iraq abolished DST last week, according to the following
      +# news sources (in Arabic):
      +# 
      +# http://www.aljeeran.net/wesima_articles/news-20080305-98602.html
      +# 
      +# 
      +# http://www.aswataliraq.info/look/article.tpl?id=2047&IdLanguage=17&IdPublication=4&NrArticle=71743&NrIssue=1&NrSection=10
      +# 
      +#
      +# We have published a short article in English about the change:
      +# 
      +# http://www.timeanddate.com/news/time/iraq-dumps-daylight-saving.html
      +# 
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Iraq	1982	only	-	May	1	0:00	1:00	D
      +Rule	Iraq	1982	1984	-	Oct	1	0:00	0	S
      +Rule	Iraq	1983	only	-	Mar	31	0:00	1:00	D
      +Rule	Iraq	1984	1985	-	Apr	1	0:00	1:00	D
      +Rule	Iraq	1985	1990	-	Sep	lastSun	1:00s	0	S
      +Rule	Iraq	1986	1990	-	Mar	lastSun	1:00s	1:00	D
      +# IATA SSIM (1991/1996) says Apr 1 12:01am UTC; guess the `:01' is a typo.
      +# Shanks & Pottenger say Iraq did not observe DST 1992/1997; ignore this.
      +#
      +Rule	Iraq	1991	2007	-	Apr	 1	3:00s	1:00	D
      +Rule	Iraq	1991	2007	-	Oct	 1	3:00s	0	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Baghdad	2:57:40	-	LMT	1890
      +			2:57:36	-	BMT	1918	    # Baghdad Mean Time?
      +			3:00	-	AST	1982 May
      +			3:00	Iraq	A%sT
      +
      +
      +###############################################################################
      +
      +# Israel
      +
      +# From Ephraim Silverberg (2001-01-11):
      +#
      +# I coined "IST/IDT" circa 1988.  Until then there were three
      +# different abbreviations in use:
      +#
      +# JST  Jerusalem Standard Time [Danny Braniss, Hebrew University]
      +# IZT  Israel Zonal (sic) Time [Prof. Haim Papo, Technion]
      +# EEST Eastern Europe Standard Time [used by almost everyone else]
      +#
      +# Since timezones should be called by country and not capital cities,
      +# I ruled out JST.  As Israel is in Asia Minor and not Eastern Europe,
      +# EEST was equally unacceptable.  Since "zonal" was not compatible with
      +# any other timezone abbreviation, I felt that 'IST' was the way to go
      +# and, indeed, it has received almost universal acceptance in timezone
      +# settings in Israeli computers.
      +#
      +# In any case, I am happy to share timezone abbreviations with India,
      +# high on my favorite-country list (and not only because my wife's
      +# family is from India).
      +
      +# From Shanks & Pottenger:
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Zion	1940	only	-	Jun	 1	0:00	1:00	D
      +Rule	Zion	1942	1944	-	Nov	 1	0:00	0	S
      +Rule	Zion	1943	only	-	Apr	 1	2:00	1:00	D
      +Rule	Zion	1944	only	-	Apr	 1	0:00	1:00	D
      +Rule	Zion	1945	only	-	Apr	16	0:00	1:00	D
      +Rule	Zion	1945	only	-	Nov	 1	2:00	0	S
      +Rule	Zion	1946	only	-	Apr	16	2:00	1:00	D
      +Rule	Zion	1946	only	-	Nov	 1	0:00	0	S
      +Rule	Zion	1948	only	-	May	23	0:00	2:00	DD
      +Rule	Zion	1948	only	-	Sep	 1	0:00	1:00	D
      +Rule	Zion	1948	1949	-	Nov	 1	2:00	0	S
      +Rule	Zion	1949	only	-	May	 1	0:00	1:00	D
      +Rule	Zion	1950	only	-	Apr	16	0:00	1:00	D
      +Rule	Zion	1950	only	-	Sep	15	3:00	0	S
      +Rule	Zion	1951	only	-	Apr	 1	0:00	1:00	D
      +Rule	Zion	1951	only	-	Nov	11	3:00	0	S
      +Rule	Zion	1952	only	-	Apr	20	2:00	1:00	D
      +Rule	Zion	1952	only	-	Oct	19	3:00	0	S
      +Rule	Zion	1953	only	-	Apr	12	2:00	1:00	D
      +Rule	Zion	1953	only	-	Sep	13	3:00	0	S
      +Rule	Zion	1954	only	-	Jun	13	0:00	1:00	D
      +Rule	Zion	1954	only	-	Sep	12	0:00	0	S
      +Rule	Zion	1955	only	-	Jun	11	2:00	1:00	D
      +Rule	Zion	1955	only	-	Sep	11	0:00	0	S
      +Rule	Zion	1956	only	-	Jun	 3	0:00	1:00	D
      +Rule	Zion	1956	only	-	Sep	30	3:00	0	S
      +Rule	Zion	1957	only	-	Apr	29	2:00	1:00	D
      +Rule	Zion	1957	only	-	Sep	22	0:00	0	S
      +Rule	Zion	1974	only	-	Jul	 7	0:00	1:00	D
      +Rule	Zion	1974	only	-	Oct	13	0:00	0	S
      +Rule	Zion	1975	only	-	Apr	20	0:00	1:00	D
      +Rule	Zion	1975	only	-	Aug	31	0:00	0	S
      +Rule	Zion	1985	only	-	Apr	14	0:00	1:00	D
      +Rule	Zion	1985	only	-	Sep	15	0:00	0	S
      +Rule	Zion	1986	only	-	May	18	0:00	1:00	D
      +Rule	Zion	1986	only	-	Sep	 7	0:00	0	S
      +Rule	Zion	1987	only	-	Apr	15	0:00	1:00	D
      +Rule	Zion	1987	only	-	Sep	13	0:00	0	S
      +Rule	Zion	1988	only	-	Apr	 9	0:00	1:00	D
      +Rule	Zion	1988	only	-	Sep	 3	0:00	0	S
      +
      +# From Ephraim Silverberg
      +# (1997-03-04, 1998-03-16, 1998-12-28, 2000-01-17, 2000-07-25, 2004-12-22,
      +# and 2005-02-17):
      +
      +# According to the Office of the Secretary General of the Ministry of
      +# Interior, there is NO set rule for Daylight-Savings/Standard time changes.
      +# One thing is entrenched in law, however: that there must be at least 150
      +# days of daylight savings time annually.  From 1993-1998, the change to
      +# daylight savings time was on a Friday morning from midnight IST to
      +# 1 a.m IDT; up until 1998, the change back to standard time was on a
      +# Saturday night from midnight daylight savings time to 11 p.m. standard
      +# time.  1996 is an exception to this rule where the change back to standard
      +# time took place on Sunday night instead of Saturday night to avoid
      +# conflicts with the Jewish New Year.  In 1999, the change to
      +# daylight savings time was still on a Friday morning but from
      +# 2 a.m. IST to 3 a.m. IDT; furthermore, the change back to standard time
      +# was also on a Friday morning from 2 a.m. IDT to 1 a.m. IST for
      +# 1999 only.  In the year 2000, the change to daylight savings time was
      +# similar to 1999, but although the change back will be on a Friday, it
      +# will take place from 1 a.m. IDT to midnight IST.  Starting in 2001, all
      +# changes to/from will take place at 1 a.m. old time, but now there is no
      +# rule as to what day of the week it will take place in as the start date
      +# (except in 2003) is the night after the Passover Seder (i.e. the eve
      +# of the 16th of Nisan in the lunar Hebrew calendar) and the end date
      +# (except in 2002) is three nights before Yom Kippur [Day of Atonement]
      +# (the eve of the 7th of Tishrei in the lunar Hebrew calendar).
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Zion	1989	only	-	Apr	30	0:00	1:00	D
      +Rule	Zion	1989	only	-	Sep	 3	0:00	0	S
      +Rule	Zion	1990	only	-	Mar	25	0:00	1:00	D
      +Rule	Zion	1990	only	-	Aug	26	0:00	0	S
      +Rule	Zion	1991	only	-	Mar	24	0:00	1:00	D
      +Rule	Zion	1991	only	-	Sep	 1	0:00	0	S
      +Rule	Zion	1992	only	-	Mar	29	0:00	1:00	D
      +Rule	Zion	1992	only	-	Sep	 6	0:00	0	S
      +Rule	Zion	1993	only	-	Apr	 2	0:00	1:00	D
      +Rule	Zion	1993	only	-	Sep	 5	0:00	0	S
      +
      +# The dates for 1994-1995 were obtained from Office of the Spokeswoman for the
      +# Ministry of Interior, Jerusalem, Israel.  The spokeswoman can be reached by
      +# calling the office directly at 972-2-6701447 or 972-2-6701448.
      +
      +# Rule	NAME    FROM    TO      TYPE    IN      ON      AT      SAVE    LETTER/S
      +Rule	Zion	1994	only	-	Apr	 1	0:00	1:00	D
      +Rule	Zion	1994	only	-	Aug	28	0:00	0	S
      +Rule	Zion	1995	only	-	Mar	31	0:00	1:00	D
      +Rule	Zion	1995	only	-	Sep	 3	0:00	0	S
      +
      +# The dates for 1996 were determined by the Minister of Interior of the
      +# time, Haim Ramon.  The official announcement regarding 1996-1998
      +# (with the dates for 1997-1998 no longer being relevant) can be viewed at:
      +#
      +#   ftp://ftp.cs.huji.ac.il/pub/tz/announcements/1996-1998.ramon.ps.gz
      +#
      +# The dates for 1997-1998 were altered by his successor, Rabbi Eli Suissa.
      +#
      +# The official announcements for the years 1997-1999 can be viewed at:
      +#
      +#   ftp://ftp.cs.huji.ac.il/pub/tz/announcements/YYYY.ps.gz
      +#
      +#       where YYYY is the relevant year.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Zion	1996	only	-	Mar	15	0:00	1:00	D
      +Rule	Zion	1996	only	-	Sep	16	0:00	0	S
      +Rule	Zion	1997	only	-	Mar	21	0:00	1:00	D
      +Rule	Zion	1997	only	-	Sep	14	0:00	0	S
      +Rule	Zion	1998	only	-	Mar	20	0:00	1:00	D
      +Rule	Zion	1998	only	-	Sep	 6	0:00	0	S
      +Rule	Zion	1999	only	-	Apr	 2	2:00	1:00	D
      +Rule	Zion	1999	only	-	Sep	 3	2:00	0	S
      +
      +# The Knesset Interior Committee has changed the dates for 2000 for
      +# the third time in just over a year and have set new dates for the
      +# years 2001-2004 as well.
      +#
      +# The official announcement for the start date of 2000 can be viewed at:
      +#
      +#	ftp://ftp.cs.huji.ac.il/pub/tz/announcements/2000-start.ps.gz
      +#
      +# The official announcement for the end date of 2000 and the dates
      +# for the years 2001-2004 can be viewed at:
      +#
      +#	ftp://ftp.cs.huji.ac.il/pub/tz/announcements/2000-2004.ps.gz
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Zion	2000	only	-	Apr	14	2:00	1:00	D
      +Rule	Zion	2000	only	-	Oct	 6	1:00	0	S
      +Rule	Zion	2001	only	-	Apr	 9	1:00	1:00	D
      +Rule	Zion	2001	only	-	Sep	24	1:00	0	S
      +Rule	Zion	2002	only	-	Mar	29	1:00	1:00	D
      +Rule	Zion	2002	only	-	Oct	 7	1:00	0	S
      +Rule	Zion	2003	only	-	Mar	28	1:00	1:00	D
      +Rule	Zion	2003	only	-	Oct	 3	1:00	0	S
      +Rule	Zion	2004	only	-	Apr	 7	1:00	1:00	D
      +Rule	Zion	2004	only	-	Sep	22	1:00	0	S
      +
      +# The proposed law agreed upon by the Knesset Interior Committee on
      +# 2005-02-14 is that, for 2005 and beyond, DST starts at 02:00 the
      +# last Friday before April 2nd (i.e. the last Friday in March or April
      +# 1st itself if it falls on a Friday) and ends at 02:00 on the Saturday
      +# night _before_ the fast of Yom Kippur.
      +#
      +# Those who can read Hebrew can view the announcement at:
      +#
      +#	ftp://ftp.cs.huji.ac.il/pub/tz/announcements/2005+beyond.ps
      +
      +# From Paul Eggert (2012-10-26):
      +# I used Ephraim Silverberg's dst-israel.el program
      +#  (2005-02-20)
      +# along with Ed Reingold's cal-hebrew in GNU Emacs 21.4,
      +# to generate the transitions from 2005 through 2012.
      +# (I replaced "lastFri" with "Fri>=26" by hand.)
      +# The spring transitions all correspond to the following Rule:
      +#
      +# Rule	Zion	2005	2012	-	Mar	Fri>=26	2:00	1:00	D
      +#
      +# but older zic implementations (e.g., Solaris 8) do not support
      +# "Fri>=26" to mean April 1 in years like 2005, so for now we list the
      +# springtime transitions explicitly.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Zion	2005	only	-	Apr	 1	2:00	1:00	D
      +Rule	Zion	2005	only	-	Oct	 9	2:00	0	S
      +Rule	Zion	2006	2010	-	Mar	Fri>=26	2:00	1:00	D
      +Rule	Zion	2006	only	-	Oct	 1	2:00	0	S
      +Rule	Zion	2007	only	-	Sep	16	2:00	0	S
      +Rule	Zion	2008	only	-	Oct	 5	2:00	0	S
      +Rule	Zion	2009	only	-	Sep	27	2:00	0	S
      +Rule	Zion	2010	only	-	Sep	12	2:00	0	S
      +Rule	Zion	2011	only	-	Apr	 1	2:00	1:00	D
      +Rule	Zion	2011	only	-	Oct	 2	2:00	0	S
      +Rule	Zion	2012	only	-	Mar	Fri>=26	2:00	1:00	D
      +Rule	Zion	2012	only	-	Sep	23	2:00	0	S
      +
      +# From Ephraim Silverberg (2012-10-18):
      +
      +# Yesterday, the Interior Ministry Committee, after more than a year
      +# past, approved sending the proposed June 2011 changes to the Time
      +# Decree Law back to the Knesset for second and third (final) votes
      +# before the upcoming elections on Jan. 22, 2013.  Hence, although the
      +# changes are not yet law, they are expected to be so before February 2013.
      +#
      +# As of 2013, DST starts at 02:00 on the Friday before the last Sunday in March.
      +# DST ends at 02:00 on the first Sunday after October 1, unless it occurs on the
      +# second day of the Jewish Rosh Hashana holiday, in which case DST ends a day
      +# later (i.e. at 02:00 the first Monday after October 2).
      +# [Rosh Hashana holidays are factored in until 2100.]
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Zion	2013	max	-	Mar	Fri>=23	2:00	1:00	D
      +Rule	Zion	2013	2026	-	Oct	Sun>=2	2:00	0	S
      +Rule	Zion	2027	only	-	Oct	Mon>=3	2:00	0	S
      +Rule	Zion	2028	max	-	Oct	Sun>=2	2:00	0	S
      +# The following rules are commented out for now, as they break older
      +# versions of zic that support only signed 32-bit timestamps, i.e.,
      +# through 2038-01-19 03:14:07 UTC.
      +#Rule	Zion	2028	2053	-	Oct	Sun>=2	2:00	0	S
      +#Rule	Zion	2054	only	-	Oct	Mon>=3	2:00	0	S
      +#Rule	Zion	2055	2080	-	Oct	Sun>=2	2:00	0	S
      +#Rule	Zion	2081	only	-	Oct	Mon>=3	2:00	0	S
      +#Rule	Zion	2082	max	-	Oct	Sun>=2	2:00	0	S
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Jerusalem	2:20:56 -	LMT	1880
      +			2:20:40	-	JMT	1918	# Jerusalem Mean Time?
      +			2:00	Zion	I%sT
      +
      +
      +
      +###############################################################################
      +
      +# Japan
      +
      +# `9:00' and `JST' is from Guy Harris.
      +
      +# From Paul Eggert (1995-03-06):
      +# Today's _Asahi Evening News_ (page 4) reports that Japan had
      +# daylight saving between 1948 and 1951, but ``the system was discontinued
      +# because the public believed it would lead to longer working hours.''
      +
      +# From Mayumi Negishi in the 2005-08-10 Japan Times
      +# :
      +# Occupation authorities imposed daylight-saving time on Japan on
      +# [1948-05-01]....  But lack of prior debate and the execution of
      +# daylight-saving time just three days after the bill was passed generated
      +# deep hatred of the concept....  The Diet unceremoniously passed a bill to
      +# dump the unpopular system in October 1951, less than a month after the San
      +# Francisco Peace Treaty was signed.  (A government poll in 1951 showed 53%
      +# of the Japanese wanted to scrap daylight-saving time, as opposed to 30% who
      +# wanted to keep it.)
      +
      +# From Paul Eggert (2006-03-22):
      +# Shanks & Pottenger write that DST in Japan during those years was as follows:
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Japan	1948	only	-	May	Sun>=1	2:00	1:00	D
      +Rule	Japan	1948	1951	-	Sep	Sat>=8	2:00	0	S
      +Rule	Japan	1949	only	-	Apr	Sun>=1	2:00	1:00	D
      +Rule	Japan	1950	1951	-	May	Sun>=1	2:00	1:00	D
      +# but the only locations using it (for birth certificates, presumably, since
      +# their audience is astrologers) were US military bases.  For now, assume
      +# that for most purposes daylight-saving time was observed; otherwise, what
      +# would have been the point of the 1951 poll?
      +
      +# From Hideyuki Suzuki (1998-11-09):
      +# 'Tokyo' usually stands for the former location of Tokyo Astronomical
      +# Observatory: E 139 44' 40".90 (9h 18m 58s.727), N 35 39' 16".0.
      +# This data is from 'Rika Nenpyou (Chronological Scientific Tables) 1996'
      +# edited by National Astronomical Observatory of Japan....
      +# JST (Japan Standard Time) has been used since 1888-01-01 00:00 (JST).
      +# The law is enacted on 1886-07-07.
      +
      +# From Hideyuki Suzuki (1998-11-16):
      +# The ordinance No. 51 (1886) established "standard time" in Japan,
      +# which stands for the time on E 135 degree.
      +# In the ordinance No. 167 (1895), "standard time" was renamed to "central
      +# standard time".  And the same ordinance also established "western standard
      +# time", which stands for the time on E 120 degree....  But "western standard
      +# time" was abolished in the ordinance No. 529 (1937).  In the ordinance No.
      +# 167, there is no mention regarding for what place western standard time is
      +# standard....
      +#
      +# I wrote "ordinance" above, but I don't know how to translate.
      +# In Japanese it's "chokurei", which means ordinance from emperor.
      +
      +# Shanks & Pottenger claim JST in use since 1896, and that a few
      +# places (e.g. Ishigaki) use +0800; go with Suzuki.  Guess that all
      +# ordinances took effect on Jan 1.
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Tokyo	9:18:59	-	LMT	1887 Dec 31 15:00u
      +			9:00	-	JST	1896
      +			9:00	-	CJT	1938
      +			9:00	Japan	J%sT
      +# Since 1938, all Japanese possessions have been like Asia/Tokyo.
      +
      +# Jordan
      +#
      +# From 
      +# Jordan Week (1999-07-01)  via Steffen Thorsen (1999-09-09):
      +# Clocks in Jordan were forwarded one hour on Wednesday at midnight,
      +# in accordance with the government's decision to implement summer time
      +# all year round.
      +#
      +# From 
      +# Jordan Week (1999-09-30)  via Steffen Thorsen (1999-11-09):
      +# Winter time starts today Thursday, 30 September. Clocks will be turned back
      +# by one hour.  This is the latest government decision and it's final!
      +# The decision was taken because of the increase in working hours in
      +# government's departments from six to seven hours.
      +#
      +# From Paul Eggert (2005-11-22):
      +# Starting 2003 transitions are from Steffen Thorsen's web site timeanddate.com.
      +#
      +# From Steffen Thorsen (2005-11-23):
      +# For Jordan I have received multiple independent user reports every year
      +# about DST end dates, as the end-rule is different every year.
      +#
      +# From Steffen Thorsen (2006-10-01), after a heads-up from Hilal Malawi:
      +# http://www.petranews.gov.jo/nepras/2006/Sep/05/4000.htm
      +# "Jordan will switch to winter time on Friday, October 27".
      +#
      +
      +# From Phil Pizzey (2009-04-02):
      +# ...I think I may have spotted an error in the timezone data for
      +# Jordan.
      +# The current (2009d) asia file shows Jordan going to daylight
      +# saving
      +# time on the last Thursday in March.
      +#
      +# Rule  Jordan      2000  max	-  Mar   lastThu     0:00s 1:00  S
      +#
      +# However timeanddate.com, which I usually find reliable, shows Jordan
      +# going to daylight saving time on the last Friday in March since 2002.
      +# Please see
      +# 
      +# http://www.timeanddate.com/worldclock/timezone.html?n=11
      +# 
      +
      +# From Steffen Thorsen (2009-04-02):
      +# This single one might be good enough, (2009-03-24, Arabic):
      +# 
      +# http://petra.gov.jo/Artical.aspx?Lng=2&Section=8&Artical=95279
      +# 
      +#
      +# Google's translation:
      +#
      +# > The Council of Ministers decided in 2002 to adopt the principle of timely
      +# > submission of the summer at 60 minutes as of midnight on the last Thursday
      +# > of the month of March of each year.
      +#
      +# So - this means the midnight between Thursday and Friday since 2002.
      +
      +# From Arthur David Olson (2009-04-06):
      +# We still have Jordan switching to DST on Thursdays in 2000 and 2001.
      +
      +# From Steffen Thorsen (2012-10-25):
      +# Yesterday the government in Jordan announced that they will not
      +# switch back to standard time this winter, so the will stay on DST
      +# until about the same time next year (at least).
      +# http://www.petra.gov.jo/Public_News/Nws_NewsDetails.aspx?NewsID=88950
      +#
      +# From Paul Eggert (2012-10-25):
      +# For now, assume this is just a one-year measure.  If it becomes
      +# permanent, we should move Jordan from EET to AST effective tomorrow.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Jordan	1973	only	-	Jun	6	0:00	1:00	S
      +Rule	Jordan	1973	1975	-	Oct	1	0:00	0	-
      +Rule	Jordan	1974	1977	-	May	1	0:00	1:00	S
      +Rule	Jordan	1976	only	-	Nov	1	0:00	0	-
      +Rule	Jordan	1977	only	-	Oct	1	0:00	0	-
      +Rule	Jordan	1978	only	-	Apr	30	0:00	1:00	S
      +Rule	Jordan	1978	only	-	Sep	30	0:00	0	-
      +Rule	Jordan	1985	only	-	Apr	1	0:00	1:00	S
      +Rule	Jordan	1985	only	-	Oct	1	0:00	0	-
      +Rule	Jordan	1986	1988	-	Apr	Fri>=1	0:00	1:00	S
      +Rule	Jordan	1986	1990	-	Oct	Fri>=1	0:00	0	-
      +Rule	Jordan	1989	only	-	May	8	0:00	1:00	S
      +Rule	Jordan	1990	only	-	Apr	27	0:00	1:00	S
      +Rule	Jordan	1991	only	-	Apr	17	0:00	1:00	S
      +Rule	Jordan	1991	only	-	Sep	27	0:00	0	-
      +Rule	Jordan	1992	only	-	Apr	10	0:00	1:00	S
      +Rule	Jordan	1992	1993	-	Oct	Fri>=1	0:00	0	-
      +Rule	Jordan	1993	1998	-	Apr	Fri>=1	0:00	1:00	S
      +Rule	Jordan	1994	only	-	Sep	Fri>=15	0:00	0	-
      +Rule	Jordan	1995	1998	-	Sep	Fri>=15	0:00s	0	-
      +Rule	Jordan	1999	only	-	Jul	 1	0:00s	1:00	S
      +Rule	Jordan	1999	2002	-	Sep	lastFri	0:00s	0	-
      +Rule	Jordan	2000	2001	-	Mar	lastThu	0:00s	1:00	S
      +Rule	Jordan	2002	max	-	Mar	lastThu	24:00	1:00	S
      +Rule	Jordan	2003	only	-	Oct	24	0:00s	0	-
      +Rule	Jordan	2004	only	-	Oct	15	0:00s	0	-
      +Rule	Jordan	2005	only	-	Sep	lastFri	0:00s	0	-
      +Rule	Jordan	2006	2011	-	Oct	lastFri	0:00s	0	-
      +Rule	Jordan	2013	max	-	Oct	lastFri	0:00s	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Amman	2:23:44 -	LMT	1931
      +			2:00	Jordan	EE%sT
      +
      +
      +# Kazakhstan
      +
      +# From Paul Eggert (1996-11-22):
      +# Andrew Evtichov (1996-04-13) writes that Kazakhstan
      +# stayed in sync with Moscow after 1990, and that Aqtobe (formerly Aktyubinsk)
      +# and Aqtau (formerly Shevchenko) are the largest cities in their zones.
      +# Guess that Aqtau and Aqtobe diverged in 1995, since that's the first time
      +# IATA SSIM mentions a third time zone in Kazakhstan.
      +
      +# From Paul Eggert (2006-03-22):
      +# German Iofis, ELSI, Almaty (2001-10-09) reports that Kazakhstan uses
      +# RussiaAsia rules, instead of switching at 00:00 as the IATA has it.
      +# Go with Shanks & Pottenger, who have them always using RussiaAsia rules.
      +# Also go with the following claims of Shanks & Pottenger:
      +#
      +# - Kazakhstan did not observe DST in 1991.
      +# - Qyzylorda switched from +5:00 to +6:00 on 1992-01-19 02:00.
      +# - Oral switched from +5:00 to +4:00 in spring 1989.
      +
      +# 
      +# From Kazakhstan Embassy's News Bulletin #11 (2005-03-21):
      +# 
      +# The Government of Kazakhstan passed a resolution March 15 abolishing
      +# daylight saving time citing lack of economic benefits and health
      +# complications coupled with a decrease in productivity.
      +#
      +# From Branislav Kojic (in Astana) via Gwillim Law (2005-06-28):
      +# ... what happened was that the former Kazakhstan Eastern time zone
      +# was "blended" with the Central zone.  Therefore, Kazakhstan now has
      +# two time zones, and difference between them is one hour.  The zone
      +# closer to UTC is the former Western zone (probably still called the
      +# same), encompassing four provinces in the west: Aqtobe, Atyrau,
      +# Mangghystau, and West Kazakhstan.  The other zone encompasses
      +# everything else....  I guess that would make Kazakhstan time zones
      +# de jure UTC+5 and UTC+6 respectively.
      +
      +#
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +#
      +# Almaty (formerly Alma-Ata), representing most locations in Kazakhstan
      +Zone	Asia/Almaty	5:07:48 -	LMT	1924 May  2 # or Alma-Ata
      +			5:00	-	ALMT	1930 Jun 21 # Alma-Ata Time
      +			6:00 RussiaAsia ALM%sT	1991
      +			6:00	-	ALMT	1992
      +			6:00 RussiaAsia	ALM%sT	2005 Mar 15
      +			6:00	-	ALMT
      +# Qyzylorda (aka Kyzylorda, Kizilorda, Kzyl-Orda, etc.)
      +Zone	Asia/Qyzylorda	4:21:52 -	LMT	1924 May  2
      +			4:00	-	KIZT	1930 Jun 21 # Kizilorda Time
      +			5:00	-	KIZT	1981 Apr  1
      +			5:00	1:00	KIZST	1981 Oct  1
      +			6:00	-	KIZT	1982 Apr  1
      +			5:00 RussiaAsia	KIZ%sT	1991
      +			5:00	-	KIZT	1991 Dec 16 # independence
      +			5:00	-	QYZT	1992 Jan 19 2:00
      +			6:00 RussiaAsia	QYZ%sT	2005 Mar 15
      +			6:00	-	QYZT
      +# Aqtobe (aka Aktobe, formerly Akt'ubinsk)
      +Zone	Asia/Aqtobe	3:48:40	-	LMT	1924 May  2
      +			4:00	-	AKTT	1930 Jun 21 # Aktyubinsk Time
      +			5:00	-	AKTT	1981 Apr  1
      +			5:00	1:00	AKTST	1981 Oct  1
      +			6:00	-	AKTT	1982 Apr  1
      +			5:00 RussiaAsia	AKT%sT	1991
      +			5:00	-	AKTT	1991 Dec 16 # independence
      +			5:00 RussiaAsia	AQT%sT	2005 Mar 15 # Aqtobe Time
      +			5:00	-	AQTT
      +# Mangghystau
      +# Aqtau was not founded until 1963, but it represents an inhabited region,
      +# so include time stamps before 1963.
      +Zone	Asia/Aqtau	3:21:04	-	LMT	1924 May  2
      +			4:00	-	FORT	1930 Jun 21 # Fort Shevchenko T
      +			5:00	-	FORT	1963
      +			5:00	-	SHET	1981 Oct  1 # Shevchenko Time
      +			6:00	-	SHET	1982 Apr  1
      +			5:00 RussiaAsia	SHE%sT	1991
      +			5:00	-	SHET	1991 Dec 16 # independence
      +			5:00 RussiaAsia	AQT%sT	1995 Mar lastSun 2:00 # Aqtau Time
      +			4:00 RussiaAsia	AQT%sT	2005 Mar 15
      +			5:00	-	AQTT
      +# West Kazakhstan
      +Zone	Asia/Oral	3:25:24	-	LMT	1924 May  2 # or Ural'sk
      +			4:00	-	URAT	1930 Jun 21 # Ural'sk time
      +			5:00	-	URAT	1981 Apr  1
      +			5:00	1:00	URAST	1981 Oct  1
      +			6:00	-	URAT	1982 Apr  1
      +			5:00 RussiaAsia	URA%sT	1989 Mar 26 2:00
      +			4:00 RussiaAsia	URA%sT	1991
      +			4:00	-	URAT	1991 Dec 16 # independence
      +			4:00 RussiaAsia	ORA%sT	2005 Mar 15 # Oral Time
      +			5:00	-	ORAT
      +
      +# Kyrgyzstan (Kirgizstan)
      +# Transitions through 1991 are from Shanks & Pottenger.
      +
      +# From Paul Eggert (2005-08-15):
      +# According to an article dated today in the Kyrgyzstan Development Gateway
      +# 
      +# Kyrgyzstan is canceling the daylight saving time system.  I take the article
      +# to mean that they will leave their clocks at 6 hours ahead of UTC.
      +# From Malik Abdugaliev (2005-09-21):
      +# Our government cancels daylight saving time 6th of August 2005.
      +# From 2005-08-12 our GMT-offset is +6, w/o any daylight saving.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Kyrgyz	1992	1996	-	Apr	Sun>=7	0:00s	1:00	S
      +Rule	Kyrgyz	1992	1996	-	Sep	lastSun	0:00	0	-
      +Rule	Kyrgyz	1997	2005	-	Mar	lastSun	2:30	1:00	S
      +Rule	Kyrgyz	1997	2004	-	Oct	lastSun	2:30	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Bishkek	4:58:24 -	LMT	1924 May  2
      +			5:00	-	FRUT	1930 Jun 21 # Frunze Time
      +			6:00 RussiaAsia FRU%sT	1991 Mar 31 2:00s
      +			5:00	1:00	FRUST	1991 Aug 31 2:00 # independence
      +			5:00	Kyrgyz	KG%sT	2005 Aug 12    # Kyrgyzstan Time
      +			6:00	-	KGT
      +
      +###############################################################################
      +
      +# Korea (North and South)
      +
      +# From Annie I. Bang (2006-07-10) in
      +# :
      +# The Ministry of Commerce, Industry and Energy has already
      +# commissioned a research project [to reintroduce DST] and has said
      +# the system may begin as early as 2008....  Korea ran a daylight
      +# saving program from 1949-61 but stopped it during the 1950-53 Korean War.
      +
      +# From Shanks & Pottenger:
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	ROK	1960	only	-	May	15	0:00	1:00	D
      +Rule	ROK	1960	only	-	Sep	13	0:00	0	S
      +Rule	ROK	1987	1988	-	May	Sun>=8	0:00	1:00	D
      +Rule	ROK	1987	1988	-	Oct	Sun>=8	0:00	0	S
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Seoul	8:27:52	-	LMT	1890
      +			8:30	-	KST	1904 Dec
      +			9:00	-	KST	1928
      +			8:30	-	KST	1932
      +			9:00	-	KST	1954 Mar 21
      +			8:00	ROK	K%sT	1961 Aug 10
      +			8:30	-	KST	1968 Oct
      +			9:00	ROK	K%sT
      +Zone	Asia/Pyongyang	8:23:00 -	LMT	1890
      +			8:30	-	KST	1904 Dec
      +			9:00	-	KST	1928
      +			8:30	-	KST	1932
      +			9:00	-	KST	1954 Mar 21
      +			8:00	-	KST	1961 Aug 10
      +			9:00	-	KST
      +
      +###############################################################################
      +
      +# Kuwait
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +# From the Arab Times (2007-03-14):
      +# The Civil Service Commission (CSC) has approved a proposal forwarded
      +# by MP Ahmad Baqer on implementing the daylight saving time (DST) in
      +# Kuwait starting from April until the end of Sept this year, reports Al-Anba.
      +# .
      +# From Paul Eggert (2007-03-29):
      +# We don't know the details, or whether the approval means it'll happen,
      +# so for now we assume no DST.
      +Zone	Asia/Kuwait	3:11:56 -	LMT	1950
      +			3:00	-	AST
      +
      +# Laos
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Vientiane	6:50:24 -	LMT	1906 Jun  9 # or Viangchan
      +			7:06:20	-	SMT	1911 Mar 11 0:01 # Saigon MT?
      +			7:00	-	ICT	1912 May
      +			8:00	-	ICT	1931 May
      +			7:00	-	ICT
      +
      +# Lebanon
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Lebanon	1920	only	-	Mar	28	0:00	1:00	S
      +Rule	Lebanon	1920	only	-	Oct	25	0:00	0	-
      +Rule	Lebanon	1921	only	-	Apr	3	0:00	1:00	S
      +Rule	Lebanon	1921	only	-	Oct	3	0:00	0	-
      +Rule	Lebanon	1922	only	-	Mar	26	0:00	1:00	S
      +Rule	Lebanon	1922	only	-	Oct	8	0:00	0	-
      +Rule	Lebanon	1923	only	-	Apr	22	0:00	1:00	S
      +Rule	Lebanon	1923	only	-	Sep	16	0:00	0	-
      +Rule	Lebanon	1957	1961	-	May	1	0:00	1:00	S
      +Rule	Lebanon	1957	1961	-	Oct	1	0:00	0	-
      +Rule	Lebanon	1972	only	-	Jun	22	0:00	1:00	S
      +Rule	Lebanon	1972	1977	-	Oct	1	0:00	0	-
      +Rule	Lebanon	1973	1977	-	May	1	0:00	1:00	S
      +Rule	Lebanon	1978	only	-	Apr	30	0:00	1:00	S
      +Rule	Lebanon	1978	only	-	Sep	30	0:00	0	-
      +Rule	Lebanon	1984	1987	-	May	1	0:00	1:00	S
      +Rule	Lebanon	1984	1991	-	Oct	16	0:00	0	-
      +Rule	Lebanon	1988	only	-	Jun	1	0:00	1:00	S
      +Rule	Lebanon	1989	only	-	May	10	0:00	1:00	S
      +Rule	Lebanon	1990	1992	-	May	1	0:00	1:00	S
      +Rule	Lebanon	1992	only	-	Oct	4	0:00	0	-
      +Rule	Lebanon	1993	max	-	Mar	lastSun	0:00	1:00	S
      +Rule	Lebanon	1993	1998	-	Sep	lastSun	0:00	0	-
      +Rule	Lebanon	1999	max	-	Oct	lastSun	0:00	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Beirut	2:22:00 -	LMT	1880
      +			2:00	Lebanon	EE%sT
      +
      +# Malaysia
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	NBorneo	1935	1941	-	Sep	14	0:00	0:20	TS # one-Third Summer
      +Rule	NBorneo	1935	1941	-	Dec	14	0:00	0	-
      +#
      +# peninsular Malaysia
      +# The data here are taken from Mok Ly Yng (2003-10-30)
      +# .
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Asia/Kuala_Lumpur	6:46:46 -	LMT	1901 Jan  1
      +			6:55:25	-	SMT	1905 Jun  1 # Singapore M.T.
      +			7:00	-	MALT	1933 Jan  1 # Malaya Time
      +			7:00	0:20	MALST	1936 Jan  1
      +			7:20	-	MALT	1941 Sep  1
      +			7:30	-	MALT	1942 Feb 16
      +			9:00	-	JST	1945 Sep 12
      +			7:30	-	MALT	1982 Jan  1
      +			8:00	-	MYT	# Malaysia Time
      +# Sabah & Sarawak
      +# From Paul Eggert (2006-03-22):
      +# The data here are mostly from Shanks & Pottenger, but the 1942, 1945 and 1982
      +# transition dates are from Mok Ly Yng.
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Asia/Kuching	7:21:20	-	LMT	1926 Mar
      +			7:30	-	BORT	1933	# Borneo Time
      +			8:00	NBorneo	BOR%sT	1942 Feb 16
      +			9:00	-	JST	1945 Sep 12
      +			8:00	-	BORT	1982 Jan  1
      +			8:00	-	MYT
      +
      +# Maldives
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Indian/Maldives	4:54:00 -	LMT	1880	# Male
      +			4:54:00	-	MMT	1960	# Male Mean Time
      +			5:00	-	MVT		# Maldives Time
      +
      +# Mongolia
      +
      +# Shanks & Pottenger say that Mongolia has three time zones, but
      +# usno1995 and the CIA map Standard Time Zones of the World (2005-03)
      +# both say that it has just one.
      +
      +# From Oscar van Vlijmen (1999-12-11):
      +# 
      +# General Information Mongolia
      +#  (1999-09)
      +# "Time: Mongolia has two time zones. Three westernmost provinces of
      +# Bayan-Ulgii, Uvs, and Hovd are one hour earlier than the capital city, and
      +# the rest of the country follows the Ulaanbaatar time, which is UTC/GMT plus
      +# eight hours."
      +
      +# From Rives McDow (1999-12-13):
      +# Mongolia discontinued the use of daylight savings time in 1999; 1998
      +# being the last year it was implemented.  The dates of implementation I am
      +# unsure of, but most probably it was similar to Russia, except for the time
      +# of implementation may have been different....
      +# Some maps in the past have indicated that there was an additional time
      +# zone in the eastern part of Mongolia, including the provinces of Dornod,
      +# Suhbaatar, and possibly Khentij.
      +
      +# From Paul Eggert (1999-12-15):
      +# Naming and spelling is tricky in Mongolia.
      +# We'll use Hovd (also spelled Chovd and Khovd) to represent the west zone;
      +# the capital of the Hovd province is sometimes called Hovd, sometimes Dund-Us,
      +# and sometimes Jirgalanta (with variant spellings), but the name Hovd
      +# is good enough for our purposes.
      +
      +# From Rives McDow (2001-05-13):
      +# In addition to Mongolia starting daylight savings as reported earlier
      +# (adopted DST on 2001-04-27 02:00 local time, ending 2001-09-28),
      +# there are three time zones.
      +#
      +# Provinces [at 7:00]: Bayan-ulgii, Uvs, Khovd, Zavkhan, Govi-Altai
      +# Provinces [at 8:00]: Khovsgol, Bulgan, Arkhangai, Khentii, Tov,
      +#	Bayankhongor, Ovorkhangai, Dundgovi, Dornogovi, Omnogovi
      +# Provinces [at 9:00]: Dornod, Sukhbaatar
      +#
      +# [The province of Selenge is omitted from the above lists.]
      +
      +# From Ganbold Ts., Ulaanbaatar (2004-04-17):
      +# Daylight saving occurs at 02:00 local time last Saturday of March.
      +# It will change back to normal at 02:00 local time last Saturday of
      +# September.... As I remember this rule was changed in 2001.
      +#
      +# From Paul Eggert (2004-04-17):
      +# For now, assume Rives McDow's informant got confused about Friday vs
      +# Saturday, and that his 2001 dates should have 1 added to them.
      +
      +# From Paul Eggert (2005-07-26):
      +# We have wildly conflicting information about Mongolia's time zones.
      +# Bill Bonnet (2005-05-19) reports that the US Embassy in Ulaanbaatar says
      +# there is only one time zone and that DST is observed, citing Microsoft
      +# Windows XP as the source.  Risto Nykanen (2005-05-16) reports that
      +# travelmongolia.org says there are two time zones (UTC+7, UTC+8) with no DST.
      +# Oscar van Vlijmen (2005-05-20) reports that the Mongolian Embassy in
      +# Washington, DC says there are two time zones, with DST observed.
      +# He also found
      +# 
      +# which also says that there is DST, and which has a comment by "Toddius"
      +# (2005-03-31 06:05 +0700) saying "Mongolia actually has 3.5 time zones.
      +# The West (OLGII) is +7 GMT, most of the country is ULAT is +8 GMT
      +# and some Eastern provinces are +9 GMT but Sukhbaatar Aimag is SUHK +8.5 GMT.
      +# The SUKH timezone is new this year, it is one of the few things the
      +# parliament passed during the tumultuous winter session."
      +# For now, let's ignore this information, until we have more confirmation.
      +
      +# From Ganbold Ts. (2007-02-26):
      +# Parliament of Mongolia has just changed the daylight-saving rule in February.
      +# They decided not to adopt daylight-saving time....
      +# http://www.mongolnews.mn/index.php?module=unuudur&sec=view&id=15742
      +
      +# From Deborah Goldsmith (2008-03-30):
      +# We received a bug report claiming that the tz database UTC offset for
      +# Asia/Choibalsan (GMT+09:00) is incorrect, and that it should be GMT
      +# +08:00 instead. Different sources appear to disagree with the tz
      +# database on this, e.g.:
      +#
      +# 
      +# http://www.timeanddate.com/worldclock/city.html?n=1026
      +# 
      +# 
      +# http://www.worldtimeserver.com/current_time_in_MN.aspx
      +# 
      +#
      +# both say GMT+08:00.
      +
      +# From Steffen Thorsen (2008-03-31):
      +# eznis airways, which operates several domestic flights, has a flight
      +# schedule here:
      +# 
      +# http://www.eznis.com/Container.jsp?id=112
      +# 
      +# (click the English flag for English)
      +#
      +# There it appears that flights between Choibalsan and Ulaanbatar arrive
      +# about 1:35 - 1:50 hours later in local clock time, no matter the
      +# direction, while Ulaanbaatar-Khvod takes 2 hours in the Eastern
      +# direction and 3:35 back, which indicates that Ulaanbatar and Khvod are
      +# in different time zones (like we know about), while Choibalsan and
      +# Ulaanbatar are in the same time zone (correction needed).
      +
      +# From Arthur David Olson (2008-05-19):
      +# Assume that Choibalsan is indeed offset by 8:00.
      +# XXX--in the absence of better information, assume that transition
      +# was at the start of 2008-03-31 (the day of Steffen Thorsen's report);
      +# this is almost surely wrong.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Mongol	1983	1984	-	Apr	1	0:00	1:00	S
      +Rule	Mongol	1983	only	-	Oct	1	0:00	0	-
      +# Shanks & Pottenger and IATA SSIM say 1990s switches occurred at 00:00,
      +# but McDow says the 2001 switches occurred at 02:00.  Also, IATA SSIM
      +# (1996-09) says 1996-10-25.  Go with Shanks & Pottenger through 1998.
      +#
      +# Shanks & Pottenger say that the Sept. 1984 through Sept. 1990 switches
      +# in Choibalsan (more precisely, in Dornod and Sukhbaatar) took place
      +# at 02:00 standard time, not at 00:00 local time as in the rest of
      +# the country.  That would be odd, and possibly is a result of their
      +# correction of 02:00 (in the previous edition) not being done correctly
      +# in the latest edition; so ignore it for now.
      +
      +Rule	Mongol	1985	1998	-	Mar	lastSun	0:00	1:00	S
      +Rule	Mongol	1984	1998	-	Sep	lastSun	0:00	0	-
      +# IATA SSIM (1999-09) says Mongolia no longer observes DST.
      +Rule	Mongol	2001	only	-	Apr	lastSat	2:00	1:00	S
      +Rule	Mongol	2001	2006	-	Sep	lastSat	2:00	0	-
      +Rule	Mongol	2002	2006	-	Mar	lastSat	2:00	1:00	S
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +# Hovd, a.k.a. Chovd, Dund-Us, Dzhargalant, Khovd, Jirgalanta
      +Zone	Asia/Hovd	6:06:36 -	LMT	1905 Aug
      +			6:00	-	HOVT	1978	# Hovd Time
      +			7:00	Mongol	HOV%sT
      +# Ulaanbaatar, a.k.a. Ulan Bataar, Ulan Bator, Urga
      +Zone	Asia/Ulaanbaatar 7:07:32 -	LMT	1905 Aug
      +			7:00	-	ULAT	1978	# Ulaanbaatar Time
      +			8:00	Mongol	ULA%sT
      +# Choibalsan, a.k.a. Bajan Tuemen, Bajan Tumen, Chojbalsan,
      +# Choybalsan, Sanbejse, Tchoibalsan
      +Zone	Asia/Choibalsan	7:38:00 -	LMT	1905 Aug
      +			7:00	-	ULAT	1978
      +			8:00	-	ULAT	1983 Apr
      +			9:00	Mongol	CHO%sT	2008 Mar 31 # Choibalsan Time
      +			8:00	Mongol	CHO%sT
      +
      +# Nepal
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Kathmandu	5:41:16 -	LMT	1920
      +			5:30	-	IST	1986
      +			5:45	-	NPT	# Nepal Time
      +
      +# Oman
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Muscat	3:54:20 -	LMT	1920
      +			4:00	-	GST
      +
      +# Pakistan
      +
      +# From Rives McDow (2002-03-13):
      +# I have been advised that Pakistan has decided to adopt dst on a
      +# TRIAL basis for one year, starting 00:01 local time on April 7, 2002
      +# and ending at 00:01 local time October 6, 2002.  This is what I was
      +# told, but I believe that the actual time of change may be 00:00; the
      +# 00:01 was to make it clear which day it was on.
      +
      +# From Paul Eggert (2002-03-15):
      +# Jesper Norgaard found this URL:
      +# http://www.pak.gov.pk/public/news/app/app06_dec.htm
      +# (dated 2001-12-06) which says that the Cabinet adopted a scheme "to
      +# advance the clocks by one hour on the night between the first
      +# Saturday and Sunday of April and revert to the original position on
      +# 15th October each year".  This agrees with McDow's 04-07 at 00:00,
      +# but disagrees about the October transition, and makes it sound like
      +# it's not on a trial basis.  Also, the "between the first Saturday
      +# and Sunday of April" phrase, if taken literally, means that the
      +# transition takes place at 00:00 on the first Sunday on or after 04-02.
      +
      +# From Paul Eggert (2003-02-09):
      +# DAWN  reported on 2002-10-05
      +# that 2002 DST ended that day at midnight.  Go with McDow for now.
      +
      +# From Steffen Thorsen (2003-03-14):
      +# According to http://www.dawn.com/2003/03/07/top15.htm
      +# there will be no DST in Pakistan this year:
      +#
      +# ISLAMABAD, March 6: Information and Media Development Minister Sheikh
      +# Rashid Ahmed on Thursday said the cabinet had reversed a previous
      +# decision to advance clocks by one hour in summer and put them back by
      +# one hour in winter with the aim of saving light hours and energy.
      +#
      +# The minister told a news conference that the experiment had rather
      +# shown 8 per cent higher consumption of electricity.
      +
      +# From Alex Krivenyshev (2008-05-15):
      +#
      +# Here is an article that Pakistan plan to introduce Daylight Saving Time
      +# on June 1, 2008 for 3 months.
      +#
      +# "... The federal cabinet on Wednesday announced a new conservation plan to help
      +# reduce load shedding by approving the closure of commercial centres at 9pm and
      +# moving clocks forward by one hour for the next three months.
      +# ...."
      +#
      +# 
      +# http://www.worldtimezone.net/dst_news/dst_news_pakistan01.html
      +# 
      +# OR
      +# 
      +# http://www.dailytimes.com.pk/default.asp?page=2008%5C05%5C15%5Cstory_15-5-2008_pg1_4
      +# 
      +
      +# From Arthur David Olson (2008-05-19):
      +# XXX--midnight transitions is a guess; 2008 only is a guess.
      +
      +# From Alexander Krivenyshev (2008-08-28):
      +# Pakistan government has decided to keep the watches one-hour advanced
      +# for another 2 months--plan to return to Standard Time on October 31
      +# instead of August 31.
      +#
      +# 
      +# http://www.worldtimezone.com/dst_news/dst_news_pakistan02.html
      +# 
      +# OR
      +# 
      +# http://dailymailnews.com/200808/28/news/dmbrn03.html
      +# 
      +
      +# From Alexander Krivenyshev (2009-04-08):
      +# Based on previous media reports that "... proposed plan to
      +# advance clocks by one hour from May 1 will cause disturbance
      +# to the working schedules rather than bringing discipline in
      +# official working."
      +# 
      +# http://www.thenews.com.pk/daily_detail.asp?id=171280
      +# 
      +#
      +# recent news that instead of May 2009 - Pakistan plan to
      +# introduce DST from April 15, 2009
      +#
      +# FYI: Associated Press Of Pakistan
      +# April 08, 2009
      +# Cabinet okays proposal to advance clocks by one hour from April 15
      +# 
      +# http://www.app.com.pk/en_/index.php?option=com_content&task=view&id=73043&Itemid=1
      +# 
      +#
      +# or
      +#
      +# 
      +# http://www.worldtimezone.com/dst_news/dst_news_pakistan05.html
      +# 
      +#
      +# ....
      +# The Federal Cabinet on Wednesday approved the proposal to
      +# advance clocks in the country by one hour from April 15 to
      +# conserve energy"
      +
      +# From Steffen Thorsen (2009-09-17):
      +# "The News International," Pakistan reports that: "The Federal
      +# Government has decided to restore the previous time by moving the
      +# clocks backward by one hour from October 1. A formal announcement to
      +# this effect will be made after the Prime Minister grants approval in
      +# this regard."
      +# 
      +# http://www.thenews.com.pk/updates.asp?id=87168
      +# 
      +
      +# From Alexander Krivenyshev (2009-09-28):
      +# According to Associated Press Of Pakistan, it is confirmed that
      +# Pakistan clocks across the country would be turned back by an hour from October
      +# 1, 2009.
      +#
      +# "Clocks to go back one hour from 1 Oct"
      +# 
      +# http://www.app.com.pk/en_/index.php?option=com_content&task=view&id=86715&Itemid=2
      +# 
      +# or
      +# 
      +# http://www.worldtimezone.com/dst_news/dst_news_pakistan07.htm
      +# 
      +
      +# From Steffen Thorsen (2009-09-29):
      +# Alexander Krivenyshev wrote:
      +# > According to Associated Press Of Pakistan, it is confirmed that
      +# > Pakistan clocks across the country would be turned back by an hour from October
      +# > 1, 2009.
      +#
      +# Now they seem to have changed their mind, November 1 is the new date:
      +# 
      +# http://www.thenews.com.pk/top_story_detail.asp?Id=24742
      +# 
      +# "The country's clocks will be reversed by one hour on November 1.
      +# Officials of Federal Ministry for Interior told this to Geo News on
      +# Monday."
      +#
      +# And more importantly, it seems that these dates will be kept every year:
      +# "It has now been decided that clocks will be wound forward by one hour
      +# on April 15 and reversed by an hour on November 1 every year without
      +# obtaining prior approval, the officials added."
      +#
      +# We have confirmed this year's end date with both with the Ministry of
      +# Water and Power and the Pakistan Electric Power Company:
      +# 
      +# http://www.timeanddate.com/news/time/pakistan-ends-dst09.html
      +# 
      +
      +# From Christoph Goehre (2009-10-01):
      +# [T]he German Consulate General in Karachi reported me today that Pakistan
      +# will go back to standard time on 1st of November.
      +
      +# From Steffen Thorsen (2010-03-26):
      +# Steffen Thorsen wrote:
      +# > On Thursday (2010-03-25) it was announced that DST would start in
      +# > Pakistan on 2010-04-01.
      +# >
      +# > Then today, the president said that they might have to revert the
      +# > decision if it is not supported by the parliament. So at the time
      +# > being, it seems unclear if DST will be actually observed or not - but
      +# > April 1 could be a more likely date than April 15.
      +# Now, it seems that the decision to not observe DST in final:
      +#
      +# "Govt Withdraws Plan To Advance Clocks"
      +# 
      +# http://www.apakistannews.com/govt-withdraws-plan-to-advance-clocks-172041
      +# 
      +#
      +# "People laud PM's announcement to end DST"
      +# 
      +# http://www.app.com.pk/en_/index.php?option=com_content&task=view&id=99374&Itemid=2
      +# 
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule Pakistan	2002	only	-	Apr	Sun>=2	0:01	1:00	S
      +Rule Pakistan	2002	only	-	Oct	Sun>=2	0:01	0	-
      +Rule Pakistan	2008	only	-	Jun	1	0:00	1:00	S
      +Rule Pakistan	2008	only	-	Nov	1	0:00	0	-
      +Rule Pakistan	2009	only	-	Apr	15	0:00	1:00	S
      +Rule Pakistan	2009	only	-	Nov	1	0:00	0	-
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Karachi	4:28:12 -	LMT	1907
      +			5:30	-	IST	1942 Sep
      +			5:30	1:00	IST	1945 Oct 15
      +			5:30	-	IST	1951 Sep 30
      +			5:00	-	KART	1971 Mar 26 # Karachi Time
      +			5:00 Pakistan	PK%sT	# Pakistan Time
      +
      +# Palestine
      +
      +# From Amos Shapir (1998-02-15):
      +#
      +# From 1917 until 1948-05-15, all of Palestine, including the parts now
      +# known as the Gaza Strip and the West Bank, was under British rule.
      +# Therefore the rules given for Israel for that period, apply there too...
      +#
      +# The Gaza Strip was under Egyptian rule between 1948-05-15 until 1967-06-05
      +# (except a short occupation by Israel from 1956-11 till 1957-03, but no
      +# time zone was affected then).  It was never formally annexed to Egypt,
      +# though.
      +#
      +# The rest of Palestine was under Jordanian rule at that time, formally
      +# annexed in 1950 as the West Bank (and the word "Trans" was dropped from
      +# the country's previous name of "the Hashemite Kingdom of the
      +# Trans-Jordan").  So the rules for Jordan for that time apply.  Major
      +# towns in that area are Nablus (Shchem), El-Halil (Hebron), Ramallah, and
      +# East Jerusalem.
      +#
      +# Both areas were occupied by Israel in June 1967, but not annexed (except
      +# for East Jerusalem).  They were on Israel time since then; there might
      +# have been a Military Governor's order about time zones, but I'm not aware
      +# of any (such orders may have been issued semi-annually whenever summer
      +# time was in effect, but maybe the legal aspect of time was just neglected).
      +#
      +# The Palestinian Authority was established in 1993, and got hold of most
      +# towns in the West Bank and Gaza by 1995.  I know that in order to
      +# demonstrate...independence, they have been switching to
      +# summer time and back on a different schedule than Israel's, but I don't
      +# know when this was started, or what algorithm is used (most likely the
      +# Jordanian one).
      +#
      +# To summarize, the table should probably look something like that:
      +#
      +# Area \ when | 1918-1947 | 1948-1967 | 1967-1995 | 1996-
      +# ------------+-----------+-----------+-----------+-----------
      +# Israel      | Zion      | Zion      | Zion      | Zion
      +# West bank   | Zion      | Jordan    | Zion      | Jordan
      +# Gaza        | Zion      | Egypt     | Zion      | Jordan
      +#
      +# I guess more info may be available from the PA's web page (if/when they
      +# have one).
      +
      +# From Paul Eggert (2006-03-22):
      +# Shanks & Pottenger write that Gaza did not observe DST until 1957, but go
      +# with Shapir and assume that it observed DST from 1940 through 1947,
      +# and that it used Jordanian rules starting in 1996.
      +# We don't yet need a separate entry for the West Bank, since
      +# the only differences between it and Gaza that we know about
      +# occurred before our cutoff date of 1970.
      +# However, as we get more information, we may need to add entries
      +# for parts of the West Bank as they transitioned from Israel's rules
      +# to Palestine's rules.  If you have more info about this, please
      +# send it to tz@elsie.nci.nih.gov for incorporation into future editions.
      +
      +# From IINS News Service - Israel - 1998-03-23 10:38:07 Israel time,
      +# forwarded by Ephraim Silverberg:
      +#
      +# Despite the fact that Israel changed over to daylight savings time
      +# last week, the PLO Authority (PA) has decided not to turn its clocks
      +# one-hour forward at this time.  As a sign of independence from Israeli rule,
      +# the PA has decided to implement DST in April.
      +
      +# From Paul Eggert (1999-09-20):
      +# Daoud Kuttab writes in
      +# 
      +# Holiday havoc
      +#  (Jerusalem Post, 1999-04-22) that
      +# the Palestinian National Authority changed to DST on 1999-04-15.
      +# I vaguely recall that they switch back in October (sorry, forgot the source).
      +# For now, let's assume that the spring switch was at 24:00,
      +# and that they switch at 0:00 on the 3rd Fridays of April and October.
      +
      +# From Paul Eggert (2005-11-22):
      +# Starting 2004 transitions are from Steffen Thorsen's web site timeanddate.com.
      +
      +# From Steffen Thorsen (2005-11-23):
      +# A user from Gaza reported that Gaza made the change early because of
      +# the Ramadan.  Next year Ramadan will be even earlier, so I think
      +# there is a good chance next year's end date will be around two weeks
      +# earlier--the same goes for Jordan.
      +
      +# From Steffen Thorsen (2006-08-17):
      +# I was informed by a user in Bethlehem that in Bethlehem it started the
      +# same day as Israel, and after checking with other users in the area, I
      +# was informed that they started DST one day after Israel.  I was not
      +# able to find any authoritative sources at the time, nor details if
      +# Gaza changed as well, but presumed Gaza to follow the same rules as
      +# the West Bank.
      +
      +# From Steffen Thorsen (2006-09-26):
      +# according to the Palestine News Network (2006-09-19):
      +# http://english.pnn.ps/index.php?option=com_content&task=view&id=596&Itemid=5
      +# > The Council of Ministers announced that this year its winter schedule
      +# > will begin early, as of midnight Thursday.  It is also time to turn
      +# > back the clocks for winter.  Friday will begin an hour late this week.
      +# I guess it is likely that next year's date will be moved as well,
      +# because of the Ramadan.
      +
      +# From Jesper Norgaard Welen (2007-09-18):
      +# According to Steffen Thorsen's web site the Gaza Strip and the rest of the
      +# Palestinian territories left DST early on 13.th. of September at 2:00.
      +
      +# From Paul Eggert (2007-09-20):
      +# My understanding is that Gaza and the West Bank disagree even over when
      +# the weekend is (Thursday+Friday versus Friday+Saturday), so I'd be a bit
      +# surprised if they agreed about DST.  But for now, assume they agree.
      +# For lack of better information, predict that future changes will be
      +# the 2nd Thursday of September at 02:00.
      +
      +# From Alexander Krivenyshev (2008-08-28):
      +# Here is an article, that Mideast running on different clocks at Ramadan.
      +#
      +# Gaza Strip (as Egypt) ended DST at midnight Thursday (Aug 28, 2008), while
      +# the West Bank will end Daylight Saving Time at midnight Sunday (Aug 31, 2008).
      +#
      +# 
      +# http://www.guardian.co.uk/world/feedarticle/7759001
      +# 
      +# 
      +# http://www.abcnews.go.com/International/wireStory?id=5676087
      +# 
      +# or
      +# 
      +# http://www.worldtimezone.com/dst_news/dst_news_gazastrip01.html
      +# 
      +
      +# From Alexander Krivenyshev (2009-03-26):
      +# According to the Palestine News Network (arabic.pnn.ps), Palestinian
      +# government decided to start Daylight Time on Thursday night March
      +# 26 and continue until the night of 27 September 2009.
      +#
      +# (in Arabic)
      +# 
      +# http://arabic.pnn.ps/index.php?option=com_content&task=view&id=50850
      +# 
      +#
      +# or
      +# (English translation)
      +# 
      +# http://www.worldtimezone.com/dst_news/dst_news_westbank01.html
      +# 
      +
      +# From Steffen Thorsen (2009-08-31):
      +# Palestine's Council of Ministers announced that they will revert back to
      +# winter time on Friday, 2009-09-04.
      +#
      +# One news source:
      +# 
      +# http://www.safa.ps/ara/?action=showdetail&seid=4158
      +# 
      +# (Palestinian press agency, Arabic),
      +# Google translate: "Decided that the Palestinian government in Ramallah
      +# headed by Salam Fayyad, the start of work in time for the winter of
      +# 2009, starting on Friday approved the fourth delay Sept. clock sixty
      +# minutes per hour as of Friday morning."
      +#
      +# We are not sure if Gaza will do the same, last year they had a different
      +# end date, we will keep this page updated:
      +# 
      +# http://www.timeanddate.com/news/time/westbank-gaza-dst-2009.html
      +# 
      +
      +# From Alexander Krivenyshev (2009-09-02):
      +# Seems that Gaza Strip will go back to Winter Time same date as West Bank.
      +#
      +# According to Palestinian Ministry Of Interior, West Bank and Gaza Strip plan
      +# to change time back to Standard time on September 4, 2009.
      +#
      +# "Winter time unite the West Bank and Gaza"
      +# (from Palestinian National Authority):
      +# 
      +# http://www.worldtimezone.com/dst_news/dst_news_gazastrip02.html
      +# 
      +
      +# From Alexander Krivenyshev (2010-03-19):
      +# According to Voice of Palestine DST will last for 191 days, from March
      +# 26, 2010 till "the last Sunday before the tenth day of Tishri
      +# (October), each year" (October 03, 2010?)
      +#
      +# 
      +# http://palvoice.org/forums/showthread.php?t=245697
      +# 
      +# (in Arabic)
      +# or
      +# 
      +# http://www.worldtimezone.com/dst_news/dst_news_westbank03.html
      +# 
      +
      +# From Steffen Thorsen (2010-03-24):
      +# ...Ma'an News Agency reports that Hamas cabinet has decided it will
      +# start one day later, at 12:01am. Not sure if they really mean 12:01am or
      +# noon though:
      +#
      +# 
      +# http://www.maannews.net/eng/ViewDetails.aspx?ID=271178
      +# 
      +# (Ma'an News Agency)
      +# "At 12:01am Friday, clocks in Israel and the West Bank will change to
      +# 1:01am, while Gaza clocks will change at 12:01am Saturday morning."
      +
      +# From Steffen Thorsen (2010-08-11):
      +# According to several sources, including
      +# 
      +# http://www.maannews.net/eng/ViewDetails.aspx?ID=306795
      +# 
      +# the clocks were set back one hour at 2010-08-11 00:00:00 local time in
      +# Gaza and the West Bank.
      +# Some more background info:
      +# 
      +# http://www.timeanddate.com/news/time/westbank-gaza-end-dst-2010.html
      +# 
      +
      +# From Steffen Thorsen (2011-08-26):
      +# Gaza and the West Bank did go back to standard time in the beginning of
      +# August, and will now enter daylight saving time again on 2011-08-30
      +# 00:00 (so two periods of DST in 2011). The pause was because of
      +# Ramadan.
      +#
      +# 
      +# http://www.maannews.net/eng/ViewDetails.aspx?ID=416217
      +# 
      +# Additional info:
      +# 
      +# http://www.timeanddate.com/news/time/palestine-dst-2011.html
      +# 
      +
      +# From Alexander Krivenyshev (2011-08-27):
      +# According to the article in The Jerusalem Post:
      +# "...Earlier this month, the Palestinian government in the West Bank decided to
      +# move to standard time for 30 days, during Ramadan. The Palestinians in the
      +# Gaza Strip accepted the change and also moved their clocks one hour back.
      +# The Hamas government said on Saturday that it won't observe summertime after
      +# the Muslim feast of Id al-Fitr, which begins on Tuesday..."
      +# ...
      +# 
      +# http://www.jpost.com/MiddleEast/Article.aspx?id=235650
      +# 
      +# or
      +# 
      +# http://www.worldtimezone.com/dst_news/dst_news_gazastrip05.html
      +# 
      +# The rules for Egypt are stolen from the `africa' file.
      +
      +# From Steffen Thorsen (2011-09-30):
      +# West Bank did end Daylight Saving Time this morning/midnight (2011-09-30
      +# 00:00).
      +# So West Bank and Gaza now have the same time again.
      +#
      +# Many sources, including:
      +# 
      +# http://www.maannews.net/eng/ViewDetails.aspx?ID=424808
      +# 
      +
      +# From Steffen Thorsen (2012-03-26):
      +# Palestinian news sources tell that both Gaza and West Bank will start DST
      +# on Friday (Thursday midnight, 2012-03-29 24:00).
      +# Some of many sources in Arabic:
      +# 
      +# http://www.samanews.com/index.php?act=Show&id=122638
      +# 
      +#
      +# 
      +# http://safa.ps/details/news/74352/%D8%A8%D8%AF%D8%A1-%D8%A7%D9%84%D8%AA%D9%88%D9%82%D9%8A%D8%AA-%D8%A7%D9%84%D8%B5%D9%8A%D9%81%D9%8A-%D8%A8%D8%A7%D9%84%D8%B6%D9%81%D8%A9-%D9%88%D8%BA%D8%B2%D8%A9-%D9%84%D9%8A%D9%84%D8%A9-%D8%A7%D9%84%D8%AC%D9%85%D8%B9%D8%A9.html
      +# 
      +#
      +# Our brief summary:
      +# 
      +# http://www.timeanddate.com/news/time/gaza-west-bank-dst-2012.html
      +# 
      +
      +# From Arthur David Olson (2012-03-27):
      +# The timeanddate article for 2012 says that "the end date has not yet been
      +# announced" and that "Last year, both...paused daylight saving time during...
      +# Ramadan. It is not yet known [for] 2012."
      +# For now, assume both switch back on the last Friday in September. XXX
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule EgyptAsia	1957	only	-	May	10	0:00	1:00	S
      +Rule EgyptAsia	1957	1958	-	Oct	 1	0:00	0	-
      +Rule EgyptAsia	1958	only	-	May	 1	0:00	1:00	S
      +Rule EgyptAsia	1959	1967	-	May	 1	1:00	1:00	S
      +Rule EgyptAsia	1959	1965	-	Sep	30	3:00	0	-
      +Rule EgyptAsia	1966	only	-	Oct	 1	3:00	0	-
      +
      +Rule Palestine	1999	2005	-	Apr	Fri>=15	0:00	1:00	S
      +Rule Palestine	1999	2003	-	Oct	Fri>=15	0:00	0	-
      +Rule Palestine	2004	only	-	Oct	 1	1:00	0	-
      +Rule Palestine	2005	only	-	Oct	 4	2:00	0	-
      +Rule Palestine	2006	2008	-	Apr	 1	0:00	1:00	S
      +Rule Palestine	2006	only	-	Sep	22	0:00	0	-
      +Rule Palestine	2007	only	-	Sep	Thu>=8	2:00	0	-
      +Rule Palestine	2008	only	-	Aug	lastFri	0:00	0	-
      +Rule Palestine	2009	only	-	Mar	lastFri	0:00	1:00	S
      +Rule Palestine	2009	only	-	Sep	Fri>=1	2:00	0	-
      +Rule Palestine	2010	only	-	Mar	lastSat	0:01	1:00	S
      +Rule Palestine	2010	only	-	Aug	11	0:00	0	-
      +
      +# From Arthur David Olson (2011-09-20):
      +# 2011 transitions per http://www.timeanddate.com as of 2011-09-20.
      +# From Paul Eggert (2012-10-12):
      +# 2012 transitions per http://www.timeanddate.com as of 2012-10-12.
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Gaza	2:17:52	-	LMT	1900 Oct
      +			2:00	Zion	EET	1948 May 15
      +			2:00 EgyptAsia	EE%sT	1967 Jun  5
      +			2:00	Zion	I%sT	1996
      +			2:00	Jordan	EE%sT	1999
      +			2:00 Palestine	EE%sT	2011 Apr  2 12:01
      +			2:00	1:00	EEST	2011 Aug  1
      +			2:00	-	EET	2012 Mar 30
      +			2:00	1:00	EEST	2012 Sep 21 1:00
      +			2:00	-	EET
      +
      +Zone	Asia/Hebron	2:20:23	-	LMT	1900 Oct
      +			2:00	Zion	EET	1948 May 15
      +			2:00 EgyptAsia	EE%sT	1967 Jun  5
      +			2:00	Zion	I%sT	1996
      +			2:00	Jordan	EE%sT	1999
      +			2:00 Palestine	EE%sT	2008 Aug
      +			2:00 	1:00	EEST	2008 Sep
      +			2:00 Palestine	EE%sT	2011 Apr  1 12:01
      +			2:00	1:00	EEST	2011 Aug  1
      +			2:00	-	EET	2011 Aug 30
      +			2:00	1:00	EEST	2011 Sep 30 3:00
      +			2:00	-	EET	2012 Mar 30
      +			2:00	1:00	EEST	2012 Sep 21 1:00
      +			2:00	-	EET
      +
      +# Paracel Is
      +# no information
      +
      +# Philippines
      +# On 1844-08-16, Narciso Claveria, governor-general of the
      +# Philippines, issued a proclamation announcing that 1844-12-30 was to
      +# be immediately followed by 1845-01-01.  Robert H. van Gent has a
      +# transcript of the decree in .
      +# The rest of the data are from Shanks & Pottenger.
      +
      +# From Paul Eggert (2006-04-25):
      +# Tomorrow's Manila Standard reports that the Philippines Department of
      +# Trade and Industry is considering adopting DST this June when the
      +# rainy season begins.  See
      +# .
      +# For now, we'll ignore this, since it's not definite and we lack details.
      +#
      +# From Jesper Norgaard Welen (2006-04-26):
      +# ... claims that Philippines had DST last time in 1990:
      +# http://story.philippinetimes.com/p.x/ct/9/id/145be20cc6b121c0/cid/3e5bbccc730d258c/
      +# [a story dated 2006-04-25 by Cris Larano of Dow Jones Newswires,
      +# but no details]
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Phil	1936	only	-	Nov	1	0:00	1:00	S
      +Rule	Phil	1937	only	-	Feb	1	0:00	0	-
      +Rule	Phil	1954	only	-	Apr	12	0:00	1:00	S
      +Rule	Phil	1954	only	-	Jul	1	0:00	0	-
      +Rule	Phil	1978	only	-	Mar	22	0:00	1:00	S
      +Rule	Phil	1978	only	-	Sep	21	0:00	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Manila	-15:56:00 -	LMT	1844 Dec 31
      +			8:04:00 -	LMT	1899 May 11
      +			8:00	Phil	PH%sT	1942 May
      +			9:00	-	JST	1944 Nov
      +			8:00	Phil	PH%sT
      +
      +# Qatar
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Qatar	3:26:08 -	LMT	1920	# Al Dawhah / Doha
      +			4:00	-	GST	1972 Jun
      +			3:00	-	AST
      +
      +# Saudi Arabia
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Riyadh	3:06:52 -	LMT	1950
      +			3:00	-	AST
      +
      +# Singapore
      +# The data here are taken from Mok Ly Yng (2003-10-30)
      +# .
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Singapore	6:55:25 -	LMT	1901 Jan  1
      +			6:55:25	-	SMT	1905 Jun  1 # Singapore M.T.
      +			7:00	-	MALT	1933 Jan  1 # Malaya Time
      +			7:00	0:20	MALST	1936 Jan  1
      +			7:20	-	MALT	1941 Sep  1
      +			7:30	-	MALT	1942 Feb 16
      +			9:00	-	JST	1945 Sep 12
      +			7:30	-	MALT	1965 Aug  9 # independence
      +			7:30	-	SGT	1982 Jan  1 # Singapore Time
      +			8:00	-	SGT
      +
      +# Spratly Is
      +# no information
      +
      +# Sri Lanka
      +# From Paul Eggert (1996-09-03):
      +# "Sri Lanka advances clock by an hour to avoid blackout"
      +# (www.virtual-pc.com/lankaweb/news/items/240596-2.html, 1996-05-24,
      +# no longer available as of 1999-08-17)
      +# reported ``the country's standard time will be put forward by one hour at
      +# midnight Friday (1830 GMT) `in the light of the present power crisis'.''
      +#
      +# From Dharmasiri Senanayake, Sri Lanka Media Minister (1996-10-24), as quoted
      +# by Shamindra in
      +# 
      +# Daily News - Hot News Section (1996-10-26)
      +# :
      +# With effect from 12.30 a.m. on 26th October 1996
      +# Sri Lanka will be six (06) hours ahead of GMT.
      +
      +# From Jesper Norgaard Welen (2006-04-14), quoting Sri Lanka News Online
      +#  (2006-04-13):
      +# 0030 hrs on April 15, 2006 (midnight of April 14, 2006 +30 minutes)
      +# at present, become 2400 hours of April 14, 2006 (midnight of April 14, 2006).
      +
      +# From Peter Apps and Ranga Sirila of Reuters (2006-04-12) in:
      +# 
      +# [The Tamil Tigers] never accepted the original 1996 time change and simply
      +# kept their clocks set five and a half hours ahead of Greenwich Mean
      +# Time (GMT), in line with neighbor India.
      +# From Paul Eggert (2006-04-18):
      +# People who live in regions under Tamil control can use [TZ='Asia/Kolkata'],
      +# as that zone has agreed with the Tamil areas since our cutoff date of 1970.
      +
      +# From K Sethu (2006-04-25):
      +# I think the abbreviation LKT originated from the world of computers at
      +# the time of or subsequent to the time zone changes by SL Government
      +# twice in 1996 and probably SL Government or its standardization
      +# agencies never declared an abbreviation as a national standard.
      +#
      +# I recollect before the recent change the government annoucemments
      +# mentioning it as simply changing Sri Lanka Standard Time or Sri Lanka
      +# Time and no mention was made about the abbreviation.
      +#
      +# If we look at Sri Lanka Department of Government's "Official News
      +# Website of Sri Lanka" ... http://www.news.lk/ we can see that they
      +# use SLT as abbreviation in time stamp at the beginning of each news
      +# item....
      +#
      +# Within Sri Lanka I think LKT is well known among computer users and
      +# adminsitrators.  In my opinion SLT may not be a good choice because the
      +# nation's largest telcom / internet operator Sri Lanka Telcom is well
      +# known by that abbreviation - simply as SLT (there IP domains are
      +# slt.lk and sltnet.lk).
      +#
      +# But if indeed our government has adopted SLT as standard abbreviation
      +# (that we have not known so far) then  it is better that it be used for
      +# all computers.
      +
      +# From Paul Eggert (2006-04-25):
      +# One possibility is that we wait for a bit for the dust to settle down
      +# and then see what people actually say in practice.
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Colombo	5:19:24 -	LMT	1880
      +			5:19:32	-	MMT	1906	# Moratuwa Mean Time
      +			5:30	-	IST	1942 Jan  5
      +			5:30	0:30	IHST	1942 Sep
      +			5:30	1:00	IST	1945 Oct 16 2:00
      +			5:30	-	IST	1996 May 25 0:00
      +			6:30	-	LKT	1996 Oct 26 0:30
      +			6:00	-	LKT	2006 Apr 15 0:30
      +			5:30	-	IST
      +
      +# Syria
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Syria	1920	1923	-	Apr	Sun>=15	2:00	1:00	S
      +Rule	Syria	1920	1923	-	Oct	Sun>=1	2:00	0	-
      +Rule	Syria	1962	only	-	Apr	29	2:00	1:00	S
      +Rule	Syria	1962	only	-	Oct	1	2:00	0	-
      +Rule	Syria	1963	1965	-	May	1	2:00	1:00	S
      +Rule	Syria	1963	only	-	Sep	30	2:00	0	-
      +Rule	Syria	1964	only	-	Oct	1	2:00	0	-
      +Rule	Syria	1965	only	-	Sep	30	2:00	0	-
      +Rule	Syria	1966	only	-	Apr	24	2:00	1:00	S
      +Rule	Syria	1966	1976	-	Oct	1	2:00	0	-
      +Rule	Syria	1967	1978	-	May	1	2:00	1:00	S
      +Rule	Syria	1977	1978	-	Sep	1	2:00	0	-
      +Rule	Syria	1983	1984	-	Apr	9	2:00	1:00	S
      +Rule	Syria	1983	1984	-	Oct	1	2:00	0	-
      +Rule	Syria	1986	only	-	Feb	16	2:00	1:00	S
      +Rule	Syria	1986	only	-	Oct	9	2:00	0	-
      +Rule	Syria	1987	only	-	Mar	1	2:00	1:00	S
      +Rule	Syria	1987	1988	-	Oct	31	2:00	0	-
      +Rule	Syria	1988	only	-	Mar	15	2:00	1:00	S
      +Rule	Syria	1989	only	-	Mar	31	2:00	1:00	S
      +Rule	Syria	1989	only	-	Oct	1	2:00	0	-
      +Rule	Syria	1990	only	-	Apr	1	2:00	1:00	S
      +Rule	Syria	1990	only	-	Sep	30	2:00	0	-
      +Rule	Syria	1991	only	-	Apr	 1	0:00	1:00	S
      +Rule	Syria	1991	1992	-	Oct	 1	0:00	0	-
      +Rule	Syria	1992	only	-	Apr	 8	0:00	1:00	S
      +Rule	Syria	1993	only	-	Mar	26	0:00	1:00	S
      +Rule	Syria	1993	only	-	Sep	25	0:00	0	-
      +# IATA SSIM (1998-02) says 1998-04-02;
      +# (1998-09) says 1999-03-29 and 1999-09-29; (1999-02) says 1999-04-02,
      +# 2000-04-02, and 2001-04-02; (1999-09) says 2000-03-31 and 2001-03-31;
      +# (2006) says 2006-03-31 and 2006-09-22;
      +# for now ignore all these claims and go with Shanks & Pottenger,
      +# except for the 2006-09-22 claim (which seems right for Ramadan).
      +Rule	Syria	1994	1996	-	Apr	 1	0:00	1:00	S
      +Rule	Syria	1994	2005	-	Oct	 1	0:00	0	-
      +Rule	Syria	1997	1998	-	Mar	lastMon	0:00	1:00	S
      +Rule	Syria	1999	2006	-	Apr	 1	0:00	1:00	S
      +# From Stephen Colebourne (2006-09-18):
      +# According to IATA data, Syria will change DST on 21st September [21:00 UTC]
      +# this year [only]....  This is probably related to Ramadan, like Egypt.
      +Rule	Syria	2006	only	-	Sep	22	0:00	0	-
      +# From Paul Eggert (2007-03-29):
      +# Today the AP reported "Syria will switch to summertime at midnight Thursday."
      +# http://www.iht.com/articles/ap/2007/03/29/africa/ME-GEN-Syria-Time-Change.php
      +Rule	Syria	2007	only	-	Mar	lastFri	0:00	1:00	S
      +# From Jesper Norgard (2007-10-27):
      +# The sister center ICARDA of my work CIMMYT is confirming that Syria DST will
      +# not take place 1.st November at 0:00 o'clock but 1.st November at 24:00 or
      +# rather Midnight between Thursday and Friday. This does make more sence than
      +# having it between Wednesday and Thursday (two workdays in Syria) since the
      +# weekend in Syria is not Saturday and Sunday, but Friday and Saturday. So now
      +# it is implemented at midnight of the last workday before weekend...
      +#
      +# From Steffen Thorsen (2007-10-27):
      +# Jesper Norgaard Welen wrote:
      +#
      +# > "Winter local time in Syria will be observed at midnight of Thursday 1
      +# > November 2007, and the clock will be put back 1 hour."
      +#
      +# I found confirmation on this in this gov.sy-article (Arabic):
      +# http://wehda.alwehda.gov.sy/_print_veiw.asp?FileName=12521710520070926111247
      +#
      +# which using Google's translate tools says:
      +# Council of Ministers also approved the commencement of work on
      +# identifying the winter time as of Friday, 2/11/2007 where the 60th
      +# minute delay at midnight Thursday 1/11/2007.
      +Rule	Syria	2007	only	-	Nov	 Fri>=1	0:00	0	-
      +
      +# From Stephen Colebourne (2008-03-17):
      +# For everyone's info, I saw an IATA time zone change for [Syria] for
      +# this month (March 2008) in the last day or so...This is the data IATA
      +# are now using:
      +# Country     Time Standard   --- DST Start ---   --- DST End ---  DST
      +# Name        Zone Variation   Time    Date        Time    Date
      +# Variation
      +# Syrian Arab
      +# Republic    SY    +0200      2200  03APR08       2100  30SEP08   +0300
      +#                              2200  02APR09       2100  30SEP09   +0300
      +#                              2200  01APR10       2100  30SEP10   +0300
      +
      +# From Arthur David Olson (2008-03-17):
      +# Here's a link to English-language coverage by the Syrian Arab News
      +# Agency (SANA)...
      +# 
      +# http://www.sana.sy/eng/21/2008/03/11/165173.htm
      +# ...which reads (in part) "The Cabinet approved the suggestion of the
      +# Ministry of Electricity to begin daylight savings time on Friday April
      +# 4th, advancing clocks one hour ahead on midnight of Thursday April 3rd."
      +# Since Syria is two hours east of UTC, the 2200 and 2100 transition times
      +# shown above match up with midnight in Syria.
      +
      +# From Arthur David Olson (2008-03-18):
      +# My buest guess at a Syrian rule is "the Friday nearest April 1";
      +# coding that involves either using a "Mar Fri>=29" construct that old time zone
      +# compilers can't handle  or having multiple Rules (a la Israel).
      +# For now, use "Apr Fri>=1", and go with IATA on a uniform Sep 30 end.
      +
      +# From Steffen Thorsen (2008-10-07):
      +# Syria has now officially decided to end DST on 2008-11-01 this year,
      +# according to the following article in the Syrian Arab News Agency (SANA).
      +#
      +# The article is in Arabic, and seems to tell that they will go back to
      +# winter time on 2008-11-01 at 00:00 local daylight time (delaying/setting
      +# clocks back 60 minutes).
      +#
      +# 
      +# http://sana.sy/ara/2/2008/10/07/195459.htm
      +# 
      +
      +# From Steffen Thorsen (2009-03-19):
      +# Syria will start DST on 2009-03-27 00:00 this year according to many sources,
      +# two examples:
      +#
      +# 
      +# http://www.sana.sy/eng/21/2009/03/17/217563.htm
      +# 
      +# (English, Syrian Arab News # Agency)
      +# 
      +# http://thawra.alwehda.gov.sy/_View_news2.asp?FileName=94459258720090318012209
      +# 
      +# (Arabic, gov-site)
      +#
      +# We have not found any sources saying anything about when DST ends this year.
      +#
      +# Our summary
      +# 
      +# http://www.timeanddate.com/news/time/syria-dst-starts-march-27-2009.html
      +# 
      +
      +# From Steffen Thorsen (2009-10-27):
      +# The Syrian Arab News Network on 2009-09-29 reported that Syria will
      +# revert back to winter (standard) time on midnight between Thursday
      +# 2009-10-29 and Friday 2009-10-30:
      +# 
      +# http://www.sana.sy/ara/2/2009/09/29/247012.htm (Arabic)
      +# 
      +
      +# From Arthur David Olson (2009-10-28):
      +# We'll see if future DST switching times turn out to be end of the last
      +# Thursday of the month or the start of the last Friday of the month or
      +# something else. For now, use the start of the last Friday.
      +
      +# From Steffen Thorsen (2010-03-17):
      +# The "Syrian News Station" reported on 2010-03-16 that the Council of
      +# Ministers has decided that Syria will start DST on midnight Thursday
      +# 2010-04-01: (midnight between Thursday and Friday):
      +# 
      +# http://sns.sy/sns/?path=news/read/11421 (Arabic)
      +# 
      +
      +# From Steffen Thorsen (2012-03-26):
      +# Today, Syria's government announced that they will start DST early on Friday
      +# (00:00). This is a bit earlier than the past two years.
      +#
      +# From Syrian Arab News Agency, in Arabic:
      +# 
      +# http://www.sana.sy/ara/2/2012/03/26/408215.htm
      +# 
      +#
      +# Our brief summary:
      +# 
      +# http://www.timeanddate.com/news/time/syria-dst-2012.html
      +# 
      +
      +# From Arthur David Olson (2012-03-27):
      +# Assume last Friday in March going forward XXX.
      +
      +Rule	Syria	2008	only	-	Apr	Fri>=1	0:00	1:00	S
      +Rule	Syria	2008	only	-	Nov	1	0:00	0	-
      +Rule	Syria	2009	only	-	Mar	lastFri	0:00	1:00	S
      +Rule	Syria	2010	2011	-	Apr	Fri>=1	0:00	1:00	S
      +Rule	Syria	2012	max	-	Mar	lastFri	0:00	1:00	S
      +Rule	Syria	2009	max	-	Oct	lastFri	0:00	0	-
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Damascus	2:25:12 -	LMT	1920	# Dimashq
      +			2:00	Syria	EE%sT
      +
      +# Tajikistan
      +# From Shanks & Pottenger.
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Dushanbe	4:35:12 -	LMT	1924 May  2
      +			5:00	-	DUST	1930 Jun 21 # Dushanbe Time
      +			6:00 RussiaAsia DUS%sT	1991 Mar 31 2:00s
      +			5:00	1:00	DUSST	1991 Sep  9 2:00s
      +			5:00	-	TJT		    # Tajikistan Time
      +
      +# Thailand
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Bangkok	6:42:04	-	LMT	1880
      +			6:42:04	-	BMT	1920 Apr # Bangkok Mean Time
      +			7:00	-	ICT
      +
      +# Turkmenistan
      +# From Shanks & Pottenger.
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Ashgabat	3:53:32 -	LMT	1924 May  2 # or Ashkhabad
      +			4:00	-	ASHT	1930 Jun 21 # Ashkhabad Time
      +			5:00 RussiaAsia	ASH%sT	1991 Mar 31 2:00
      +			4:00 RussiaAsia	ASH%sT	1991 Oct 27 # independence
      +			4:00 RussiaAsia	TM%sT	1992 Jan 19 2:00
      +			5:00	-	TMT
      +
      +# United Arab Emirates
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Dubai	3:41:12 -	LMT	1920
      +			4:00	-	GST
      +
      +# Uzbekistan
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Samarkand	4:27:12 -	LMT	1924 May  2
      +			4:00	-	SAMT	1930 Jun 21 # Samarkand Time
      +			5:00	-	SAMT	1981 Apr  1
      +			5:00	1:00	SAMST	1981 Oct  1
      +			6:00	-	TAST	1982 Apr  1 # Tashkent Time
      +			5:00 RussiaAsia	SAM%sT	1991 Sep  1 # independence
      +			5:00 RussiaAsia	UZ%sT	1992
      +			5:00	-	UZT
      +Zone	Asia/Tashkent	4:37:12 -	LMT	1924 May  2
      +			5:00	-	TAST	1930 Jun 21 # Tashkent Time
      +			6:00 RussiaAsia	TAS%sT	1991 Mar 31 2:00
      +			5:00 RussiaAsia	TAS%sT	1991 Sep  1 # independence
      +			5:00 RussiaAsia	UZ%sT	1992
      +			5:00	-	UZT
      +
      +# Vietnam
      +
      +# From Arthur David Olson (2008-03-18):
      +# The English-language name of Vietnam's most populous city is "Ho Chi Min City";
      +# we use Ho_Chi_Minh below to avoid a name of more than 14 characters.
      +
      +# From Shanks & Pottenger:
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Ho_Chi_Minh	7:06:40 -	LMT	1906 Jun  9
      +			7:06:20	-	SMT	1911 Mar 11 0:01 # Saigon MT?
      +			7:00	-	ICT	1912 May
      +			8:00	-	ICT	1931 May
      +			7:00	-	ICT
      +
      +# Yemen
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Asia/Aden	3:00:48	-	LMT	1950
      +			3:00	-	AST
      diff --git a/jdk/test/sun/util/calendar/zi/tzdata/australasia b/jdk/test/sun/util/calendar/zi/tzdata/australasia
      new file mode 100644
      index 00000000000..7f83448f3fb
      --- /dev/null
      +++ b/jdk/test/sun/util/calendar/zi/tzdata/australasia
      @@ -0,0 +1,1742 @@
      +#
      +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      +#  
      +# This code is free software; you can redistribute it and/or modify it
      +# under the terms of the GNU General Public License version 2 only, as
      +# published by the Free Software Foundation.  Oracle designates this
      +# particular file as subject to the "Classpath" exception as provided
      +# by Oracle in the LICENSE file that accompanied this code.
      +#  
      +# This code is distributed in the hope that it will be useful, but WITHOUT
      +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      +# version 2 for more details (a copy is included in the LICENSE file that
      +# accompanied this code).
      +#  
      +# You should have received a copy of the GNU General Public License version
      +# 2 along with this work; if not, write to the Free Software Foundation,
      +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      +#  
      +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      +# or visit www.oracle.com if you need additional information or have any
      +# questions.
      +#
      +# 
      +# This file is in the public domain, so clarified as of
      +# 2009-05-17 by Arthur David Olson.
      +
      +# This file also includes Pacific islands.
      +
      +# Notes are at the end of this file
      +
      +###############################################################################
      +
      +# Australia
      +
      +# Please see the notes below for the controversy about "EST" versus "AEST" etc.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Aus	1917	only	-	Jan	 1	0:01	1:00	-
      +Rule	Aus	1917	only	-	Mar	25	2:00	0	-
      +Rule	Aus	1942	only	-	Jan	 1	2:00	1:00	-
      +Rule	Aus	1942	only	-	Mar	29	2:00	0	-
      +Rule	Aus	1942	only	-	Sep	27	2:00	1:00	-
      +Rule	Aus	1943	1944	-	Mar	lastSun	2:00	0	-
      +Rule	Aus	1943	only	-	Oct	 3	2:00	1:00	-
      +# Go with Whitman and the Australian National Standards Commission, which
      +# says W Australia didn't use DST in 1943/1944.  Ignore Whitman's claim that
      +# 1944/1945 was just like 1943/1944.
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +# Northern Territory
      +Zone Australia/Darwin	 8:43:20 -	LMT	1895 Feb
      +			 9:00	-	CST	1899 May
      +			 9:30	Aus	CST
      +# Western Australia
      +#
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	AW	1974	only	-	Oct	lastSun	2:00s	1:00	-
      +Rule	AW	1975	only	-	Mar	Sun>=1	2:00s	0	-
      +Rule	AW	1983	only	-	Oct	lastSun	2:00s	1:00	-
      +Rule	AW	1984	only	-	Mar	Sun>=1	2:00s	0	-
      +Rule	AW	1991	only	-	Nov	17	2:00s	1:00	-
      +Rule	AW	1992	only	-	Mar	Sun>=1	2:00s	0	-
      +Rule	AW	2006	only	-	Dec	 3	2:00s	1:00	-
      +Rule	AW	2007	2009	-	Mar	lastSun	2:00s	0	-
      +Rule	AW	2007	2008	-	Oct	lastSun	2:00s	1:00	-
      +Zone Australia/Perth	 7:43:24 -	LMT	1895 Dec
      +			 8:00	Aus	WST	1943 Jul
      +			 8:00	AW	WST
      +Zone Australia/Eucla	 8:35:28 -	LMT	1895 Dec
      +			 8:45	Aus	CWST	1943 Jul
      +			 8:45	AW	CWST
      +
      +# Queensland
      +#
      +# From Alex Livingston (1996-11-01):
      +# I have heard or read more than once that some resort islands off the coast
      +# of Queensland chose to keep observing daylight-saving time even after
      +# Queensland ceased to.
      +#
      +# From Paul Eggert (1996-11-22):
      +# IATA SSIM (1993-02/1994-09) say that the Holiday Islands (Hayman, Lindeman,
      +# Hamilton) observed DST for two years after the rest of Queensland stopped.
      +# Hamilton is the largest, but there is also a Hamilton in Victoria,
      +# so use Lindeman.
      +#
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	AQ	1971	only	-	Oct	lastSun	2:00s	1:00	-
      +Rule	AQ	1972	only	-	Feb	lastSun	2:00s	0	-
      +Rule	AQ	1989	1991	-	Oct	lastSun	2:00s	1:00	-
      +Rule	AQ	1990	1992	-	Mar	Sun>=1	2:00s	0	-
      +Rule	Holiday	1992	1993	-	Oct	lastSun	2:00s	1:00	-
      +Rule	Holiday	1993	1994	-	Mar	Sun>=1	2:00s	0	-
      +Zone Australia/Brisbane	10:12:08 -	LMT	1895
      +			10:00	Aus	EST	1971
      +			10:00	AQ	EST
      +Zone Australia/Lindeman  9:55:56 -	LMT	1895
      +			10:00	Aus	EST	1971
      +			10:00	AQ	EST	1992 Jul
      +			10:00	Holiday	EST
      +
      +# South Australia
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	AS	1971	1985	-	Oct	lastSun	2:00s	1:00	-
      +Rule	AS	1986	only	-	Oct	19	2:00s	1:00	-
      +Rule	AS	1987	2007	-	Oct	lastSun	2:00s	1:00	-
      +Rule	AS	1972	only	-	Feb	27	2:00s	0	-
      +Rule	AS	1973	1985	-	Mar	Sun>=1	2:00s	0	-
      +Rule	AS	1986	1990	-	Mar	Sun>=15	2:00s	0	-
      +Rule	AS	1991	only	-	Mar	3	2:00s	0	-
      +Rule	AS	1992	only	-	Mar	22	2:00s	0	-
      +Rule	AS	1993	only	-	Mar	7	2:00s	0	-
      +Rule	AS	1994	only	-	Mar	20	2:00s	0	-
      +Rule	AS	1995	2005	-	Mar	lastSun	2:00s	0	-
      +Rule	AS	2006	only	-	Apr	2	2:00s	0	-
      +Rule	AS	2007	only	-	Mar	lastSun	2:00s	0	-
      +Rule	AS	2008	max	-	Apr	Sun>=1	2:00s	0	-
      +Rule	AS	2008	max	-	Oct	Sun>=1	2:00s	1:00	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Australia/Adelaide	9:14:20 -	LMT	1895 Feb
      +			9:00	-	CST	1899 May
      +			9:30	Aus	CST	1971
      +			9:30	AS	CST
      +
      +# Tasmania
      +#
      +# From Paul Eggert (2005-08-16):
      +# 
      +# says King Island didn't observe DST from WWII until late 1971.
      +#
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	AT	1967	only	-	Oct	Sun>=1	2:00s	1:00	-
      +Rule	AT	1968	only	-	Mar	lastSun	2:00s	0	-
      +Rule	AT	1968	1985	-	Oct	lastSun	2:00s	1:00	-
      +Rule	AT	1969	1971	-	Mar	Sun>=8	2:00s	0	-
      +Rule	AT	1972	only	-	Feb	lastSun	2:00s	0	-
      +Rule	AT	1973	1981	-	Mar	Sun>=1	2:00s	0	-
      +Rule	AT	1982	1983	-	Mar	lastSun	2:00s	0	-
      +Rule	AT	1984	1986	-	Mar	Sun>=1	2:00s	0	-
      +Rule	AT	1986	only	-	Oct	Sun>=15	2:00s	1:00	-
      +Rule	AT	1987	1990	-	Mar	Sun>=15	2:00s	0	-
      +Rule	AT	1987	only	-	Oct	Sun>=22	2:00s	1:00	-
      +Rule	AT	1988	1990	-	Oct	lastSun	2:00s	1:00	-
      +Rule	AT	1991	1999	-	Oct	Sun>=1	2:00s	1:00	-
      +Rule	AT	1991	2005	-	Mar	lastSun	2:00s	0	-
      +Rule	AT	2000	only	-	Aug	lastSun	2:00s	1:00	-
      +Rule	AT	2001	max	-	Oct	Sun>=1	2:00s	1:00	-
      +Rule	AT	2006	only	-	Apr	Sun>=1	2:00s	0	-
      +Rule	AT	2007	only	-	Mar	lastSun	2:00s	0	-
      +Rule	AT	2008	max	-	Apr	Sun>=1	2:00s	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Australia/Hobart	9:49:16	-	LMT	1895 Sep
      +			10:00	-	EST	1916 Oct 1 2:00
      +			10:00	1:00	EST	1917 Feb
      +			10:00	Aus	EST	1967
      +			10:00	AT	EST
      +Zone Australia/Currie	9:35:28	-	LMT	1895 Sep
      +			10:00	-	EST	1916 Oct 1 2:00
      +			10:00	1:00	EST	1917 Feb
      +			10:00	Aus	EST	1971 Jul
      +			10:00	AT	EST
      +
      +# Victoria
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	AV	1971	1985	-	Oct	lastSun	2:00s	1:00	-
      +Rule	AV	1972	only	-	Feb	lastSun	2:00s	0	-
      +Rule	AV	1973	1985	-	Mar	Sun>=1	2:00s	0	-
      +Rule	AV	1986	1990	-	Mar	Sun>=15	2:00s	0	-
      +Rule	AV	1986	1987	-	Oct	Sun>=15	2:00s	1:00	-
      +Rule	AV	1988	1999	-	Oct	lastSun	2:00s	1:00	-
      +Rule	AV	1991	1994	-	Mar	Sun>=1	2:00s	0	-
      +Rule	AV	1995	2005	-	Mar	lastSun	2:00s	0	-
      +Rule	AV	2000	only	-	Aug	lastSun	2:00s	1:00	-
      +Rule	AV	2001	2007	-	Oct	lastSun	2:00s	1:00	-
      +Rule	AV	2006	only	-	Apr	Sun>=1	2:00s	0	-
      +Rule	AV	2007	only	-	Mar	lastSun	2:00s	0	-
      +Rule	AV	2008	max	-	Apr	Sun>=1	2:00s	0	-
      +Rule	AV	2008	max	-	Oct	Sun>=1	2:00s	1:00	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Australia/Melbourne 9:39:52 -	LMT	1895 Feb
      +			10:00	Aus	EST	1971
      +			10:00	AV	EST
      +
      +# New South Wales
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	AN	1971	1985	-	Oct	lastSun	2:00s	1:00	-
      +Rule	AN	1972	only	-	Feb	27	2:00s	0	-
      +Rule	AN	1973	1981	-	Mar	Sun>=1	2:00s	0	-
      +Rule	AN	1982	only	-	Apr	Sun>=1	2:00s	0	-
      +Rule	AN	1983	1985	-	Mar	Sun>=1	2:00s	0	-
      +Rule	AN	1986	1989	-	Mar	Sun>=15	2:00s	0	-
      +Rule	AN	1986	only	-	Oct	19	2:00s	1:00	-
      +Rule	AN	1987	1999	-	Oct	lastSun	2:00s	1:00	-
      +Rule	AN	1990	1995	-	Mar	Sun>=1	2:00s	0	-
      +Rule	AN	1996	2005	-	Mar	lastSun	2:00s	0	-
      +Rule	AN	2000	only	-	Aug	lastSun	2:00s	1:00	-
      +Rule	AN	2001	2007	-	Oct	lastSun	2:00s	1:00	-
      +Rule	AN	2006	only	-	Apr	Sun>=1	2:00s	0	-
      +Rule	AN	2007	only	-	Mar	lastSun	2:00s	0	-
      +Rule	AN	2008	max	-	Apr	Sun>=1	2:00s	0	-
      +Rule	AN	2008	max	-	Oct	Sun>=1	2:00s	1:00	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Australia/Sydney	10:04:52 -	LMT	1895 Feb
      +			10:00	Aus	EST	1971
      +			10:00	AN	EST
      +Zone Australia/Broken_Hill 9:25:48 -	LMT	1895 Feb
      +			10:00	-	EST	1896 Aug 23
      +			9:00	-	CST	1899 May
      +			9:30	Aus	CST	1971
      +			9:30	AN	CST	2000
      +			9:30	AS	CST
      +
      +# Lord Howe Island
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	LH	1981	1984	-	Oct	lastSun	2:00	1:00	-
      +Rule	LH	1982	1985	-	Mar	Sun>=1	2:00	0	-
      +Rule	LH	1985	only	-	Oct	lastSun	2:00	0:30	-
      +Rule	LH	1986	1989	-	Mar	Sun>=15	2:00	0	-
      +Rule	LH	1986	only	-	Oct	19	2:00	0:30	-
      +Rule	LH	1987	1999	-	Oct	lastSun	2:00	0:30	-
      +Rule	LH	1990	1995	-	Mar	Sun>=1	2:00	0	-
      +Rule	LH	1996	2005	-	Mar	lastSun	2:00	0	-
      +Rule	LH	2000	only	-	Aug	lastSun	2:00	0:30	-
      +Rule	LH	2001	2007	-	Oct	lastSun	2:00	0:30	-
      +Rule	LH	2006	only	-	Apr	Sun>=1	2:00	0	-
      +Rule	LH	2007	only	-	Mar	lastSun	2:00	0	-
      +Rule	LH	2008	max	-	Apr	Sun>=1	2:00	0	-
      +Rule	LH	2008	max	-	Oct	Sun>=1	2:00	0:30	-
      +Zone Australia/Lord_Howe 10:36:20 -	LMT	1895 Feb
      +			10:00	-	EST	1981 Mar
      +			10:30	LH	LHST
      +
      +# Australian miscellany
      +#
      +# Ashmore Is, Cartier
      +# no indigenous inhabitants; only seasonal caretakers
      +# no times are set
      +#
      +# Coral Sea Is
      +# no indigenous inhabitants; only meteorologists
      +# no times are set
      +#
      +# Macquarie
      +# permanent occupation (scientific station) since 1948;
      +# sealing and penguin oil station operated 1888/1917
      +# like Australia/Hobart
      +
      +# Christmas
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Indian/Christmas	7:02:52 -	LMT	1895 Feb
      +			7:00	-	CXT	# Christmas Island Time
      +
      +# Cook Is
      +# From Shanks & Pottenger:
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Cook	1978	only	-	Nov	12	0:00	0:30	HS
      +Rule	Cook	1979	1991	-	Mar	Sun>=1	0:00	0	-
      +Rule	Cook	1979	1990	-	Oct	lastSun	0:00	0:30	HS
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Pacific/Rarotonga	-10:39:04 -	LMT	1901		# Avarua
      +			-10:30	-	CKT	1978 Nov 12	# Cook Is Time
      +			-10:00	Cook	CK%sT
      +
      +# Cocos
      +# These islands were ruled by the Ross family from about 1830 to 1978.
      +# We don't know when standard time was introduced; for now, we guess 1900.
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Indian/Cocos	6:27:40	-	LMT	1900
      +			6:30	-	CCT	# Cocos Islands Time
      +
      +# Fiji
      +# From Alexander Krivenyshev (2009-11-10):
      +# According to Fiji Broadcasting Corporation,  Fiji plans to re-introduce DST
      +# from November 29th 2009  to April 25th 2010.
      +#
      +# "Daylight savings to commence this month"
      +# 
      +# http://www.radiofiji.com.fj/fullstory.php?id=23719
      +# 
      +# or
      +# 
      +# http://www.worldtimezone.com/dst_news/dst_news_fiji01.html
      +# 
      +
      +# From Steffen Thorsen (2009-11-10):
      +# The Fiji Government has posted some more details about the approved
      +# amendments:
      +# 
      +# http://www.fiji.gov.fj/publish/page_16198.shtml
      +# 
      +
      +# From Steffen Thorsen (2010-03-03):
      +# The Cabinet in Fiji has decided to end DST about a month early, on
      +# 2010-03-28 at 03:00.
      +# The plan is to observe DST again, from 2010-10-24 to sometime in March
      +# 2011 (last Sunday a good guess?).
      +#
      +# Official source:
      +# 
      +# http://www.fiji.gov.fj/index.php?option=com_content&view=article&id=1096:3310-cabinet-approves-change-in-daylight-savings-dates&catid=49:cabinet-releases&Itemid=166
      +# 
      +#
      +# A bit more background info here:
      +# 
      +# http://www.timeanddate.com/news/time/fiji-dst-ends-march-2010.html
      +# 
      +
      +# From Alexander Krivenyshev (2010-10-24):
      +# According to Radio Fiji and Fiji Times online, Fiji will end DST 3
      +# weeks earlier than expected - on March 6, 2011, not March 27, 2011...
      +# Here is confirmation from Government of the Republic of the Fiji Islands,
      +# Ministry of Information (fiji.gov.fj) web site:
      +# 
      +# http://www.fiji.gov.fj/index.php?option=com_content&view=article&id=2608:daylight-savings&catid=71:press-releases&Itemid=155
      +# 
      +# or
      +# 
      +# http://www.worldtimezone.com/dst_news/dst_news_fiji04.html
      +# 
      +
      +# From Steffen Thorsen (2011-10-03):
      +# Now the dates have been confirmed, and at least our start date
      +# assumption was correct (end date was one week wrong).
      +#
      +# 
      +# www.fiji.gov.fj/index.php?option=com_content&view=article&id=4966:daylight-saving-starts-in-fiji&catid=71:press-releases&Itemid=155
      +# 
      +# which says
      +# Members of the public are reminded to change their time to one hour in
      +# advance at 2am to 3am on October 23, 2011 and one hour back at 3am to
      +# 2am on February 26 next year.
      +
      +# From Ken Rylander (2011-10-24)
      +# Another change to the Fiji DST end date. In the TZ database the end date for
      +# Fiji DST 2012, is currently Feb 26. This has been changed to Jan 22.
      +#
      +# 
      +# http://www.fiji.gov.fj/index.php?option=com_content&view=article&id=5017:amendments-to-daylight-savings&catid=71:press-releases&Itemid=155
      +# 
      +# states:
      +#
      +# The end of daylight saving scheduled initially for the 26th of February 2012
      +# has been brought forward to the 22nd of January 2012.
      +# The commencement of daylight saving will remain unchanged and start
      +# on the  23rd of October, 2011.
      +
      +# From the Fiji Government Online Portal (2012-08-21) via Steffen Thorsen:
      +# The Minister for Labour, Industrial Relations and Employment Mr Jone Usamate
      +# today confirmed that Fiji will start daylight savings at 2 am on Sunday 21st
      +# October 2012 and end at 3 am on Sunday 20th January 2013.
      +# http://www.fiji.gov.fj/index.php?option=com_content&view=article&id=6702&catid=71&Itemid=155
      +#
      +# From Paul Eggert (2012-08-31):
      +# For now, guess a pattern of the penultimate Sundays in October and January.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Fiji	1998	1999	-	Nov	Sun>=1	2:00	1:00	S
      +Rule	Fiji	1999	2000	-	Feb	lastSun	3:00	0	-
      +Rule	Fiji	2009	only	-	Nov	29	2:00	1:00	S
      +Rule	Fiji	2010	only	-	Mar	lastSun	3:00	0	-
      +Rule	Fiji	2010	max	-	Oct	Sun>=18	2:00	1:00	S
      +Rule	Fiji	2011	only	-	Mar	Sun>=1	3:00	0	-
      +Rule	Fiji	2012	max	-	Jan	Sun>=18	3:00	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Pacific/Fiji	11:53:40 -	LMT	1915 Oct 26	# Suva
      +			12:00	Fiji	FJ%sT	# Fiji Time
      +
      +# French Polynesia
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Pacific/Gambier	 -8:59:48 -	LMT	1912 Oct	# Rikitea
      +			 -9:00	-	GAMT	# Gambier Time
      +Zone	Pacific/Marquesas -9:18:00 -	LMT	1912 Oct
      +			 -9:30	-	MART	# Marquesas Time
      +Zone	Pacific/Tahiti	 -9:58:16 -	LMT	1912 Oct	# Papeete
      +			-10:00	-	TAHT	# Tahiti Time
      +# Clipperton (near North America) is administered from French Polynesia;
      +# it is uninhabited.
      +
      +# Guam
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Pacific/Guam	-14:21:00 -	LMT	1844 Dec 31
      +			 9:39:00 -	LMT	1901		# Agana
      +			10:00	-	GST	2000 Dec 23	# Guam
      +			10:00	-	ChST	# Chamorro Standard Time
      +
      +# Kiribati
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Pacific/Tarawa	 11:32:04 -	LMT	1901		# Bairiki
      +			 12:00	-	GILT		 # Gilbert Is Time
      +Zone Pacific/Enderbury	-11:24:20 -	LMT	1901
      +			-12:00	-	PHOT	1979 Oct # Phoenix Is Time
      +			-11:00	-	PHOT	1995
      +			 13:00	-	PHOT
      +Zone Pacific/Kiritimati	-10:29:20 -	LMT	1901
      +			-10:40	-	LINT	1979 Oct # Line Is Time
      +			-10:00	-	LINT	1995
      +			 14:00	-	LINT
      +
      +# N Mariana Is
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Pacific/Saipan	-14:17:00 -	LMT	1844 Dec 31
      +			 9:43:00 -	LMT	1901
      +			 9:00	-	MPT	1969 Oct # N Mariana Is Time
      +			10:00	-	MPT	2000 Dec 23
      +			10:00	-	ChST	# Chamorro Standard Time
      +
      +# Marshall Is
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Pacific/Majuro	11:24:48 -	LMT	1901
      +			11:00	-	MHT	1969 Oct # Marshall Islands Time
      +			12:00	-	MHT
      +Zone Pacific/Kwajalein	11:09:20 -	LMT	1901
      +			11:00	-	MHT	1969 Oct
      +			-12:00	-	KWAT	1993 Aug 20	# Kwajalein Time
      +			12:00	-	MHT
      +
      +# Micronesia
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Pacific/Chuuk	10:07:08 -	LMT	1901
      +			10:00	-	CHUT			# Chuuk Time
      +Zone Pacific/Pohnpei	10:32:52 -	LMT	1901		# Kolonia
      +			11:00	-	PONT			# Pohnpei Time
      +Zone Pacific/Kosrae	10:51:56 -	LMT	1901
      +			11:00	-	KOST	1969 Oct	# Kosrae Time
      +			12:00	-	KOST	1999
      +			11:00	-	KOST
      +
      +# Nauru
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Pacific/Nauru	11:07:40 -	LMT	1921 Jan 15	# Uaobe
      +			11:30	-	NRT	1942 Mar 15	# Nauru Time
      +			9:00	-	JST	1944 Aug 15
      +			11:30	-	NRT	1979 May
      +			12:00	-	NRT
      +
      +# New Caledonia
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	NC	1977	1978	-	Dec	Sun>=1	0:00	1:00	S
      +Rule	NC	1978	1979	-	Feb	27	0:00	0	-
      +Rule	NC	1996	only	-	Dec	 1	2:00s	1:00	S
      +# Shanks & Pottenger say the following was at 2:00; go with IATA.
      +Rule	NC	1997	only	-	Mar	 2	2:00s	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Pacific/Noumea	11:05:48 -	LMT	1912 Jan 13
      +			11:00	NC	NC%sT
      +
      +
      +###############################################################################
      +
      +# New Zealand
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	NZ	1927	only	-	Nov	 6	2:00	1:00	S
      +Rule	NZ	1928	only	-	Mar	 4	2:00	0	M
      +Rule	NZ	1928	1933	-	Oct	Sun>=8	2:00	0:30	S
      +Rule	NZ	1929	1933	-	Mar	Sun>=15	2:00	0	M
      +Rule	NZ	1934	1940	-	Apr	lastSun	2:00	0	M
      +Rule	NZ	1934	1940	-	Sep	lastSun	2:00	0:30	S
      +Rule	NZ	1946	only	-	Jan	 1	0:00	0	S
      +# Since 1957 Chatham has been 45 minutes ahead of NZ, but there's no
      +# convenient notation for this so we must duplicate the Rule lines.
      +Rule	NZ	1974	only	-	Nov	Sun>=1	2:00s	1:00	D
      +Rule	Chatham	1974	only	-	Nov	Sun>=1	2:45s	1:00	D
      +Rule	NZ	1975	only	-	Feb	lastSun	2:00s	0	S
      +Rule	Chatham	1975	only	-	Feb	lastSun	2:45s	0	S
      +Rule	NZ	1975	1988	-	Oct	lastSun	2:00s	1:00	D
      +Rule	Chatham	1975	1988	-	Oct	lastSun	2:45s	1:00	D
      +Rule	NZ	1976	1989	-	Mar	Sun>=1	2:00s	0	S
      +Rule	Chatham	1976	1989	-	Mar	Sun>=1	2:45s	0	S
      +Rule	NZ	1989	only	-	Oct	Sun>=8	2:00s	1:00	D
      +Rule	Chatham	1989	only	-	Oct	Sun>=8	2:45s	1:00	D
      +Rule	NZ	1990	2006	-	Oct	Sun>=1	2:00s	1:00	D
      +Rule	Chatham	1990	2006	-	Oct	Sun>=1	2:45s	1:00	D
      +Rule	NZ	1990	2007	-	Mar	Sun>=15	2:00s	0	S
      +Rule	Chatham	1990	2007	-	Mar	Sun>=15	2:45s	0	S
      +Rule	NZ	2007	max	-	Sep	lastSun	2:00s	1:00	D
      +Rule	Chatham	2007	max	-	Sep	lastSun	2:45s	1:00	D
      +Rule	NZ	2008	max	-	Apr	Sun>=1	2:00s	0	S
      +Rule	Chatham	2008	max	-	Apr	Sun>=1	2:45s	0	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Pacific/Auckland	11:39:04 -	LMT	1868 Nov  2
      +			11:30	NZ	NZ%sT	1946 Jan  1
      +			12:00	NZ	NZ%sT
      +Zone Pacific/Chatham	12:13:48 -	LMT	1957 Jan  1
      +			12:45	Chatham	CHA%sT
      +
      +
      +# Auckland Is
      +# uninhabited; Maori and Moriori, colonial settlers, pastoralists, sealers,
      +# and scientific personnel have wintered
      +
      +# Campbell I
      +# minor whaling stations operated 1909/1914
      +# scientific station operated 1941/1995;
      +# previously whalers, sealers, pastoralists, and scientific personnel wintered
      +# was probably like Pacific/Auckland
      +
      +###############################################################################
      +
      +
      +# Niue
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Pacific/Niue	-11:19:40 -	LMT	1901		# Alofi
      +			-11:20	-	NUT	1951	# Niue Time
      +			-11:30	-	NUT	1978 Oct 1
      +			-11:00	-	NUT
      +
      +# Norfolk
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Pacific/Norfolk	11:11:52 -	LMT	1901		# Kingston
      +			11:12	-	NMT	1951	# Norfolk Mean Time
      +			11:30	-	NFT		# Norfolk Time
      +
      +# Palau (Belau)
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Pacific/Palau	8:57:56 -	LMT	1901		# Koror
      +			9:00	-	PWT	# Palau Time
      +
      +# Papua New Guinea
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Pacific/Port_Moresby 9:48:40 -	LMT	1880
      +			9:48:32	-	PMMT	1895	# Port Moresby Mean Time
      +			10:00	-	PGT		# Papua New Guinea Time
      +
      +# Pitcairn
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Pacific/Pitcairn	-8:40:20 -	LMT	1901		# Adamstown
      +			-8:30	-	PNT	1998 Apr 27 00:00
      +			-8:00	-	PST	# Pitcairn Standard Time
      +
      +# American Samoa
      +Zone Pacific/Pago_Pago	 12:37:12 -	LMT	1879 Jul  5
      +			-11:22:48 -	LMT	1911
      +			-11:30	-	SAMT	1950		# Samoa Time
      +			-11:00	-	NST	1967 Apr	# N=Nome
      +			-11:00	-	BST	1983 Nov 30	# B=Bering
      +			-11:00	-	SST			# S=Samoa
      +
      +# Samoa
      +
      +# From Steffen Thorsen (2009-10-16):
      +# We have been in contact with the government of Samoa again, and received
      +# the following info:
      +#
      +# "Cabinet has now approved Daylight Saving to be effected next year
      +# commencing from the last Sunday of September 2010 and conclude first
      +# Sunday of April 2011."
      +#
      +# Background info:
      +# 
      +# http://www.timeanddate.com/news/time/samoa-dst-plan-2009.html
      +# 
      +#
      +# Samoa's Daylight Saving Time Act 2009 is available here, but does not
      +# contain any dates:
      +# 
      +# http://www.parliament.gov.ws/documents/acts/Daylight%20Saving%20Act%20%202009%20%28English%29%20-%20Final%207-7-091.pdf
      +# 
      +
      +# From Laupue Raymond Hughes (2010-10-07):
      +# Please see
      +# 
      +# http://www.mcil.gov.ws
      +# ,
      +# the Ministry of Commerce, Industry and Labour (sideframe) "Last Sunday
      +# September 2010 (26/09/10) - adjust clocks forward from 12:00 midnight
      +# to 01:00am and First Sunday April 2011 (03/04/11) - adjust clocks
      +# backwards from 1:00am to 12:00am"
      +
      +# From Laupue Raymond Hughes (2011-03-07):
      +# I believe this will be posted shortly on the website
      +# 
      +# www.mcil.gov.ws
      +# 
      +#
      +# PUBLIC NOTICE ON DAYLIGHT SAVING TIME
      +#
      +# Pursuant to the Daylight Saving Act 2009 and Cabinets decision,
      +# businesses and the general public are hereby advised that daylight
      +# saving time is on the first Saturday of April 2011 (02/04/11).
      +#
      +# The public is therefore advised that when the standard time strikes
      +# the hour of four oclock (4.00am or 0400 Hours) on the 2nd April 2011,
      +# then all instruments used to measure standard time are to be
      +# adjusted/changed to three oclock (3:00am or 0300Hrs).
      +#
      +# Margaret Fruean ACTING CHIEF EXECUTIVE OFFICER MINISTRY OF COMMERCE,
      +# INDUSTRY AND LABOUR 28th February 2011
      +
      +# From David Zuelke (2011-05-09):
      +# Subject: Samoa to move timezone from east to west of international date line
      +#
      +# 
      +# http://www.morningstar.co.uk/uk/markets/newsfeeditem.aspx?id=138501958347963
      +# 
      +
      +# From Mark Sim-Smith (2011-08-17):
      +# I have been in contact with Leilani Tuala Warren from the Samoa Law
      +# Reform Commission, and she has sent me a copy of the Bill that she
      +# confirmed has been passed...Most of the sections are about maps rather
      +# than the time zone change, but I'll paste the relevant bits below. But
      +# the essence is that at midnight 29 Dec (UTC-11 I suppose), Samoa
      +# changes from UTC-11 to UTC+13:
      +#
      +# International Date Line Bill 2011
      +#
      +# AN ACT to provide for the change to standard time in Samoa and to make
      +# consequential amendments to the position of the International Date
      +# Line, and for related purposes.
      +#
      +# BE IT ENACTED by the Legislative Assembly of Samoa in Parliament
      +# assembled as follows:
      +#
      +# 1. Short title and commencement-(1) This Act may be cited as the
      +# International Date Line Act 2011. (2) Except for section 5(3) this Act
      +# commences at 12 o'clock midnight, on Thursday 29th December 2011. (3)
      +# Section 5(3) commences on the date of assent by the Head of State.
      +#
      +# [snip]
      +#
      +# 3. Interpretation - [snip] "Samoa standard time" in this Act and any
      +# other statute of Samoa which refers to 'Samoa standard time' means the
      +# time 13 hours in advance of Co-ordinated Universal Time.
      +#
      +# 4. Samoa standard time - (1) Upon the commencement of this Act, Samoa
      +# standard time shall be set at 13 hours in advance of Co-ordinated
      +# Universal Time for the whole of Samoa. (2) All references to Samoa's
      +# time zone and to Samoa standard time in Samoa in all legislation and
      +# instruments after the commencement of this Act shall be references to
      +# Samoa standard time as provided for in this Act. (3) Nothing in this
      +# Act affects the provisions of the Daylight Saving Act 2009, except that
      +# it defines Samoa standard time....
      +
      +# From Laupue Raymond Hughes (2011-09-02):
      +# 
      +# http://www.mcil.gov.ws/mcil_publications.html
      +# 
      +#
      +# here is the official website publication for Samoa DST and dateline change
      +#
      +# DST
      +# Year	End	Time	Start	Time
      +# 2011	- - -	- - -	24 September	3:00am to 4:00am
      +# 2012	01 April	4:00am to 3:00am	- - -	- - -
      +#
      +# Dateline Change skip Friday 30th Dec 2011
      +# Thursday 29th December 2011	23:59:59 Hours
      +# Saturday 31st December 2011	00:00:00 Hours
      +#
      +# Clarification by Tim Parenti (2012-01-03):
      +# Although Samoa has used Daylight Saving Time in the 2010-2011 and 2011-2012
      +# seasons, there is not yet any indication that this trend will continue on
      +# a regular basis. For now, we have explicitly listed the transitions below.
      +#
      +# From Nicky (2012-09-10):
      +# Daylight Saving Time commences on Sunday 30th September 2012 and
      +# ends on Sunday 7th of April 2013.
      +#
      +# Please find link below for more information.
      +# http://www.mcil.gov.ws/mcil_publications.html
      +#
      +# That publication also includes dates for Summer of 2013/4 as well
      +# which give the impression of a pattern in selecting dates for the
      +# future, so for now, we will guess this will continue.
      +
      +# Western Samoa
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	WS	2012	max	-	Sep	lastSun	3:00	1	D
      +Rule	WS	2012	max	-	Apr	Sun>=1	4:00	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Pacific/Apia	 12:33:04 -	LMT	1879 Jul  5
      +			-11:26:56 -	LMT	1911
      +			-11:30	-	SAMT	1950		# Samoa Time
      +			-11:00	-	WST	2010 Sep 26
      +			-11:00	1:00	WSDT	2011 Apr 2 4:00
      +			-11:00	-	WST	2011 Sep 24 3:00
      +			-11:00	1:00	WSDT	2011 Dec 30
      +			 13:00	1:00	WSDT	2012 Apr Sun>=1 4:00
      +			 13:00	WS	WS%sT
      +
      +# Solomon Is
      +# excludes Bougainville, for which see Papua New Guinea
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Pacific/Guadalcanal 10:39:48 -	LMT	1912 Oct	# Honiara
      +			11:00	-	SBT	# Solomon Is Time
      +
      +# Tokelau Is
      +#
      +# From Gwillim Law (2011-12-29)
      +# A correspondent informed me that Tokelau, like Samoa, will be skipping
      +# December 31 this year ...
      +#
      +# From Steffen Thorsen (2012-07-25)
      +# ... we double checked by calling hotels and offices based in Tokelau asking
      +# about the time there, and they all told a time that agrees with UTC+13....
      +# Shanks says UTC-10 from 1901 [but] ... there is a good chance the change
      +# actually was to UTC-11 back then.
      +#
      +# From Paul Eggert (2012-07-25)
      +# A Google Books snippet of Appendix to the Journals of the House of
      +# Representatives of New Zealand, Session 1948,
      +# , page 65, says Tokelau
      +# was "11 hours slow on G.M.T."  Go with Thorsen and assume Shanks & Pottenger
      +# are off by an hour starting in 1901.
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Pacific/Fakaofo	-11:24:56 -	LMT	1901
      +			-11:00	-	TKT 2011 Dec 30	# Tokelau Time
      +			13:00	-	TKT
      +
      +# Tonga
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Tonga	1999	only	-	Oct	 7	2:00s	1:00	S
      +Rule	Tonga	2000	only	-	Mar	19	2:00s	0	-
      +Rule	Tonga	2000	2001	-	Nov	Sun>=1	2:00	1:00	S
      +Rule	Tonga	2001	2002	-	Jan	lastSun	2:00	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Pacific/Tongatapu	12:19:20 -	LMT	1901
      +			12:20	-	TOT	1941 # Tonga Time
      +			13:00	-	TOT	1999
      +			13:00	Tonga	TO%sT
      +
      +# Tuvalu
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Pacific/Funafuti	11:56:52 -	LMT	1901
      +			12:00	-	TVT	# Tuvalu Time
      +
      +
      +# US minor outlying islands
      +
      +# Howland, Baker
      +# Howland was mined for guano by American companies 1857-1878 and British
      +# 1886-1891; Baker was similar but exact dates are not known.
      +# Inhabited by civilians 1935-1942; U.S. military bases 1943-1944;
      +# uninhabited thereafter.
      +# Howland observed Hawaii Standard Time (UTC-10:30) in 1937;
      +# see page 206 of Elgen M. Long and Marie K. Long,
      +# Amelia Earhart: the Mystery Solved, Simon & Schuster (2000).
      +# So most likely Howland and Baker observed Hawaii Time from 1935
      +# until they were abandoned after the war.
      +
      +# Jarvis
      +# Mined for guano by American companies 1857-1879 and British 1883?-1891?.
      +# Inhabited by civilians 1935-1942; IGY scientific base 1957-1958;
      +# uninhabited thereafter.
      +# no information; was probably like Pacific/Kiritimati
      +
      +# Johnston
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Pacific/Johnston	-10:00	-	HST
      +
      +# Kingman
      +# uninhabited
      +
      +# Midway
      +#
      +# From Mark Brader (2005-01-23):
      +# [Fallacies and Fantasies of Air Transport History, by R.E.G. Davies,
      +# published 1994 by Paladwr Press, McLean, VA, USA; ISBN 0-9626483-5-3]
      +# reproduced a Pan American Airways timeables from 1936, for their weekly
      +# "Orient Express" flights between San Francisco and Manila, and connecting
      +# flights to Chicago and the US East Coast.  As it uses some time zone
      +# designations that I've never seen before:....
      +# Fri. 6:30A Lv. HONOLOLU (Pearl Harbor), H.I.   H.L.T. Ar. 5:30P Sun.
      +#  "   3:00P Ar. MIDWAY ISLAND . . . . . . . . . M.L.T. Lv. 6:00A  "
      +#
      +Zone Pacific/Midway	-11:49:28 -	LMT	1901
      +			-11:00	-	NST	1956 Jun  3
      +			-11:00	1:00	NDT	1956 Sep  2
      +			-11:00	-	NST	1967 Apr	# N=Nome
      +			-11:00	-	BST	1983 Nov 30	# B=Bering
      +			-11:00	-	SST			# S=Samoa
      +
      +# Palmyra
      +# uninhabited since World War II; was probably like Pacific/Kiritimati
      +
      +# Wake
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Pacific/Wake	11:06:28 -	LMT	1901
      +			12:00	-	WAKT	# Wake Time
      +
      +
      +# Vanuatu
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Vanuatu	1983	only	-	Sep	25	0:00	1:00	S
      +Rule	Vanuatu	1984	1991	-	Mar	Sun>=23	0:00	0	-
      +Rule	Vanuatu	1984	only	-	Oct	23	0:00	1:00	S
      +Rule	Vanuatu	1985	1991	-	Sep	Sun>=23	0:00	1:00	S
      +Rule	Vanuatu	1992	1993	-	Jan	Sun>=23	0:00	0	-
      +Rule	Vanuatu	1992	only	-	Oct	Sun>=23	0:00	1:00	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Pacific/Efate	11:13:16 -	LMT	1912 Jan 13		# Vila
      +			11:00	Vanuatu	VU%sT	# Vanuatu Time
      +
      +# Wallis and Futuna
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Pacific/Wallis	12:15:20 -	LMT	1901
      +			12:00	-	WFT	# Wallis & Futuna Time
      +
      +###############################################################################
      +
      +# NOTES
      +
      +# This data is by no means authoritative; if you think you know better,
      +# go ahead and edit the file (and please send any changes to
      +# tz@elsie.nci.nih.gov for general use in the future).
      +
      +# From Paul Eggert (2006-03-22):
      +# A good source for time zone historical data outside the U.S. is
      +# Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition),
      +# San Diego: ACS Publications, Inc. (2003).
      +#
      +# Gwillim Law writes that a good source
      +# for recent time zone data is the International Air Transport
      +# Association's Standard Schedules Information Manual (IATA SSIM),
      +# published semiannually.  Law sent in several helpful summaries
      +# of the IATA's data after 1990.
      +#
      +# Except where otherwise noted, Shanks & Pottenger is the source for
      +# entries through 1990, and IATA SSIM is the source for entries afterwards.
      +#
      +# Another source occasionally used is Edward W. Whitman, World Time Differences,
      +# Whitman Publishing Co, 2 Niagara Av, Ealing, London (undated), which
      +# I found in the UCLA library.
      +#
      +# A reliable and entertaining source about time zones is
      +# Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
      +#
      +# I invented the abbreviations marked `*' in the following table;
      +# the rest are from earlier versions of this file, or from other sources.
      +# Corrections are welcome!
      +#		std dst
      +#		LMT	Local Mean Time
      +#	  8:00	WST WST	Western Australia
      +#	  8:45	CWST CWST Central Western Australia*
      +#	  9:00	JST	Japan
      +#	  9:30	CST CST	Central Australia
      +#	 10:00	EST EST	Eastern Australia
      +#	 10:00	ChST	Chamorro
      +#	 10:30	LHST LHST Lord Howe*
      +#	 11:30	NZMT NZST New Zealand through 1945
      +#	 12:00	NZST NZDT New Zealand 1946-present
      +#	 12:45	CHAST CHADT Chatham*
      +#	-11:00	SST	Samoa
      +#	-10:00	HST	Hawaii
      +#	- 8:00	PST	Pitcairn*
      +#
      +# See the `northamerica' file for Hawaii.
      +# See the `southamerica' file for Easter I and the Galapagos Is.
      +
      +###############################################################################
      +
      +# Australia
      +
      +# From Paul Eggert (2005-12-08):
      +# 
      +# Implementation Dates of Daylight Saving Time within Australia
      +#  summarizes daylight saving issues in Australia.
      +
      +# From Arthur David Olson (2005-12-12):
      +# 
      +# Lawlink NSW:Daylight Saving in New South Wales
      +#  covers New South Wales in particular.
      +
      +# From John Mackin (1991-03-06):
      +# We in Australia have _never_ referred to DST as `daylight' time.
      +# It is called `summer' time.  Now by a happy coincidence, `summer'
      +# and `standard' happen to start with the same letter; hence, the
      +# abbreviation does _not_ change...
      +# The legislation does not actually define abbreviations, at least
      +# in this State, but the abbreviation is just commonly taken to be the
      +# initials of the phrase, and the legislation here uniformly uses
      +# the phrase `summer time' and does not use the phrase `daylight
      +# time'.
      +# Announcers on the Commonwealth radio network, the ABC (for Australian
      +# Broadcasting Commission), use the phrases `Eastern Standard Time'
      +# or `Eastern Summer Time'.  (Note, though, that as I say in the
      +# current australasia file, there is really no such thing.)  Announcers
      +# on its overseas service, Radio Australia, use the same phrases
      +# prefixed by the word `Australian' when referring to local times;
      +# time announcements on that service, naturally enough, are made in UTC.
      +
      +# From Arthur David Olson (1992-03-08):
      +# Given the above, what's chosen for year-round use is:
      +#	CST	for any place operating at a GMTOFF of 9:30
      +#	WST	for any place operating at a GMTOFF of 8:00
      +#	EST	for any place operating at a GMTOFF of 10:00
      +
      +# From Chuck Soper (2006-06-01):
      +# I recently found this Australian government web page on time zones:
      +# 
      +# And this government web page lists time zone names and abbreviations:
      +# 
      +
      +# From Paul Eggert (2001-04-05), summarizing a long discussion about "EST"
      +# versus "AEST" etc.:
      +#
      +# I see the following points of dispute:
      +#
      +# * How important are unique time zone abbreviations?
      +#
      +#   Here I tend to agree with the point (most recently made by Chris
      +#   Newman) that unique abbreviations should not be essential for proper
      +#   operation of software.  We have other instances of ambiguity
      +#   (e.g. "IST" denoting both "Israel Standard Time" and "Indian
      +#   Standard Time"), and they are not likely to go away any time soon.
      +#   In the old days, some software mistakenly relied on unique
      +#   abbreviations, but this is becoming less true with time, and I don't
      +#   think it's that important to cater to such software these days.
      +#
      +#   On the other hand, there is another motivation for unambiguous
      +#   abbreviations: it cuts down on human confusion.  This is
      +#   particularly true for Australia, where "EST" can mean one thing for
      +#   time T and a different thing for time T plus 1 second.
      +#
      +# * Does the relevant legislation indicate which abbreviations should be used?
      +#
      +#   Here I tend to think that things are a mess, just as they are in
      +#   many other countries.  We Americans are currently disagreeing about
      +#   which abbreviation to use for the newly legislated Chamorro Standard
      +#   Time, for example.
      +#
      +#   Personally, I would prefer to use common practice; I would like to
      +#   refer to legislation only for examples of common practice, or as a
      +#   tiebreaker.
      +#
      +# * Do Australians more often use "Eastern Daylight Time" or "Eastern
      +#   Summer Time"?  Do they typically prefix the time zone names with
      +#   the word "Australian"?
      +#
      +#   My own impression is that both "Daylight Time" and "Summer Time" are
      +#   common and are widely understood, but that "Summer Time" is more
      +#   popular; and that the leading "A" is also common but is omitted more
      +#   often than not.  I just used AltaVista advanced search and got the
      +#   following count of page hits:
      +#
      +#     1,103 "Eastern Summer Time" AND domain:au
      +#       971 "Australian Eastern Summer Time" AND domain:au
      +#       613 "Eastern Daylight Time" AND domain:au
      +#       127 "Australian Eastern Daylight Time" AND domain:au
      +#
      +#   Here "Summer" seems quite a bit more popular than "Daylight",
      +#   particularly when we know the time zone is Australian and not US,
      +#   say.  The "Australian" prefix seems to be popular for Eastern Summer
      +#   Time, but unpopular for Eastern Daylight Time.
      +#
      +#   For abbreviations, tools like AltaVista are less useful because of
      +#   ambiguity.  Many hits are not really time zones, unfortunately, and
      +#   many hits denote US time zones and not Australian ones.  But here
      +#   are the hit counts anyway:
      +#
      +#     161,304 "EST" and domain:au
      +#      25,156 "EDT" and domain:au
      +#      18,263 "AEST" and domain:au
      +#      10,416 "AEDT" and domain:au
      +#
      +#      14,538 "CST" and domain:au
      +#       5,728 "CDT" and domain:au
      +#         176 "ACST" and domain:au
      +#          29 "ACDT" and domain:au
      +#
      +#       7,539 "WST" and domain:au
      +#          68 "AWST" and domain:au
      +#
      +#   This data suggest that Australians tend to omit the "A" prefix in
      +#   practice.  The situation for "ST" versus "DT" is less clear, given
      +#   the ambiguities involved.
      +#
      +# * How do Australians feel about the abbreviations in the tz database?
      +#
      +#   If you just count Australians on this list, I count 2 in favor and 3
      +#   against.  One of the "against" votes (David Keegel) counseled delay,
      +#   saying that both AEST/AEDT and EST/EST are widely used and
      +#   understood in Australia.
      +
      +# From Paul Eggert (1995-12-19):
      +# Shanks & Pottenger report 2:00 for all autumn changes in Australia and NZ.
      +# Mark Prior writes that his newspaper
      +# reports that NSW's fall 1995 change will occur at 2:00,
      +# but Robert Elz says it's been 3:00 in Victoria since 1970
      +# and perhaps the newspaper's `2:00' is referring to standard time.
      +# For now we'll continue to assume 2:00s for changes since 1960.
      +
      +# From Eric Ulevik (1998-01-05):
      +#
      +# Here are some URLs to Australian time legislation. These URLs are stable,
      +# and should probably be included in the data file. There are probably more
      +# relevant entries in this database.
      +#
      +# NSW (including LHI and Broken Hill):
      +# 
      +# Standard Time Act 1987 (updated 1995-04-04)
      +# 
      +# ACT
      +# 
      +# Standard Time and Summer Time Act 1972
      +# 
      +# SA
      +# 
      +# Standard Time Act, 1898
      +# 
      +
      +# From David Grosz (2005-06-13):
      +# It was announced last week that Daylight Saving would be extended by
      +# one week next year to allow for the 2006 Commonwealth Games.
      +# Daylight Saving is now to end for next year only on the first Sunday
      +# in April instead of the last Sunday in March.
      +#
      +# From Gwillim Law (2005-06-14):
      +# I did some Googling and found that all of those states (and territory) plan
      +# to extend DST together in 2006.
      +# ACT: http://www.cmd.act.gov.au/mediareleases/fileread.cfm?file=86.txt
      +# New South Wales: http://www.thecouriermail.news.com.au/common/story_page/0,5936,15538869%255E1702,00.html
      +# South Australia: http://www.news.com.au/story/0,10117,15555031-1246,00.html
      +# Tasmania: http://www.media.tas.gov.au/release.php?id=14772
      +# Victoria: I wasn't able to find anything separate, but the other articles
      +# allude to it.
      +# But not Queensland
      +# http://www.news.com.au/story/0,10117,15564030-1248,00.html.
      +
      +# Northern Territory
      +
      +# From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
      +# # The NORTHERN TERRITORY..  [ Courtesy N.T. Dept of the Chief Minister ]
      +# #					[ Nov 1990 ]
      +# #	N.T. have never utilised any DST due to sub-tropical/tropical location.
      +# ...
      +# Zone        Australia/North         9:30    -       CST
      +
      +# From Bradley White (1991-03-04):
      +# A recent excerpt from an Australian newspaper...
      +# the Northern Territory do[es] not have daylight saving.
      +
      +# Western Australia
      +
      +# From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
      +# #  The state of WESTERN AUSTRALIA..  [ Courtesy W.A. dept Premier+Cabinet ]
      +# #						[ Nov 1990 ]
      +# #	W.A. suffers from a great deal of public and political opposition to
      +# #	DST in principle. A bill is brought before parliament in most years, but
      +# #	usually defeated either in the upper house, or in party caucus
      +# #	before reaching parliament.
      +# ...
      +# Zone	Australia/West		8:00	AW	%sST
      +# ...
      +# Rule	AW	1974	only	-	Oct	lastSun	2:00	1:00	D
      +# Rule	AW	1975	only	-	Mar	Sun>=1	3:00	0	W
      +# Rule	AW	1983	only	-	Oct	lastSun	2:00	1:00	D
      +# Rule	AW	1984	only	-	Mar	Sun>=1	3:00	0	W
      +
      +# From Bradley White (1991-03-04):
      +# A recent excerpt from an Australian newspaper...
      +# Western Australia...do[es] not have daylight saving.
      +
      +# From John D. Newman via Bradley White (1991-11-02):
      +# Western Australia is still on "winter time". Some DH in Sydney
      +# rang me at home a few days ago at 6.00am. (He had just arrived at
      +# work at 9.00am.)
      +# W.A. is switching to Summer Time on Nov 17th just to confuse
      +# everybody again.
      +
      +# From Arthur David Olson (1992-03-08):
      +# The 1992 ending date used in the rules is a best guess;
      +# it matches what was used in the past.
      +
      +# 
      +# The Australian Bureau of Meteorology FAQ
      +#  (1999-09-27) writes that Giles Meteorological Station uses
      +# South Australian time even though it's located in Western Australia.
      +
      +# Queensland
      +# From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
      +# #   The state of QUEENSLAND.. [ Courtesy Qld. Dept Premier Econ&Trade Devel ]
      +# #						[ Dec 1990 ]
      +# ...
      +# Zone	Australia/Queensland	10:00	AQ	%sST
      +# ...
      +# Rule	AQ	1971	only	-	Oct	lastSun	2:00	1:00	D
      +# Rule	AQ	1972	only	-	Feb	lastSun	3:00	0	E
      +# Rule	AQ	1989	max	-	Oct	lastSun	2:00	1:00	D
      +# Rule	AQ	1990	max	-	Mar	Sun>=1	3:00	0	E
      +
      +# From Bradley White (1989-12-24):
      +# "Australia/Queensland" now observes daylight time (i.e. from
      +# October 1989).
      +
      +# From Bradley White (1991-03-04):
      +# A recent excerpt from an Australian newspaper...
      +# ...Queensland...[has] agreed to end daylight saving
      +# at 3am tomorrow (March 3)...
      +
      +# From John Mackin (1991-03-06):
      +# I can certainly confirm for my part that Daylight Saving in NSW did in fact
      +# end on Sunday, 3 March.  I don't know at what hour, though.  (It surprised
      +# me.)
      +
      +# From Bradley White (1992-03-08):
      +# ...there was recently a referendum in Queensland which resulted
      +# in the experimental daylight saving system being abandoned. So, ...
      +# ...
      +# Rule	QLD	1989	1991	-	Oct	lastSun	2:00	1:00	D
      +# Rule	QLD	1990	1992	-	Mar	Sun>=1	3:00	0	S
      +# ...
      +
      +# From Arthur David Olson (1992-03-08):
      +# The chosen rules the union of the 1971/1972 change and the 1989-1992 changes.
      +
      +# From Christopher Hunt (2006-11-21), after an advance warning
      +# from Jesper Norgaard Welen (2006-11-01):
      +# WA are trialing DST for three years.
      +# 
      +
      +# From Rives McDow (2002-04-09):
      +# The most interesting region I have found consists of three towns on the
      +# southern coast....  South Australia observes daylight saving time; Western
      +# Australia does not.  The two states are one and a half hours apart.  The
      +# residents decided to forget about this nonsense of changing the clock so
      +# much and set the local time 20 hours and 45 minutes from the
      +# international date line, or right in the middle of the time of South
      +# Australia and Western Australia....
      +#
      +# From Paul Eggert (2002-04-09):
      +# This is confirmed by the section entitled
      +# "What's the deal with time zones???" in
      +# .
      +#
      +# From Alex Livingston (2006-12-07):
      +# ... it was just on four years ago that I drove along the Eyre Highway,
      +# which passes through eastern Western Australia close to the southern
      +# coast of the continent.
      +#
      +# I paid particular attention to the time kept there. There can be no
      +# dispute that UTC+08:45 was considered "the time" from the border
      +# village just inside the border with South Australia to as far west
      +# as just east of Caiguna. There can also be no dispute that Eucla is
      +# the largest population centre in this zone....
      +#
      +# Now that Western Australia is observing daylight saving, the
      +# question arose whether this part of the state would follow suit. I
      +# just called the border village and confirmed that indeed they have,
      +# meaning that they are now observing UTC+09:45.
      +#
      +# (2006-12-09):
      +# I personally doubt that either experimentation with daylight saving
      +# in WA or its introduction in SA had anything to do with the genesis
      +# of this time zone.  My hunch is that it's been around since well
      +# before 1975.  I remember seeing it noted on road maps decades ago.
      +
      +# From Paul Eggert (2006-12-15):
      +# For lack of better info, assume the tradition dates back to the
      +# introduction of standard time in 1895.
      +
      +
      +# southeast Australia
      +#
      +# From Paul Eggert (2007-07-23):
      +# Starting autumn 2008 Victoria, NSW, South Australia, Tasmania and the ACT
      +# end DST the first Sunday in April and start DST the first Sunday in October.
      +# http://www.theage.com.au/news/national/daylight-savings-to-span-six-months/2007/06/27/1182623966703.html
      +
      +
      +# South Australia
      +
      +# From Bradley White (1991-03-04):
      +# A recent excerpt from an Australian newspaper...
      +# ...South Australia...[has] agreed to end daylight saving
      +# at 3am tomorrow (March 3)...
      +
      +# From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
      +# #   The state of SOUTH AUSTRALIA....[ Courtesy of S.A. Dept of Labour ]
      +# #						[ Nov 1990 ]
      +# ...
      +# Zone	Australia/South		9:30	AS	%sST
      +# ...
      +# Rule	 AS	1971	max	-	Oct	lastSun	2:00	1:00	D
      +# Rule	 AS	1972	1985	-	Mar	Sun>=1	3:00	0	C
      +# Rule	 AS	1986	1990	-	Mar	Sun>=15	3:00	0	C
      +# Rule	 AS	1991	max	-	Mar	Sun>=1	3:00	0	C
      +
      +# From Bradley White (1992-03-11):
      +# Recent correspondence with a friend in Adelaide
      +# contained the following exchange:  "Due to the Adelaide Festival,
      +# South Australia delays setting back our clocks for a few weeks."
      +
      +# From Robert Elz (1992-03-13):
      +# I heard that apparently (or at least, it appears that)
      +# South Aus will have an extra 3 weeks daylight saving every even
      +# numbered year (from 1990).  That's when the Adelaide Festival
      +# is on...
      +
      +# From Robert Elz (1992-03-16, 00:57:07 +1000):
      +# DST didn't end in Adelaide today (yesterday)....
      +# But whether it's "4th Sunday" or "2nd last Sunday" I have no idea whatever...
      +# (it's just as likely to be "the Sunday we pick for this year"...).
      +
      +# From Bradley White (1994-04-11):
      +# If Sun, 15 March, 1992 was at +1030 as kre asserts, but yet Sun, 20 March,
      +# 1994 was at +0930 as John Connolly's customer seems to assert, then I can
      +# only conclude that the actual rule is more complicated....
      +
      +# From John Warburton (1994-10-07):
      +# The new Daylight Savings dates for South Australia ...
      +# was gazetted in the Government Hansard on Sep 26 1994....
      +# start on last Sunday in October and end in last sunday in March.
      +
      +# From Paul Eggert (2007-07-23):
      +# See "southeast Australia" above for 2008 and later.
      +
      +# Tasmania
      +
      +# The rules for 1967 through 1991 were reported by George Shepherd
      +# via Simon Woodhead via Robert Elz (1991-03-06):
      +# #  The state of TASMANIA.. [Courtesy Tasmanian Dept of Premier + Cabinet ]
      +# #					[ Nov 1990 ]
      +
      +# From Bill Hart via Guy Harris (1991-10-10):
      +# Oh yes, the new daylight savings rules are uniquely tasmanian, we have
      +# 6 weeks a year now when we are out of sync with the rest of Australia
      +# (but nothing new about that).
      +
      +# From Alex Livingston (1999-10-04):
      +# I heard on the ABC (Australian Broadcasting Corporation) radio news on the
      +# (long) weekend that Tasmania, which usually goes its own way in this regard,
      +# has decided to join with most of NSW, the ACT, and most of Victoria
      +# (Australia) and start daylight saving on the last Sunday in August in 2000
      +# instead of the first Sunday in October.
      +
      +# Sim Alam (2000-07-03) reported a legal citation for the 2000/2001 rules:
      +# http://www.thelaw.tas.gov.au/fragview/42++1968+GS3A@EN+2000070300
      +
      +# From Paul Eggert (2007-07-23):
      +# See "southeast Australia" above for 2008 and later.
      +
      +# Victoria
      +
      +# The rules for 1971 through 1991 were reported by George Shepherd
      +# via Simon Woodhead via Robert Elz (1991-03-06):
      +# #   The state of VICTORIA.. [ Courtesy of Vic. Dept of Premier + Cabinet ]
      +# #						[ Nov 1990 ]
      +
      +# From Scott Harrington (2001-08-29):
      +# On KQED's "City Arts and Lectures" program last night I heard an
      +# interesting story about daylight savings time.  Dr. John Heilbron was
      +# discussing his book "The Sun in the Church: Cathedrals as Solar
      +# Observatories"[1], and in particular the Shrine of Remembrance[2] located
      +# in Melbourne, Australia.
      +#
      +# Apparently the shrine's main purpose is a beam of sunlight which
      +# illuminates a special spot on the floor at the 11th hour of the 11th day
      +# of the 11th month (Remembrance Day) every year in memory of Australia's
      +# fallen WWI soldiers.  And if you go there on Nov. 11, at 11am local time,
      +# you will indeed see the sunbeam illuminate the special spot at the
      +# expected time.
      +#
      +# However, that is only because of some special mirror contraption that had
      +# to be employed, since due to daylight savings time, the true solar time of
      +# the remembrance moment occurs one hour later (or earlier?).  Perhaps
      +# someone with more information on this jury-rig can tell us more.
      +#
      +# [1] http://www.hup.harvard.edu/catalog/HEISUN.html
      +# [2] http://www.shrine.org.au
      +
      +# From Paul Eggert (2007-07-23):
      +# See "southeast Australia" above for 2008 and later.
      +
      +# New South Wales
      +
      +# From Arthur David Olson:
      +# New South Wales and subjurisdictions have their own ideas of a fun time.
      +# Based on law library research by John Mackin,
      +# who notes:
      +#	In Australia, time is not legislated federally, but rather by the
      +#	individual states.  Thus, while such terms as ``Eastern Standard Time''
      +#	[I mean, of course, Australian EST, not any other kind] are in common
      +#	use, _they have NO REAL MEANING_, as they are not defined in the
      +#	legislation.  This is very important to understand.
      +#	I have researched New South Wales time only...
      +
      +# From Eric Ulevik (1999-05-26):
      +# DST will start in NSW on the last Sunday of August, rather than the usual
      +# October in 2000.  [See: Matthew Moore,
      +# 
      +# Two months more daylight saving
      +# 
      +# Sydney Morning Herald (1999-05-26).]
      +
      +# From Paul Eggert (1999-09-27):
      +# See the following official NSW source:
      +# 
      +# Daylight Saving in New South Wales.
      +# 
      +#
      +# Narrabri Shire (NSW) council has announced it will ignore the extension of
      +# daylight saving next year.  See:
      +# 
      +# Narrabri Council to ignore daylight saving
      +#  (1999-07-22).  For now, we'll wait to see if this really happens.
      +#
      +# Victoria will following NSW.  See:
      +# 
      +# Vic to extend daylight saving
      +#  (1999-07-28).
      +#
      +# However, South Australia rejected the DST request.  See:
      +# 
      +# South Australia rejects Olympics daylight savings request
      +#  (1999-07-19).
      +#
      +# Queensland also will not observe DST for the Olympics.  See:
      +# 
      +# Qld says no to daylight savings for Olympics
      +#  (1999-06-01), which quotes Queensland Premier Peter Beattie as saying
      +# ``Look you've got to remember in my family when this came up last time
      +# I voted for it, my wife voted against it and she said to me it's all very
      +# well for you, you don't have to worry about getting the children out of
      +# bed, getting them to school, getting them to sleep at night.
      +# I've been through all this argument domestically...my wife rules.''
      +#
      +# Broken Hill will stick with South Australian time in 2000.  See:
      +# 
      +# Broken Hill to be behind the times
      +#  (1999-07-21).
      +
      +# IATA SSIM (1998-09) says that the spring 2000 change for Australian
      +# Capital Territory, New South Wales except Lord Howe Island and Broken
      +# Hill, and Victoria will be August 27, presumably due to the Sydney Olympics.
      +
      +# From Eric Ulevik, referring to Sydney's Sun Herald (2000-08-13), page 29:
      +# The Queensland Premier Peter Beattie is encouraging northern NSW
      +# towns to use Queensland time.
      +
      +# From Paul Eggert (2007-07-23):
      +# See "southeast Australia" above for 2008 and later.
      +
      +# Yancowinna
      +
      +# From John Mackin (1989-01-04):
      +# `Broken Hill' means the County of Yancowinna.
      +
      +# From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
      +# # YANCOWINNA..  [ Confirmation courtesy of Broken Hill Postmaster ]
      +# #					[ Dec 1990 ]
      +# ...
      +# # Yancowinna uses Central Standard Time, despite [its] location on the
      +# # New South Wales side of the S.A. border. Most business and social dealings
      +# # are with CST zones, therefore CST is legislated by local government
      +# # although the switch to Summer Time occurs in line with N.S.W. There have
      +# # been years when this did not apply, but the historical data is not
      +# # presently available.
      +# Zone	Australia/Yancowinna	9:30	 AY	%sST
      +# ...
      +# Rule	 AY	1971	1985	-	Oct	lastSun	2:00	1:00	D
      +# Rule	 AY	1972	only	-	Feb	lastSun	3:00	0	C
      +# [followed by other Rules]
      +
      +# Lord Howe Island
      +
      +# From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
      +# LHI...		[ Courtesy of Pauline Van Winsen ]
      +#					[ Dec 1990 ]
      +# Lord Howe Island is located off the New South Wales coast, and is half an
      +# hour ahead of NSW time.
      +
      +# From James Lonergan, Secretary, Lord Howe Island Board (2000-01-27):
      +# Lord Howe Island summer time in 2000/2001 will commence on the same
      +# date as the rest of NSW (i.e. 2000-08-27).  For your information the
      +# Lord Howe Island Board (controlling authority for the Island) is
      +# seeking the community's views on various options for summer time
      +# arrangements on the Island, e.g. advance clocks by 1 full hour
      +# instead of only 30 minutes.  [Dependent] on the wishes of residents
      +# the Board may approach the NSW government to change the existing
      +# arrangements.  The starting date for summer time on the Island will
      +# however always coincide with the rest of NSW.
      +
      +# From James Lonergan, Secretary, Lord Howe Island Board (2000-10-25):
      +# Lord Howe Island advances clocks by 30 minutes during DST in NSW and retards
      +# clocks by 30 minutes when DST finishes. Since DST was most recently
      +# introduced in NSW, the "changeover" time on the Island has been 02:00 as
      +# shown on clocks on LHI. I guess this means that for 30 minutes at the start
      +# of DST, LHI is actually 1 hour ahead of the rest of NSW.
      +
      +# From Paul Eggert (2006-03-22):
      +# For Lord Howe dates we use Shanks & Pottenger through 1989, and
      +# Lonergan thereafter.  For times we use Lonergan.
      +
      +# From Paul Eggert (2007-07-23):
      +# See "southeast Australia" above for 2008 and later.
      +
      +# From Steffen Thorsen (2009-04-28):
      +# According to the official press release, South Australia's extended daylight
      +# saving period will continue with the same rules as used during the 2008-2009
      +# summer (southern hemisphere).
      +#
      +# From
      +# 
      +# http://www.safework.sa.gov.au/uploaded_files/DaylightDatesSet.pdf
      +# 
      +# The extended daylight saving period that South Australia has been trialling
      +# for over the last year is now set to be ongoing.
      +# Daylight saving will continue to start on the first Sunday in October each
      +# year and finish on the first Sunday in April the following year.
      +# Industrial Relations Minister, Paul Caica, says this provides South Australia
      +# with a consistent half hour time difference with NSW, Victoria, Tasmania and
      +# the ACT for all 52 weeks of the year...
      +#
      +# We have a wrap-up here:
      +# 
      +# http://www.timeanddate.com/news/time/south-australia-extends-dst.html
      +# 
      +###############################################################################
      +
      +# New Zealand
      +
      +# From Mark Davies (1990-10-03):
      +# the 1989/90 year was a trial of an extended "daylight saving" period.
      +# This trial was deemed successful and the extended period adopted for
      +# subsequent years (with the addition of a further week at the start).
      +# source -- phone call to Ministry of Internal Affairs Head Office.
      +
      +# From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
      +# # The Country of New Zealand   (Australia's east island -) Gee they hate that!
      +# #				   or is Australia the west island of N.Z.
      +# #	[ courtesy of Geoff Tribble.. Auckland N.Z. ]
      +# #				[ Nov 1990 ]
      +# ...
      +# Rule	NZ      1974    1988	-	Oct	lastSun	2:00	1:00	D
      +# Rule	NZ	1989	max	-	Oct	Sun>=1	2:00	1:00	D
      +# Rule	NZ      1975    1989	-	Mar	Sun>=1	3:00	0	S
      +# Rule	NZ	1990	max	-	Mar	lastSun	3:00	0	S
      +# ...
      +# Zone	NZ			12:00	NZ		NZ%sT	# New Zealand
      +# Zone	NZ-CHAT			12:45	-		NZ-CHAT # Chatham Island
      +
      +# From Arthur David Olson (1992-03-08):
      +# The chosen rules use the Davies October 8 values for the start of DST in 1989
      +# rather than the October 1 value.
      +
      +# From Paul Eggert (1995-12-19);
      +# Shank & Pottenger report 2:00 for all autumn changes in Australia and NZ.
      +# Robert Uzgalis writes that the New Zealand Daylight
      +# Savings Time Order in Council dated 1990-06-18 specifies 2:00 standard
      +# time on both the first Sunday in October and the third Sunday in March.
      +# As with Australia, we'll assume the tradition is 2:00s, not 2:00.
      +#
      +# From Paul Eggert (2006-03-22):
      +# The Department of Internal Affairs (DIA) maintains a brief history,
      +# as does Carol Squires; see tz-link.htm for the full references.
      +# Use these sources in preference to Shanks & Pottenger.
      +#
      +# For Chatham, IATA SSIM (1991/1999) gives the NZ rules but with
      +# transitions at 2:45 local standard time; this confirms that Chatham
      +# is always exactly 45 minutes ahead of Auckland.
      +
      +# From Colin Sharples (2007-04-30):
      +# DST will now start on the last Sunday in September, and end on the
      +# first Sunday in April.  The changes take effect this year, meaning
      +# that DST will begin on 2007-09-30 2008-04-06.
      +# http://www.dia.govt.nz/diawebsite.nsf/wpg_URL/Services-Daylight-Saving-Daylight-saving-to-be-extended
      +
      +###############################################################################
      +
      +
      +# Fiji
      +
      +# Howse writes (p 153) that in 1879 the British governor of Fiji
      +# enacted an ordinance standardizing the islands on Antipodean Time
      +# instead of the American system (which was one day behind).
      +
      +# From Rives McDow (1998-10-08):
      +# Fiji will introduce DST effective 0200 local time, 1998-11-01
      +# until 0300 local time 1999-02-28.  Each year the DST period will
      +# be from the first Sunday in November until the last Sunday in February.
      +
      +# From Paul Eggert (2000-01-08):
      +# IATA SSIM (1999-09) says DST ends 0100 local time.  Go with McDow.
      +
      +# From the BBC World Service (1998-10-31 11:32 UTC):
      +# The Fijiian government says the main reasons for the time change is to
      +# improve productivity and reduce road accidents.  But correspondents say it
      +# also hopes the move will boost Fiji's ability to compete with other pacific
      +# islands in the effort to attract tourists to witness the dawning of the new
      +# millenium.
      +
      +# http://www.fiji.gov.fj/press/2000_09/2000_09_13-05.shtml (2000-09-13)
      +# reports that Fiji has discontinued DST.
      +
      +# Johnston
      +
      +# Johnston data is from usno1995.
      +
      +
      +# Kiribati
      +
      +# From Paul Eggert (1996-01-22):
      +# Today's _Wall Street Journal_ (page 1) reports that Kiribati
      +# ``declared it the same day [throughout] the country as of Jan. 1, 1995''
      +# as part of the competition to be first into the 21st century.
      +
      +
      +# Kwajalein
      +
      +# In comp.risks 14.87 (26 August 1993), Peter Neumann writes:
      +# I wonder what happened in Kwajalein, where there was NO Friday,
      +# 1993-08-20.  Thursday night at midnight Kwajalein switched sides with
      +# respect to the International Date Line, to rejoin its fellow islands,
      +# going from 11:59 p.m. Thursday to 12:00 m. Saturday in a blink.
      +
      +
      +# N Mariana Is, Guam
      +
      +# Howse writes (p 153) ``The Spaniards, on the other hand, reached the
      +# Philippines and the Ladrones from America,'' and implies that the Ladrones
      +# (now called the Marianas) kept American date for quite some time.
      +# For now, we assume the Ladrones switched at the same time as the Philippines;
      +# see Asia/Manila.
      +
      +# US Public Law 106-564 (2000-12-23) made UTC+10 the official standard time,
      +# under the name "Chamorro Standard Time".  There is no official abbreviation,
      +# but Congressman Robert A. Underwood, author of the bill that became law,
      +# wrote in a press release (2000-12-27) that he will seek the use of "ChST".
      +
      +
      +# Micronesia
      +
      +# Alan Eugene Davis writes (1996-03-16),
      +# ``I am certain, having lived there for the past decade, that "Truk"
      +# (now properly known as Chuuk) ... is in the time zone GMT+10.''
      +#
      +# Shanks & Pottenger write that Truk switched from UTC+10 to UTC+11
      +# on 1978-10-01; ignore this for now.
      +
      +# From Paul Eggert (1999-10-29):
      +# The Federated States of Micronesia Visitors Board writes in
      +# 
      +# The Federated States of Micronesia - Visitor Information
      +#  (1999-01-26)
      +# that Truk and Yap are UTC+10, and Ponape and Kosrae are UTC+11.
      +# We don't know when Kosrae switched from UTC+12; assume January 1 for now.
      +
      +
      +# Midway
      +
      +# From Charles T O'Connor, KMTH DJ (1956),
      +# quoted in the KTMH section of the Radio Heritage Collection
      +#  (2002-12-31):
      +# For the past two months we've been on what is known as Daylight
      +# Saving Time.  This time has put us on air at 5am in the morning,
      +# your time down there in New Zealand.  Starting September 2, 1956
      +# we'll again go back to Standard Time.  This'll mean that we'll go to
      +# air at 6am your time.
      +#
      +# From Paul Eggert (2003-03-23):
      +# We don't know the date of that quote, but we'll guess they
      +# started DST on June 3.  Possibly DST was observed other years
      +# in Midway, but we have no record of it.
      +
      +
      +# Pitcairn
      +
      +# From Rives McDow (1999-11-08):
      +# A Proclamation was signed by the Governor of Pitcairn on the 27th March 1998
      +# with regard to Pitcairn Standard Time.  The Proclamation is as follows.
      +#
      +#	The local time for general purposes in the Islands shall be
      +#	Co-ordinated Universal time minus 8 hours and shall be known
      +#	as Pitcairn Standard Time.
      +#
      +# ... I have also seen Pitcairn listed as UTC minus 9 hours in several
      +# references, and can only assume that this was an error in interpretation
      +# somehow in light of this proclamation.
      +
      +# From Rives McDow (1999-11-09):
      +# The Proclamation regarding Pitcairn time came into effect on 27 April 1998
      +# ... at midnight.
      +
      +# From Howie Phelps (1999-11-10), who talked to a Pitcairner via shortwave:
      +# Betty Christian told me yesterday that their local time is the same as
      +# Pacific Standard Time. They used to be 1/2 hour different from us here in
      +# Sacramento but it was changed a couple of years ago.
      +
      +
      +# Samoa
      +
      +# Howse writes (p 153, citing p 10 of the 1883-11-18 New York Herald)
      +# that in 1879 the King of Samoa decided to change
      +# ``the date in his kingdom from the Antipodean to the American system,
      +# ordaining -- by a masterpiece of diplomatic flattery -- that
      +# the Fourth of July should be celebrated twice in that year.''
      +
      +
      +# Tonga
      +
      +# From Paul Eggert (1996-01-22):
      +# Today's _Wall Street Journal_ (p 1) reports that ``Tonga has been plotting
      +# to sneak ahead of [New Zealanders] by introducing daylight-saving time.''
      +# Since Kiribati has moved the Date Line it's not clear what Tonga will do.
      +
      +# Don Mundell writes in the 1997-02-20 Tonga Chronicle
      +# 
      +# How Tonga became `The Land where Time Begins'
      +# :
      +
      +# Until 1941 Tonga maintained a standard time 50 minutes ahead of NZST
      +# 12 hours and 20 minutes ahead of GMT.  When New Zealand adjusted its
      +# standard time in 1940s, Tonga had the choice of subtracting from its
      +# local time to come on the same standard time as New Zealand or of
      +# advancing its time to maintain the differential of 13 degrees
      +# (approximately 50 minutes ahead of New Zealand time).
      +#
      +# Because His Majesty King Taufa'ahau Tupou IV, then Crown Prince
      +# Tungi, preferred to ensure Tonga's title as the land where time
      +# begins, the Legislative Assembly approved the latter change.
      +#
      +# But some of the older, more conservative members from the outer
      +# islands objected. "If at midnight on Dec. 31, we move ahead 40
      +# minutes, as your Royal Highness wishes, what becomes of the 40
      +# minutes we have lost?"
      +#
      +# The Crown Prince, presented an unanswerable argument: "Remember that
      +# on the World Day of Prayer, you would be the first people on Earth
      +# to say your prayers in the morning."
      +
      +# From Paul Eggert (2006-03-22):
      +# Shanks & Pottenger say the transition was on 1968-10-01; go with Mundell.
      +
      +# From Eric Ulevik (1999-05-03):
      +# Tonga's director of tourism, who is also secretary of the National Millenium
      +# Committee, has a plan to get Tonga back in front.
      +# He has proposed a one-off move to tropical daylight saving for Tonga from
      +# October to March, which has won approval in principle from the Tongan
      +# Government.
      +
      +# From Steffen Thorsen (1999-09-09):
      +# * Tonga will introduce DST in November
      +#
      +# I was given this link by John Letts:
      +# 
      +# http://news.bbc.co.uk/hi/english/world/asia-pacific/newsid_424000/424764.stm
      +# 
      +#
      +# I have not been able to find exact dates for the transition in November
      +# yet. By reading this article it seems like Fiji will be 14 hours ahead
      +# of UTC as well, but as far as I know Fiji will only be 13 hours ahead
      +# (12 + 1 hour DST).
      +
      +# From Arthur David Olson (1999-09-20):
      +# According to 
      +# http://www.tongaonline.com/news/sept1799.html
      +# :
      +# "Daylight Savings Time will take effect on Oct. 2 through April 15, 2000
      +# and annually thereafter from the first Saturday in October through the
      +# third Saturday of April.  Under the system approved by Privy Council on
      +# Sept. 10, clocks must be turned ahead one hour on the opening day and
      +# set back an hour on the closing date."
      +# Alas, no indication of the time of day.
      +
      +# From Rives McDow (1999-10-06):
      +# Tonga started its Daylight Saving on Saturday morning October 2nd at 0200am.
      +# Daylight Saving ends on April 16 at 0300am which is Sunday morning.
      +
      +# From Steffen Thorsen (2000-10-31):
      +# Back in March I found a notice on the website http://www.tongaonline.com
      +# that Tonga changed back to standard time one month early, on March 19
      +# instead of the original reported date April 16. Unfortunately, the article
      +# is no longer available on the site, and I did not make a copy of the
      +# text, and I have forgotten to report it here.
      +# (Original URL was: http://www.tongaonline.com/news/march162000.htm )
      +
      +# From Rives McDow (2000-12-01):
      +# Tonga is observing DST as of 2000-11-04 and will stop on 2001-01-27.
      +
      +# From Sione Moala-Mafi (2001-09-20) via Rives McDow:
      +# At 2:00am on the first Sunday of November, the standard time in the Kingdom
      +# shall be moved forward by one hour to 3:00am.  At 2:00am on the last Sunday
      +# of January the standard time in the Kingdom shall be moved backward by one
      +# hour to 1:00am.
      +
      +# From Pulu 'Anau (2002-11-05):
      +# The law was for 3 years, supposedly to get renewed.  It wasn't.
      +
      +
      +# Wake
      +
      +# From Vernice Anderson, Personal Secretary to Philip Jessup,
      +# US Ambassador At Large (oral history interview, 1971-02-02):
      +#
      +# Saturday, the 14th [of October, 1950] -- ...  The time was all the
      +# more confusing at that point, because we had crossed the
      +# International Date Line, thus getting two Sundays.  Furthermore, we
      +# discovered that Wake Island had two hours of daylight saving time
      +# making calculation of time in Washington difficult if not almost
      +# impossible.
      +#
      +# http://www.trumanlibrary.org/wake/meeting.htm
      +
      +# From Paul Eggert (2003-03-23):
      +# We have no other report of DST in Wake Island, so omit this info for now.
      +
      +###############################################################################
      +
      +# The International Date Line
      +
      +# From Gwillim Law (2000-01-03):
      +#
      +# The International Date Line is not defined by any international standard,
      +# convention, or treaty.  Mapmakers are free to draw it as they please.
      +# Reputable mapmakers will simply ensure that every point of land appears on
      +# the correct side of the IDL, according to the date legally observed there.
      +#
      +# When Kiribati adopted a uniform date in 1995, thereby moving the Phoenix and
      +# Line Islands to the west side of the IDL (or, if you prefer, moving the IDL
      +# to the east side of the Phoenix and Line Islands), I suppose that most
      +# mapmakers redrew the IDL following the boundary of Kiribati.  Even that line
      +# has a rather arbitrary nature.  The straight-line boundaries between Pacific
      +# island nations that are shown on many maps are based on an international
      +# convention, but are not legally binding national borders.... The date is
      +# governed by the IDL; therefore, even on the high seas, there may be some
      +# places as late as fourteen hours later than UTC.  And, since the IDL is not
      +# an international standard, there are some places on the high seas where the
      +# correct date is ambiguous.
      +
      +# From Wikipedia  (2005-08-31):
      +# Before 1920, all ships kept local apparent time on the high seas by setting
      +# their clocks at night or at the morning sight so that, given the ship's
      +# speed and direction, it would be 12 o'clock when the Sun crossed the ship's
      +# meridian (12 o'clock = local apparent noon).  During 1917, at the
      +# Anglo-French Conference on Time-keeping at Sea, it was recommended that all
      +# ships, both military and civilian, should adopt hourly standard time zones
      +# on the high seas.  Whenever a ship was within the territorial waters of any
      +# nation it would use that nation's standard time.  The captain was permitted
      +# to change his ship's clocks at a time of his choice following his ship's
      +# entry into another zone time--he often chose midnight.  These zones were
      +# adopted by all major fleets between 1920 and 1925 but not by many
      +# independent merchant ships until World War II.
      +
      +# From Paul Eggert, using references suggested by Oscar van Vlijmen
      +# (2005-03-20):
      +#
      +# The American Practical Navigator (2002)
      +# 
      +# talks only about the 180-degree meridian with respect to ships in
      +# international waters; it ignores the international date line.
      diff --git a/jdk/test/sun/util/calendar/zi/tzdata/backward b/jdk/test/sun/util/calendar/zi/tzdata/backward
      new file mode 100644
      index 00000000000..4ccea7c7dbe
      --- /dev/null
      +++ b/jdk/test/sun/util/calendar/zi/tzdata/backward
      @@ -0,0 +1,140 @@
      +#
      +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      +#  
      +# This code is free software; you can redistribute it and/or modify it
      +# under the terms of the GNU General Public License version 2 only, as
      +# published by the Free Software Foundation.  Oracle designates this
      +# particular file as subject to the "Classpath" exception as provided
      +# by Oracle in the LICENSE file that accompanied this code.
      +#  
      +# This code is distributed in the hope that it will be useful, but WITHOUT
      +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      +# version 2 for more details (a copy is included in the LICENSE file that
      +# accompanied this code).
      +#  
      +# You should have received a copy of the GNU General Public License version
      +# 2 along with this work; if not, write to the Free Software Foundation,
      +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      +#  
      +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      +# or visit www.oracle.com if you need additional information or have any
      +# questions.
      +#
      +# 
      +# This file is in the public domain, so clarified as of
      +# 2009-05-17 by Arthur David Olson.
      +
      +# This file provides links between current names for time zones
      +# and their old names.  Many names changed in late 1993.
      +
      +Link	Africa/Asmara		Africa/Asmera
      +Link	Africa/Bamako		Africa/Timbuktu
      +Link	America/Argentina/Catamarca	America/Argentina/ComodRivadavia
      +Link	America/Adak		America/Atka
      +Link	America/Argentina/Buenos_Aires	America/Buenos_Aires
      +Link	America/Argentina/Catamarca	America/Catamarca
      +Link	America/Atikokan	America/Coral_Harbour
      +Link	America/Argentina/Cordoba	America/Cordoba
      +Link	America/Tijuana		America/Ensenada
      +Link	America/Indiana/Indianapolis	America/Fort_Wayne
      +Link	America/Indiana/Indianapolis	America/Indianapolis
      +Link	America/Argentina/Jujuy	America/Jujuy
      +Link	America/Indiana/Knox	America/Knox_IN
      +Link	America/Kentucky/Louisville	America/Louisville
      +Link	America/Argentina/Mendoza	America/Mendoza
      +Link	America/Rio_Branco	America/Porto_Acre
      +Link	America/Argentina/Cordoba	America/Rosario
      +Link	America/St_Thomas	America/Virgin
      +Link	Asia/Ashgabat		Asia/Ashkhabad
      +Link	Asia/Chongqing		Asia/Chungking
      +Link	Asia/Dhaka		Asia/Dacca
      +Link	Asia/Kathmandu		Asia/Katmandu
      +Link	Asia/Kolkata		Asia/Calcutta
      +Link	Asia/Macau		Asia/Macao
      +Link	Asia/Jerusalem		Asia/Tel_Aviv
      +Link	Asia/Ho_Chi_Minh	Asia/Saigon
      +Link	Asia/Thimphu		Asia/Thimbu
      +Link	Asia/Makassar		Asia/Ujung_Pandang
      +Link	Asia/Ulaanbaatar	Asia/Ulan_Bator
      +Link	Atlantic/Faroe		Atlantic/Faeroe
      +Link	Europe/Oslo		Atlantic/Jan_Mayen
      +Link	Australia/Sydney	Australia/ACT
      +Link	Australia/Sydney	Australia/Canberra
      +Link	Australia/Lord_Howe	Australia/LHI
      +Link	Australia/Sydney	Australia/NSW
      +Link	Australia/Darwin	Australia/North
      +Link	Australia/Brisbane	Australia/Queensland
      +Link	Australia/Adelaide	Australia/South
      +Link	Australia/Hobart	Australia/Tasmania
      +Link	Australia/Melbourne	Australia/Victoria
      +Link	Australia/Perth		Australia/West
      +Link	Australia/Broken_Hill	Australia/Yancowinna
      +Link	America/Rio_Branco	Brazil/Acre
      +Link	America/Noronha		Brazil/DeNoronha
      +Link	America/Sao_Paulo	Brazil/East
      +Link	America/Manaus		Brazil/West
      +Link	America/Halifax		Canada/Atlantic
      +Link	America/Winnipeg	Canada/Central
      +Link	America/Regina		Canada/East-Saskatchewan
      +Link	America/Toronto		Canada/Eastern
      +Link	America/Edmonton	Canada/Mountain
      +Link	America/St_Johns	Canada/Newfoundland
      +Link	America/Vancouver	Canada/Pacific
      +Link	America/Regina		Canada/Saskatchewan
      +Link	America/Whitehorse	Canada/Yukon
      +Link	America/Santiago	Chile/Continental
      +Link	Pacific/Easter		Chile/EasterIsland
      +Link	America/Havana		Cuba
      +Link	Africa/Cairo		Egypt
      +Link	Europe/Dublin		Eire
      +Link	Europe/London		Europe/Belfast
      +Link	Europe/Chisinau		Europe/Tiraspol
      +Link	Europe/London		GB
      +Link	Europe/London		GB-Eire
      +Link	Etc/GMT			GMT+0
      +Link	Etc/GMT			GMT-0
      +Link	Etc/GMT			GMT0
      +Link	Etc/GMT			Greenwich
      +Link	Asia/Hong_Kong		Hongkong
      +Link	Atlantic/Reykjavik	Iceland
      +Link	Asia/Tehran		Iran
      +Link	Asia/Jerusalem		Israel
      +Link	America/Jamaica		Jamaica
      +Link	Asia/Tokyo		Japan
      +Link	Pacific/Kwajalein	Kwajalein
      +Link	Africa/Tripoli		Libya
      +Link	America/Tijuana		Mexico/BajaNorte
      +Link	America/Mazatlan	Mexico/BajaSur
      +Link	America/Mexico_City	Mexico/General
      +Link	Pacific/Auckland	NZ
      +Link	Pacific/Chatham		NZ-CHAT
      +Link	America/Denver		Navajo
      +Link	Asia/Shanghai		PRC
      +Link	Pacific/Pago_Pago	Pacific/Samoa
      +Link	Pacific/Chuuk		Pacific/Yap
      +Link	Pacific/Chuuk		Pacific/Truk
      +Link	Pacific/Pohnpei		Pacific/Ponape
      +Link	Europe/Warsaw		Poland
      +Link	Europe/Lisbon		Portugal
      +Link	Asia/Taipei		ROC
      +Link	Asia/Seoul		ROK
      +Link	Asia/Singapore		Singapore
      +Link	Europe/Istanbul		Turkey
      +Link	Etc/UCT			UCT
      +Link	America/Anchorage	US/Alaska
      +Link	America/Adak		US/Aleutian
      +Link	America/Phoenix		US/Arizona
      +Link	America/Chicago		US/Central
      +Link	America/Indiana/Indianapolis	US/East-Indiana
      +Link	America/New_York	US/Eastern
      +Link	Pacific/Honolulu	US/Hawaii
      +Link	America/Indiana/Knox	US/Indiana-Starke
      +Link	America/Detroit		US/Michigan
      +Link	America/Denver		US/Mountain
      +Link	America/Los_Angeles	US/Pacific
      +Link	Pacific/Pago_Pago	US/Samoa
      +Link	Etc/UTC			UTC
      +Link	Etc/UTC			Universal
      +Link	Europe/Moscow		W-SU
      +Link	Etc/UTC			Zulu
      diff --git a/jdk/test/sun/util/calendar/zi/tzdata/etcetera b/jdk/test/sun/util/calendar/zi/tzdata/etcetera
      new file mode 100644
      index 00000000000..609b305493c
      --- /dev/null
      +++ b/jdk/test/sun/util/calendar/zi/tzdata/etcetera
      @@ -0,0 +1,104 @@
      +#
      +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      +#  
      +# This code is free software; you can redistribute it and/or modify it
      +# under the terms of the GNU General Public License version 2 only, as
      +# published by the Free Software Foundation.  Oracle designates this
      +# particular file as subject to the "Classpath" exception as provided
      +# by Oracle in the LICENSE file that accompanied this code.
      +#  
      +# This code is distributed in the hope that it will be useful, but WITHOUT
      +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      +# version 2 for more details (a copy is included in the LICENSE file that
      +# accompanied this code).
      +#  
      +# You should have received a copy of the GNU General Public License version
      +# 2 along with this work; if not, write to the Free Software Foundation,
      +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      +#  
      +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      +# or visit www.oracle.com if you need additional information or have any
      +# questions.
      +#
      +# 
      +# This file is in the public domain, so clarified as of
      +# 2009-05-17 by Arthur David Olson.
      +
      +# These entries are mostly present for historical reasons, so that
      +# people in areas not otherwise covered by the tz files could "zic -l"
      +# to a time zone that was right for their area.  These days, the
      +# tz files cover almost all the inhabited world, and the only practical
      +# need now for the entries that are not on UTC are for ships at sea
      +# that cannot use POSIX TZ settings.
      +
      +Zone	Etc/GMT		0	-	GMT
      +Zone	Etc/UTC		0	-	UTC
      +Zone	Etc/UCT		0	-	UCT
      +
      +# The following link uses older naming conventions,
      +# but it belongs here, not in the file `backward',
      +# as functions like gmtime load the "GMT" file to handle leap seconds properly.
      +# We want this to work even on installations that omit the other older names.
      +Link	Etc/GMT				GMT
      +
      +Link	Etc/UTC				Etc/Universal
      +Link	Etc/UTC				Etc/Zulu
      +
      +Link	Etc/GMT				Etc/Greenwich
      +Link	Etc/GMT				Etc/GMT-0
      +Link	Etc/GMT				Etc/GMT+0
      +Link	Etc/GMT				Etc/GMT0
      +
      +# We use POSIX-style signs in the Zone names and the output abbreviations,
      +# even though this is the opposite of what many people expect.
      +# POSIX has positive signs west of Greenwich, but many people expect
      +# positive signs east of Greenwich.  For example, TZ='Etc/GMT+4' uses
      +# the abbreviation "GMT+4" and corresponds to 4 hours behind UTC
      +# (i.e. west of Greenwich) even though many people would expect it to
      +# mean 4 hours ahead of UTC (i.e. east of Greenwich).
      +#
      +# In the draft 5 of POSIX 1003.1-200x, the angle bracket notation allows for
      +# TZ='+4'; if you want time zone abbreviations conforming to
      +# ISO 8601 you can use TZ='<-0400>+4'.  Thus the commonly-expected
      +# offset is kept within the angle bracket (and is used for display)
      +# while the POSIX sign is kept outside the angle bracket (and is used
      +# for calculation).
      +#
      +# Do not use a TZ setting like TZ='GMT+4', which is four hours behind
      +# GMT but uses the completely misleading abbreviation "GMT".
      +
      +# Earlier incarnations of this package were not POSIX-compliant,
      +# and had lines such as
      +#		Zone	GMT-12		-12	-	GMT-1200
      +# We did not want things to change quietly if someone accustomed to the old
      +# way does a
      +#		zic -l GMT-12
      +# so we moved the names into the Etc subdirectory.
      +
      +Zone	Etc/GMT-14	14	-	GMT-14	# 14 hours ahead of GMT
      +Zone	Etc/GMT-13	13	-	GMT-13
      +Zone	Etc/GMT-12	12	-	GMT-12
      +Zone	Etc/GMT-11	11	-	GMT-11
      +Zone	Etc/GMT-10	10	-	GMT-10
      +Zone	Etc/GMT-9	9	-	GMT-9
      +Zone	Etc/GMT-8	8	-	GMT-8
      +Zone	Etc/GMT-7	7	-	GMT-7
      +Zone	Etc/GMT-6	6	-	GMT-6
      +Zone	Etc/GMT-5	5	-	GMT-5
      +Zone	Etc/GMT-4	4	-	GMT-4
      +Zone	Etc/GMT-3	3	-	GMT-3
      +Zone	Etc/GMT-2	2	-	GMT-2
      +Zone	Etc/GMT-1	1	-	GMT-1
      +Zone	Etc/GMT+1	-1	-	GMT+1
      +Zone	Etc/GMT+2	-2	-	GMT+2
      +Zone	Etc/GMT+3	-3	-	GMT+3
      +Zone	Etc/GMT+4	-4	-	GMT+4
      +Zone	Etc/GMT+5	-5	-	GMT+5
      +Zone	Etc/GMT+6	-6	-	GMT+6
      +Zone	Etc/GMT+7	-7	-	GMT+7
      +Zone	Etc/GMT+8	-8	-	GMT+8
      +Zone	Etc/GMT+9	-9	-	GMT+9
      +Zone	Etc/GMT+10	-10	-	GMT+10
      +Zone	Etc/GMT+11	-11	-	GMT+11
      +Zone	Etc/GMT+12	-12	-	GMT+12
      diff --git a/jdk/test/sun/util/calendar/zi/tzdata/europe b/jdk/test/sun/util/calendar/zi/tzdata/europe
      new file mode 100644
      index 00000000000..9a0d0b9db94
      --- /dev/null
      +++ b/jdk/test/sun/util/calendar/zi/tzdata/europe
      @@ -0,0 +1,2879 @@
      +#
      +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      +#  
      +# This code is free software; you can redistribute it and/or modify it
      +# under the terms of the GNU General Public License version 2 only, as
      +# published by the Free Software Foundation.  Oracle designates this
      +# particular file as subject to the "Classpath" exception as provided
      +# by Oracle in the LICENSE file that accompanied this code.
      +#  
      +# This code is distributed in the hope that it will be useful, but WITHOUT
      +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      +# version 2 for more details (a copy is included in the LICENSE file that
      +# accompanied this code).
      +#  
      +# You should have received a copy of the GNU General Public License version
      +# 2 along with this work; if not, write to the Free Software Foundation,
      +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      +#  
      +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      +# or visit www.oracle.com if you need additional information or have any
      +# questions.
      +#
      +# 
      +# This file is in the public domain, so clarified as of
      +# 2009-05-17 by Arthur David Olson.
      +
      +# This data is by no means authoritative; if you think you know better,
      +# go ahead and edit the file (and please send any changes to
      +# tz@elsie.nci.nih.gov for general use in the future).
      +
      +# From Paul Eggert (2006-03-22):
      +# A good source for time zone historical data outside the U.S. is
      +# Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition),
      +# San Diego: ACS Publications, Inc. (2003).
      +#
      +# Gwillim Law writes that a good source
      +# for recent time zone data is the International Air Transport
      +# Association's Standard Schedules Information Manual (IATA SSIM),
      +# published semiannually.  Law sent in several helpful summaries
      +# of the IATA's data after 1990.
      +#
      +# Except where otherwise noted, Shanks & Pottenger is the source for
      +# entries through 1991, and IATA SSIM is the source for entries afterwards.
      +#
      +# Other sources occasionally used include:
      +#
      +#	Edward W. Whitman, World Time Differences,
      +#	Whitman Publishing Co, 2 Niagara Av, Ealing, London (undated),
      +#	which I found in the UCLA library.
      +#
      +#	
      +#	William Willett, The Waste of Daylight, 19th edition
      +#	 (1914-03)
      +#
      +#	Brazil's Departamento Servico da Hora (DSH),
      +#	
      +#	History of Summer Time
      +#	 (1998-09-21, in Portuguese)
      +
      +#
      +# I invented the abbreviations marked `*' in the following table;
      +# the rest are from earlier versions of this file, or from other sources.
      +# Corrections are welcome!
      +#                   std dst  2dst
      +#                   LMT           Local Mean Time
      +#       -4:00       AST ADT       Atlantic
      +#       -3:00       WGT WGST      Western Greenland*
      +#       -1:00       EGT EGST      Eastern Greenland*
      +#        0:00       GMT BST  BDST Greenwich, British Summer
      +#        0:00       GMT IST       Greenwich, Irish Summer
      +#        0:00       WET WEST WEMT Western Europe
      +#        0:19:32.13 AMT NST       Amsterdam, Netherlands Summer (1835-1937)*
      +#        0:20       NET NEST      Netherlands (1937-1940)*
      +#        1:00       CET CEST CEMT Central Europe
      +#        1:00:14    SET           Swedish (1879-1899)*
      +#        2:00       EET EEST      Eastern Europe
      +#        3:00       MSK MSD       Moscow
      +#
      +# A reliable and entertaining source about time zones, especially in Britain,
      +# Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
      +
      +# From Peter Ilieve (1994-12-04),
      +# The original six [EU members]: Belgium, France, (West) Germany, Italy,
      +# Luxembourg, the Netherlands.
      +# Plus, from 1 Jan 73: Denmark, Ireland, United Kingdom.
      +# Plus, from 1 Jan 81: Greece.
      +# Plus, from 1 Jan 86: Spain, Portugal.
      +# Plus, from 1 Jan 95: Austria, Finland, Sweden. (Norway negotiated terms for
      +# entry but in a referendum on 28 Nov 94 the people voted No by 52.2% to 47.8%
      +# on a turnout of 88.6%. This was almost the same result as Norway's previous
      +# referendum in 1972, they are the only country to have said No twice.
      +# Referendums in the other three countries voted Yes.)
      +# ...
      +# Estonia ... uses EU dates but not at 01:00 GMT, they use midnight GMT.
      +# I don't think they know yet what they will do from 1996 onwards.
      +# ...
      +# There shouldn't be any [current members who are not using EU rules].
      +# A Directive has the force of law, member states are obliged to enact
      +# national law to implement it. The only contentious issue was the
      +# different end date for the UK and Ireland, and this was always allowed
      +# in the Directive.
      +
      +
      +###############################################################################
      +
      +# Britain (United Kingdom) and Ireland (Eire)
      +
      +# From Peter Ilieve (1994-07-06):
      +#
      +# On 17 Jan 1994 the Independent, a UK quality newspaper, had a piece about
      +# historical vistas along the Thames in west London. There was a photo
      +# and a sketch map showing some of the sightlines involved. One paragraph
      +# of the text said:
      +#
      +# `An old stone obelisk marking a forgotten terrestrial meridian stands
      +# beside the river at Kew. In the 18th century, before time and longitude
      +# was standardised by the Royal Observatory in Greenwich, scholars observed
      +# this stone and the movement of stars from Kew Observatory nearby. They
      +# made their calculations and set the time for the Horse Guards and Parliament,
      +# but now the stone is obscured by scrubwood and can only be seen by walking
      +# along the towpath within a few yards of it.'
      +#
      +# I have a one inch to one mile map of London and my estimate of the stone's
      +# position is 51 deg. 28' 30" N, 0 deg. 18' 45" W. The longitude should
      +# be within about +-2". The Ordnance Survey grid reference is TQ172761.
      +#
      +# [This yields GMTOFF = -0:01:15 for London LMT in the 18th century.]
      +
      +# From Paul Eggert (1993-11-18):
      +#
      +# Howse writes that Britain was the first country to use standard time.
      +# The railways cared most about the inconsistencies of local mean time,
      +# and it was they who forced a uniform time on the country.
      +# The original idea was credited to Dr. William Hyde Wollaston (1766-1828)
      +# and was popularized by Abraham Follett Osler (1808-1903).
      +# The first railway to adopt London time was the Great Western Railway
      +# in November 1840; other railways followed suit, and by 1847 most
      +# (though not all) railways used London time.  On 1847-09-22 the
      +# Railway Clearing House, an industry standards body, recommended that GMT be
      +# adopted at all stations as soon as the General Post Office permitted it.
      +# The transition occurred on 12-01 for the L&NW, the Caledonian,
      +# and presumably other railways; the January 1848 Bradshaw's lists many
      +# railways as using GMT.  By 1855 the vast majority of public
      +# clocks in Britain were set to GMT (though some, like the great clock
      +# on Tom Tower at Christ Church, Oxford, were fitted with two minute hands,
      +# one for local time and one for GMT).  The last major holdout was the legal
      +# system, which stubbornly stuck to local time for many years, leading
      +# to oddities like polls opening at 08:13 and closing at 16:13.
      +# The legal system finally switched to GMT when the Statutes (Definition
      +# of Time) Act took effect; it received the Royal Assent on 1880-08-02.
      +#
      +# In the tables below, we condense this complicated story into a single
      +# transition date for London, namely 1847-12-01.  We don't know as much
      +# about Dublin, so we use 1880-08-02, the legal transition time.
      +
      +# From Paul Eggert (2003-09-27):
      +# Summer Time was first seriously proposed by William Willett (1857-1915),
      +# a London builder and member of the Royal Astronomical Society
      +# who circulated a pamphlet ``The Waste of Daylight'' (1907)
      +# that proposed advancing clocks 20 minutes on each of four Sundays in April,
      +# and retarding them by the same amount on four Sundays in September.
      +# A bill was drafted in 1909 and introduced in Parliament several times,
      +# but it met with ridicule and opposition, especially from farming interests.
      +# Later editions of the pamphlet proposed one-hour summer time, and
      +# it was eventually adopted as a wartime measure in 1916.
      +# See: Summer Time Arrives Early, The Times (2000-05-18).
      +# A monument to Willett was unveiled on 1927-05-21, in an open space in
      +# a 45-acre wood near Chislehurst, Kent that was purchased by popular
      +# subscription and open to the public.  On the south face of the monolith,
      +# designed by G. W. Miller, is the...William Willett Memorial Sundial,
      +# which is permanently set to Summer Time.
      +
      +# From Winston Churchill (1934-04-28):
      +# It is one of the paradoxes of history that we should owe the boon of
      +# summer time, which gives every year to the people of this country
      +# between 160 and 170 hours more daylight leisure, to a war which
      +# plunged Europe into darkness for four years, and shook the
      +# foundations of civilization throughout the world.
      +#	-- 
      +#	"A Silent Toast to William Willett", Pictorial Weekly
      +#	
      +
      +# From Paul Eggert (1996-09-03):
      +# The OED Supplement says that the English originally said ``Daylight Saving''
      +# when they were debating the adoption of DST in 1908; but by 1916 this
      +# term appears only in quotes taken from DST's opponents, whereas the
      +# proponents (who eventually won the argument) are quoted as using ``Summer''.
      +
      +# From Arthur David Olson (1989-01-19):
      +#
      +# A source at the British Information Office in New York avers that it's
      +# known as "British" Summer Time in all parts of the United Kingdom.
      +
      +# Date: 4 Jan 89 08:57:25 GMT (Wed)
      +# From: Jonathan Leffler
      +# [British Summer Time] is fixed annually by Act of Parliament.
      +# If you can predict what Parliament will do, you should be in
      +# politics making a fortune, not computing.
      +
      +# From Chris Carrier (1996-06-14):
      +# I remember reading in various wartime issues of the London Times the
      +# acronym BDST for British Double Summer Time.  Look for the published
      +# time of sunrise and sunset in The Times, when BDST was in effect, and
      +# if you find a zone reference it will say, "All times B.D.S.T."
      +
      +# From Joseph S. Myers (1999-09-02):
      +# ... some military cables (WO 219/4100 - this is a copy from the
      +# main SHAEF archives held in the US National Archives, SHAEF/5252/8/516)
      +# agree that the usage is BDST (this appears in a message dated 17 Feb 1945).
      +
      +# From Joseph S. Myers (2000-10-03):
      +# On 18th April 1941, Sir Stephen Tallents of the BBC wrote to Sir
      +# Alexander Maxwell of the Home Office asking whether there was any
      +# official designation; the reply of the 21st was that there wasn't
      +# but he couldn't think of anything better than the "Double British
      +# Summer Time" that the BBC had been using informally.
      +# http://student.cusu.cam.ac.uk/~jsm28/british-time/bbc-19410418.png
      +# http://student.cusu.cam.ac.uk/~jsm28/british-time/ho-19410421.png
      +
      +# From Sir Alexander Maxwell in the above-mentioned letter (1941-04-21):
      +# [N]o official designation has as far as I know been adopted for the time
      +# which is to be introduced in May....
      +# I cannot think of anything better than "Double British Summer Time"
      +# which could not be said to run counter to any official description.
      +
      +# From Paul Eggert (2000-10-02):
      +# Howse writes (p 157) `DBST' too, but `BDST' seems to have been common
      +# and follows the more usual convention of putting the location name first,
      +# so we use `BDST'.
      +
      +# Peter Ilieve (1998-04-19) described at length
      +# the history of summer time legislation in the United Kingdom.
      +# Since 1998 Joseph S. Myers has been updating
      +# and extending this list, which can be found in
      +# http://student.cusu.cam.ac.uk/~jsm28/british-time/
      +# 
      +# History of legal time in Britain
      +# 
      +# Rob Crowther (2012-01-04) reports that that URL no longer
      +# exists, and the article can now be found at:
      +# 
      +# http://www.polyomino.org.uk/british-time/
      +# 
      +
      +# From Joseph S. Myers (1998-01-06):
      +#
      +# The legal time in the UK outside of summer time is definitely GMT, not UTC;
      +# see Lord Tanlaw's speech
      +# 
      +# (Lords Hansard 11 June 1997 columns 964 to 976)
      +# .
      +
      +# From Paul Eggert (2006-03-22):
      +#
      +# For lack of other data, follow Shanks & Pottenger for Eire in 1940-1948.
      +#
      +# Given Ilieve and Myers's data, the following claims by Shanks & Pottenger
      +# are incorrect:
      +#     * Wales did not switch from GMT to daylight saving time until
      +#	1921 Apr 3, when they began to conform with the rest of Great Britain.
      +# Actually, Wales was identical after 1880.
      +#     * Eire had two transitions on 1916 Oct 1.
      +# It actually just had one transition.
      +#     * Northern Ireland used single daylight saving time throughout WW II.
      +# Actually, it conformed to Britain.
      +#     * GB-Eire changed standard time to 1 hour ahead of GMT on 1968-02-18.
      +# Actually, that date saw the usual switch to summer time.
      +# Standard time was not changed until 1968-10-27 (the clocks didn't change).
      +#
      +# Here is another incorrect claim by Shanks & Pottenger:
      +#     * Jersey, Guernsey, and the Isle of Man did not switch from GMT
      +#	to daylight saving time until 1921 Apr 3, when they began to
      +#	conform with Great Britain.
      +# S.R.&O. 1916, No. 382 and HO 45/10811/312364 (quoted above) say otherwise.
      +#
      +# The following claim by Shanks & Pottenger is possible though doubtful;
      +# we'll ignore it for now.
      +#     * Dublin's 1971-10-31 switch was at 02:00, even though London's was 03:00.
      +#
      +#
      +# Whitman says Dublin Mean Time was -0:25:21, which is more precise than
      +# Shanks & Pottenger.
      +# Perhaps this was Dunsink Observatory Time, as Dunsink Observatory
      +# (8 km NW of Dublin's center) seemingly was to Dublin as Greenwich was
      +# to London.  For example:
      +#
      +#   "Timeball on the ballast office is down.  Dunsink time."
      +#   -- James Joyce, Ulysses
      +
      +# From Joseph S. Myers (2005-01-26):
      +# Irish laws are available online at www.irishstatutebook.ie.  These include
      +# various relating to legal time, for example:
      +#
      +# ZZA13Y1923.html ZZA12Y1924.html ZZA8Y1925.html ZZSIV20PG1267.html
      +#
      +# ZZSI71Y1947.html ZZSI128Y1948.html ZZSI23Y1949.html ZZSI41Y1950.html
      +# ZZSI27Y1951.html ZZSI73Y1952.html
      +#
      +# ZZSI11Y1961.html ZZSI232Y1961.html ZZSI182Y1962.html
      +# ZZSI167Y1963.html ZZSI257Y1964.html ZZSI198Y1967.html
      +# ZZA23Y1968.html ZZA17Y1971.html
      +#
      +# ZZSI67Y1981.html ZZSI212Y1982.html ZZSI45Y1986.html
      +# ZZSI264Y1988.html ZZSI52Y1990.html ZZSI371Y1992.html
      +# ZZSI395Y1994.html ZZSI484Y1997.html ZZSI506Y2001.html
      +#
      +# [These are all relative to the root, e.g., the first is
      +# .]
      +#
      +# (These are those I found, but there could be more.  In any case these
      +# should allow various updates to the comments in the europe file to cover
      +# the laws applicable in Ireland.)
      +#
      +# (Note that the time in the Republic of Ireland since 1968 has been defined
      +# in terms of standard time being GMT+1 with a period of winter time when it
      +# is GMT, rather than standard time being GMT with a period of summer time
      +# being GMT+1.)
      +
      +# From Paul Eggert (1999-03-28):
      +# Clive Feather (, 1997-03-31)
      +# reports that Folkestone (Cheriton) Shuttle Terminal uses Concession Time
      +# (CT), equivalent to French civil time.
      +# Julian Hill (, 1998-09-30) reports that
      +# trains between Dollands Moor (the freight facility next door)
      +# and Frethun run in CT.
      +# My admittedly uninformed guess is that the terminal has two authorities,
      +# the French concession operators and the British civil authorities,
      +# and that the time depends on who you're talking to.
      +# If, say, the British police were called to the station for some reason,
      +# I would expect the official police report to use GMT/BST and not CET/CEST.
      +# This is a borderline case, but for now let's stick to GMT/BST.
      +
      +# From an anonymous contributor (1996-06-02):
      +# The law governing time in Ireland is under Statutory Instrument SI 395/94,
      +# which gives force to European Union 7th Council Directive # 94/21/EC.
      +# Under this directive, the Minister for Justice in Ireland makes appropriate
      +# regulations. I spoke this morning with the Secretary of the Department of
      +# Justice (tel +353 1 678 9711) who confirmed to me that the correct name is
      +# "Irish Summer Time", abbreviated to "IST".
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +# Summer Time Act, 1916
      +Rule	GB-Eire	1916	only	-	May	21	2:00s	1:00	BST
      +Rule	GB-Eire	1916	only	-	Oct	 1	2:00s	0	GMT
      +# S.R.&O. 1917, No. 358
      +Rule	GB-Eire	1917	only	-	Apr	 8	2:00s	1:00	BST
      +Rule	GB-Eire	1917	only	-	Sep	17	2:00s	0	GMT
      +# S.R.&O. 1918, No. 274
      +Rule	GB-Eire	1918	only	-	Mar	24	2:00s	1:00	BST
      +Rule	GB-Eire	1918	only	-	Sep	30	2:00s	0	GMT
      +# S.R.&O. 1919, No. 297
      +Rule	GB-Eire	1919	only	-	Mar	30	2:00s	1:00	BST
      +Rule	GB-Eire	1919	only	-	Sep	29	2:00s	0	GMT
      +# S.R.&O. 1920, No. 458
      +Rule	GB-Eire	1920	only	-	Mar	28	2:00s	1:00	BST
      +# S.R.&O. 1920, No. 1844
      +Rule	GB-Eire	1920	only	-	Oct	25	2:00s	0	GMT
      +# S.R.&O. 1921, No. 363
      +Rule	GB-Eire	1921	only	-	Apr	 3	2:00s	1:00	BST
      +Rule	GB-Eire	1921	only	-	Oct	 3	2:00s	0	GMT
      +# S.R.&O. 1922, No. 264
      +Rule	GB-Eire	1922	only	-	Mar	26	2:00s	1:00	BST
      +Rule	GB-Eire	1922	only	-	Oct	 8	2:00s	0	GMT
      +# The Summer Time Act, 1922
      +Rule	GB-Eire	1923	only	-	Apr	Sun>=16	2:00s	1:00	BST
      +Rule	GB-Eire	1923	1924	-	Sep	Sun>=16	2:00s	0	GMT
      +Rule	GB-Eire	1924	only	-	Apr	Sun>=9	2:00s	1:00	BST
      +Rule	GB-Eire	1925	1926	-	Apr	Sun>=16	2:00s	1:00	BST
      +# The Summer Time Act, 1925
      +Rule	GB-Eire	1925	1938	-	Oct	Sun>=2	2:00s	0	GMT
      +Rule	GB-Eire	1927	only	-	Apr	Sun>=9	2:00s	1:00	BST
      +Rule	GB-Eire	1928	1929	-	Apr	Sun>=16	2:00s	1:00	BST
      +Rule	GB-Eire	1930	only	-	Apr	Sun>=9	2:00s	1:00	BST
      +Rule	GB-Eire	1931	1932	-	Apr	Sun>=16	2:00s	1:00	BST
      +Rule	GB-Eire	1933	only	-	Apr	Sun>=9	2:00s	1:00	BST
      +Rule	GB-Eire	1934	only	-	Apr	Sun>=16	2:00s	1:00	BST
      +Rule	GB-Eire	1935	only	-	Apr	Sun>=9	2:00s	1:00	BST
      +Rule	GB-Eire	1936	1937	-	Apr	Sun>=16	2:00s	1:00	BST
      +Rule	GB-Eire	1938	only	-	Apr	Sun>=9	2:00s	1:00	BST
      +Rule	GB-Eire	1939	only	-	Apr	Sun>=16	2:00s	1:00	BST
      +# S.R.&O. 1939, No. 1379
      +Rule	GB-Eire	1939	only	-	Nov	Sun>=16	2:00s	0	GMT
      +# S.R.&O. 1940, No. 172 and No. 1883
      +Rule	GB-Eire	1940	only	-	Feb	Sun>=23	2:00s	1:00	BST
      +# S.R.&O. 1941, No. 476
      +Rule	GB-Eire	1941	only	-	May	Sun>=2	1:00s	2:00	BDST
      +Rule	GB-Eire	1941	1943	-	Aug	Sun>=9	1:00s	1:00	BST
      +# S.R.&O. 1942, No. 506
      +Rule	GB-Eire	1942	1944	-	Apr	Sun>=2	1:00s	2:00	BDST
      +# S.R.&O. 1944, No. 932
      +Rule	GB-Eire	1944	only	-	Sep	Sun>=16	1:00s	1:00	BST
      +# S.R.&O. 1945, No. 312
      +Rule	GB-Eire	1945	only	-	Apr	Mon>=2	1:00s	2:00	BDST
      +Rule	GB-Eire	1945	only	-	Jul	Sun>=9	1:00s	1:00	BST
      +# S.R.&O. 1945, No. 1208
      +Rule	GB-Eire	1945	1946	-	Oct	Sun>=2	2:00s	0	GMT
      +Rule	GB-Eire	1946	only	-	Apr	Sun>=9	2:00s	1:00	BST
      +# The Summer Time Act, 1947
      +Rule	GB-Eire	1947	only	-	Mar	16	2:00s	1:00	BST
      +Rule	GB-Eire	1947	only	-	Apr	13	1:00s	2:00	BDST
      +Rule	GB-Eire	1947	only	-	Aug	10	1:00s	1:00	BST
      +Rule	GB-Eire	1947	only	-	Nov	 2	2:00s	0	GMT
      +# Summer Time Order, 1948 (S.I. 1948/495)
      +Rule	GB-Eire	1948	only	-	Mar	14	2:00s	1:00	BST
      +Rule	GB-Eire	1948	only	-	Oct	31	2:00s	0	GMT
      +# Summer Time Order, 1949 (S.I. 1949/373)
      +Rule	GB-Eire	1949	only	-	Apr	 3	2:00s	1:00	BST
      +Rule	GB-Eire	1949	only	-	Oct	30	2:00s	0	GMT
      +# Summer Time Order, 1950 (S.I. 1950/518)
      +# Summer Time Order, 1951 (S.I. 1951/430)
      +# Summer Time Order, 1952 (S.I. 1952/451)
      +Rule	GB-Eire	1950	1952	-	Apr	Sun>=14	2:00s	1:00	BST
      +Rule	GB-Eire	1950	1952	-	Oct	Sun>=21	2:00s	0	GMT
      +# revert to the rules of the Summer Time Act, 1925
      +Rule	GB-Eire	1953	only	-	Apr	Sun>=16	2:00s	1:00	BST
      +Rule	GB-Eire	1953	1960	-	Oct	Sun>=2	2:00s	0	GMT
      +Rule	GB-Eire	1954	only	-	Apr	Sun>=9	2:00s	1:00	BST
      +Rule	GB-Eire	1955	1956	-	Apr	Sun>=16	2:00s	1:00	BST
      +Rule	GB-Eire	1957	only	-	Apr	Sun>=9	2:00s	1:00	BST
      +Rule	GB-Eire	1958	1959	-	Apr	Sun>=16	2:00s	1:00	BST
      +Rule	GB-Eire	1960	only	-	Apr	Sun>=9	2:00s	1:00	BST
      +# Summer Time Order, 1961 (S.I. 1961/71)
      +# Summer Time (1962) Order, 1961 (S.I. 1961/2465)
      +# Summer Time Order, 1963 (S.I. 1963/81)
      +Rule	GB-Eire	1961	1963	-	Mar	lastSun	2:00s	1:00	BST
      +Rule	GB-Eire	1961	1968	-	Oct	Sun>=23	2:00s	0	GMT
      +# Summer Time (1964) Order, 1963 (S.I. 1963/2101)
      +# Summer Time Order, 1964 (S.I. 1964/1201)
      +# Summer Time Order, 1967 (S.I. 1967/1148)
      +Rule	GB-Eire	1964	1967	-	Mar	Sun>=19	2:00s	1:00	BST
      +# Summer Time Order, 1968 (S.I. 1968/117)
      +Rule	GB-Eire	1968	only	-	Feb	18	2:00s	1:00	BST
      +# The British Standard Time Act, 1968
      +#	(no summer time)
      +# The Summer Time Act, 1972
      +Rule	GB-Eire	1972	1980	-	Mar	Sun>=16	2:00s	1:00	BST
      +Rule	GB-Eire	1972	1980	-	Oct	Sun>=23	2:00s	0	GMT
      +# Summer Time Order, 1980 (S.I. 1980/1089)
      +# Summer Time Order, 1982 (S.I. 1982/1673)
      +# Summer Time Order, 1986 (S.I. 1986/223)
      +# Summer Time Order, 1988 (S.I. 1988/931)
      +Rule	GB-Eire	1981	1995	-	Mar	lastSun	1:00u	1:00	BST
      +Rule	GB-Eire 1981	1989	-	Oct	Sun>=23	1:00u	0	GMT
      +# Summer Time Order, 1989 (S.I. 1989/985)
      +# Summer Time Order, 1992 (S.I. 1992/1729)
      +# Summer Time Order 1994 (S.I. 1994/2798)
      +Rule	GB-Eire 1990	1995	-	Oct	Sun>=22	1:00u	0	GMT
      +# Summer Time Order 1997 (S.I. 1997/2982)
      +# See EU for rules starting in 1996.
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Europe/London	-0:01:15 -	LMT	1847 Dec  1 0:00s
      +			 0:00	GB-Eire	%s	1968 Oct 27
      +			 1:00	-	BST	1971 Oct 31 2:00u
      +			 0:00	GB-Eire	%s	1996
      +			 0:00	EU	GMT/BST
      +Link	Europe/London	Europe/Jersey
      +Link	Europe/London	Europe/Guernsey
      +Link	Europe/London	Europe/Isle_of_Man
      +Zone	Europe/Dublin	-0:25:00 -	LMT	1880 Aug  2
      +			-0:25:21 -	DMT	1916 May 21 2:00
      +			-0:25:21 1:00	IST	1916 Oct  1 2:00s
      +			 0:00	GB-Eire	%s	1921 Dec  6 # independence
      +			 0:00	GB-Eire	GMT/IST	1940 Feb 25 2:00
      +			 0:00	1:00	IST	1946 Oct  6 2:00
      +			 0:00	-	GMT	1947 Mar 16 2:00
      +			 0:00	1:00	IST	1947 Nov  2 2:00
      +			 0:00	-	GMT	1948 Apr 18 2:00
      +			 0:00	GB-Eire	GMT/IST	1968 Oct 27
      +			 1:00	-	IST	1971 Oct 31 2:00u
      +			 0:00	GB-Eire	GMT/IST	1996
      +			 0:00	EU	GMT/IST
      +
      +###############################################################################
      +
      +# Europe
      +
      +# EU rules are for the European Union, previously known as the EC, EEC,
      +# Common Market, etc.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	EU	1977	1980	-	Apr	Sun>=1	 1:00u	1:00	S
      +Rule	EU	1977	only	-	Sep	lastSun	 1:00u	0	-
      +Rule	EU	1978	only	-	Oct	 1	 1:00u	0	-
      +Rule	EU	1979	1995	-	Sep	lastSun	 1:00u	0	-
      +Rule	EU	1981	max	-	Mar	lastSun	 1:00u	1:00	S
      +Rule	EU	1996	max	-	Oct	lastSun	 1:00u	0	-
      +# The most recent directive covers the years starting in 2002.  See:
      +# 
      +# Directive 2000/84/EC of the European Parliament and of the Council
      +# of 19 January 2001 on summer-time arrangements.
      +# 
      +
      +# W-Eur differs from EU only in that W-Eur uses standard time.
      +Rule	W-Eur	1977	1980	-	Apr	Sun>=1	 1:00s	1:00	S
      +Rule	W-Eur	1977	only	-	Sep	lastSun	 1:00s	0	-
      +Rule	W-Eur	1978	only	-	Oct	 1	 1:00s	0	-
      +Rule	W-Eur	1979	1995	-	Sep	lastSun	 1:00s	0	-
      +Rule	W-Eur	1981	max	-	Mar	lastSun	 1:00s	1:00	S
      +Rule	W-Eur	1996	max	-	Oct	lastSun	 1:00s	0	-
      +
      +# Older C-Eur rules are for convenience in the tables.
      +# From 1977 on, C-Eur differs from EU only in that C-Eur uses standard time.
      +Rule	C-Eur	1916	only	-	Apr	30	23:00	1:00	S
      +Rule	C-Eur	1916	only	-	Oct	 1	 1:00	0	-
      +Rule	C-Eur	1917	1918	-	Apr	Mon>=15	 2:00s	1:00	S
      +Rule	C-Eur	1917	1918	-	Sep	Mon>=15	 2:00s	0	-
      +Rule	C-Eur	1940	only	-	Apr	 1	 2:00s	1:00	S
      +Rule	C-Eur	1942	only	-	Nov	 2	 2:00s	0	-
      +Rule	C-Eur	1943	only	-	Mar	29	 2:00s	1:00	S
      +Rule	C-Eur	1943	only	-	Oct	 4	 2:00s	0	-
      +Rule	C-Eur	1944	1945	-	Apr	Mon>=1	 2:00s	1:00	S
      +# Whitman gives 1944 Oct 7; go with Shanks & Pottenger.
      +Rule	C-Eur	1944	only	-	Oct	 2	 2:00s	0	-
      +# From Jesper Norgaard Welen (2008-07-13):
      +#
      +# I found what is probably a typo of 2:00 which should perhaps be 2:00s
      +# in the C-Eur rule from tz database version 2008d (this part was
      +# corrected in version 2008d). The circumstancial evidence is simply the
      +# tz database itself, as seen below:
      +#
      +# Zone Europe/Paris 0:09:21 - LMT 1891 Mar 15  0:01
      +#    0:00 France WE%sT 1945 Sep 16  3:00
      +#
      +# Zone Europe/Monaco 0:29:32 - LMT 1891 Mar 15
      +#    0:00 France WE%sT 1945 Sep 16 3:00
      +#
      +# Zone Europe/Belgrade 1:22:00 - LMT 1884
      +#    1:00 1:00 CEST 1945 Sep 16  2:00s
      +#
      +# Rule France 1945 only - Sep 16  3:00 0 -
      +# Rule Belgium 1945 only - Sep 16  2:00s 0 -
      +# Rule Neth 1945 only - Sep 16 2:00s 0 -
      +#
      +# The rule line to be changed is:
      +#
      +# Rule C-Eur 1945 only - Sep 16  2:00 0 -
      +#
      +# It seems that Paris, Monaco, Rule France, Rule Belgium all agree on
      +# 2:00 standard time, e.g. 3:00 local time.  However there are no
      +# countries that use C-Eur rules in September 1945, so the only items
      +# affected are apparently these ficticious zones that translates acronyms
      +# CET and MET:
      +#
      +# Zone CET  1:00 C-Eur CE%sT
      +# Zone MET  1:00 C-Eur ME%sT
      +#
      +# It this is right then the corrected version would look like:
      +#
      +# Rule C-Eur 1945 only - Sep 16  2:00s 0 -
      +#
      +# A small step for mankind though 8-)
      +Rule	C-Eur	1945	only	-	Sep	16	 2:00s	0	-
      +Rule	C-Eur	1977	1980	-	Apr	Sun>=1	 2:00s	1:00	S
      +Rule	C-Eur	1977	only	-	Sep	lastSun	 2:00s	0	-
      +Rule	C-Eur	1978	only	-	Oct	 1	 2:00s	0	-
      +Rule	C-Eur	1979	1995	-	Sep	lastSun	 2:00s	0	-
      +Rule	C-Eur	1981	max	-	Mar	lastSun	 2:00s	1:00	S
      +Rule	C-Eur	1996	max	-	Oct	lastSun	 2:00s	0	-
      +
      +# E-Eur differs from EU only in that E-Eur switches at midnight local time.
      +Rule	E-Eur	1977	1980	-	Apr	Sun>=1	 0:00	1:00	S
      +Rule	E-Eur	1977	only	-	Sep	lastSun	 0:00	0	-
      +Rule	E-Eur	1978	only	-	Oct	 1	 0:00	0	-
      +Rule	E-Eur	1979	1995	-	Sep	lastSun	 0:00	0	-
      +Rule	E-Eur	1981	max	-	Mar	lastSun	 0:00	1:00	S
      +Rule	E-Eur	1996	max	-	Oct	lastSun	 0:00	0	-
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Russia	1917	only	-	Jul	 1	23:00	1:00	MST	# Moscow Summer Time
      +Rule	Russia	1917	only	-	Dec	28	 0:00	0	MMT	# Moscow Mean Time
      +Rule	Russia	1918	only	-	May	31	22:00	2:00	MDST	# Moscow Double Summer Time
      +Rule	Russia	1918	only	-	Sep	16	 1:00	1:00	MST
      +Rule	Russia	1919	only	-	May	31	23:00	2:00	MDST
      +Rule	Russia	1919	only	-	Jul	 1	 2:00	1:00	S
      +Rule	Russia	1919	only	-	Aug	16	 0:00	0	-
      +Rule	Russia	1921	only	-	Feb	14	23:00	1:00	S
      +Rule	Russia	1921	only	-	Mar	20	23:00	2:00	M # Midsummer
      +Rule	Russia	1921	only	-	Sep	 1	 0:00	1:00	S
      +Rule	Russia	1921	only	-	Oct	 1	 0:00	0	-
      +# Act No.925 of the Council of Ministers of the USSR (1980-10-24):
      +Rule	Russia	1981	1984	-	Apr	 1	 0:00	1:00	S
      +Rule	Russia	1981	1983	-	Oct	 1	 0:00	0	-
      +# Act No.967 of the Council of Ministers of the USSR (1984-09-13), repeated in
      +# Act No.227 of the Council of Ministers of the USSR (1989-03-14):
      +Rule	Russia	1984	1991	-	Sep	lastSun	 2:00s	0	-
      +Rule	Russia	1985	1991	-	Mar	lastSun	 2:00s	1:00	S
      +#
      +Rule	Russia	1992	only	-	Mar	lastSat	 23:00	1:00	S
      +Rule	Russia	1992	only	-	Sep	lastSat	 23:00	0	-
      +Rule	Russia	1993	2010	-	Mar	lastSun	 2:00s	1:00	S
      +Rule	Russia	1993	1995	-	Sep	lastSun	 2:00s	0	-
      +Rule	Russia	1996	2010	-	Oct	lastSun	 2:00s	0	-
      +
      +# From Alexander Krivenyshev (2011-06-14):
      +# According to Kremlin press service, Russian President Dmitry Medvedev
      +# signed a federal law "On calculation of time" on June 9, 2011.
      +# According to the law Russia is abolishing daylight saving time.
      +#
      +# Medvedev signed a law "On the Calculation of Time" (in russian):
      +# 
      +# http://bmockbe.ru/events/?ID=7583
      +# 
      +#
      +# Medvedev signed a law on the calculation of the time (in russian):
      +# 
      +# http://www.regnum.ru/news/polit/1413906.html
      +# 
      +
      +# From Arthur David Olson (2011-06-15):
      +# Take "abolishing daylight saving time" to mean that time is now considered
      +# to be standard.
      +
      +# These are for backward compatibility with older versions.
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	WET		0:00	EU	WE%sT
      +Zone	CET		1:00	C-Eur	CE%sT
      +Zone	MET		1:00	C-Eur	ME%sT
      +Zone	EET		2:00	EU	EE%sT
      +
      +# Previous editions of this database used abbreviations like MET DST
      +# for Central European Summer Time, but this didn't agree with common usage.
      +
      +# From Markus Kuhn (1996-07-12):
      +# The official German names ... are
      +#
      +#	Mitteleuropaeische Zeit (MEZ)         = UTC+01:00
      +#	Mitteleuropaeische Sommerzeit (MESZ)  = UTC+02:00
      +#
      +# as defined in the German Time Act (Gesetz ueber die Zeitbestimmung (ZeitG),
      +# 1978-07-25, Bundesgesetzblatt, Jahrgang 1978, Teil I, S. 1110-1111)....
      +# I wrote ... to the German Federal Physical-Technical Institution
      +#
      +#	Physikalisch-Technische Bundesanstalt (PTB)
      +#	Laboratorium 4.41 "Zeiteinheit"
      +#	Postfach 3345
      +#	D-38023 Braunschweig
      +#	phone: +49 531 592-0
      +#
      +# ... I received today an answer letter from Dr. Peter Hetzel, head of the PTB
      +# department for time and frequency transmission.  He explained that the
      +# PTB translates MEZ and MESZ into English as
      +#
      +#	Central European Time (CET)         = UTC+01:00
      +#	Central European Summer Time (CEST) = UTC+02:00
      +
      +
      +# Albania
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Albania	1940	only	-	Jun	16	0:00	1:00	S
      +Rule	Albania	1942	only	-	Nov	 2	3:00	0	-
      +Rule	Albania	1943	only	-	Mar	29	2:00	1:00	S
      +Rule	Albania	1943	only	-	Apr	10	3:00	0	-
      +Rule	Albania	1974	only	-	May	 4	0:00	1:00	S
      +Rule	Albania	1974	only	-	Oct	 2	0:00	0	-
      +Rule	Albania	1975	only	-	May	 1	0:00	1:00	S
      +Rule	Albania	1975	only	-	Oct	 2	0:00	0	-
      +Rule	Albania	1976	only	-	May	 2	0:00	1:00	S
      +Rule	Albania	1976	only	-	Oct	 3	0:00	0	-
      +Rule	Albania	1977	only	-	May	 8	0:00	1:00	S
      +Rule	Albania	1977	only	-	Oct	 2	0:00	0	-
      +Rule	Albania	1978	only	-	May	 6	0:00	1:00	S
      +Rule	Albania	1978	only	-	Oct	 1	0:00	0	-
      +Rule	Albania	1979	only	-	May	 5	0:00	1:00	S
      +Rule	Albania	1979	only	-	Sep	30	0:00	0	-
      +Rule	Albania	1980	only	-	May	 3	0:00	1:00	S
      +Rule	Albania	1980	only	-	Oct	 4	0:00	0	-
      +Rule	Albania	1981	only	-	Apr	26	0:00	1:00	S
      +Rule	Albania	1981	only	-	Sep	27	0:00	0	-
      +Rule	Albania	1982	only	-	May	 2	0:00	1:00	S
      +Rule	Albania	1982	only	-	Oct	 3	0:00	0	-
      +Rule	Albania	1983	only	-	Apr	18	0:00	1:00	S
      +Rule	Albania	1983	only	-	Oct	 1	0:00	0	-
      +Rule	Albania	1984	only	-	Apr	 1	0:00	1:00	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Europe/Tirane	1:19:20 -	LMT	1914
      +			1:00	-	CET	1940 Jun 16
      +			1:00	Albania	CE%sT	1984 Jul
      +			1:00	EU	CE%sT
      +
      +# Andorra
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Europe/Andorra	0:06:04 -	LMT	1901
      +			0:00	-	WET	1946 Sep 30
      +			1:00	-	CET	1985 Mar 31 2:00
      +			1:00	EU	CE%sT
      +
      +# Austria
      +
      +# From Paul Eggert (2006-03-22): Shanks & Pottenger give 1918-06-16 and
      +# 1945-11-18, but the Austrian Federal Office of Metrology and
      +# Surveying (BEV) gives 1918-09-16 and for Vienna gives the "alleged"
      +# date of 1945-04-12 with no time.  For the 1980-04-06 transition
      +# Shanks & Pottenger give 02:00, the BEV 00:00.  Go with the BEV,
      +# and guess 02:00 for 1945-04-12.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Austria	1920	only	-	Apr	 5	2:00s	1:00	S
      +Rule	Austria	1920	only	-	Sep	13	2:00s	0	-
      +Rule	Austria	1946	only	-	Apr	14	2:00s	1:00	S
      +Rule	Austria	1946	1948	-	Oct	Sun>=1	2:00s	0	-
      +Rule	Austria	1947	only	-	Apr	 6	2:00s	1:00	S
      +Rule	Austria	1948	only	-	Apr	18	2:00s	1:00	S
      +Rule	Austria	1980	only	-	Apr	 6	0:00	1:00	S
      +Rule	Austria	1980	only	-	Sep	28	0:00	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Europe/Vienna	1:05:20 -	LMT	1893 Apr
      +			1:00	C-Eur	CE%sT	1920
      +			1:00	Austria	CE%sT	1940 Apr  1 2:00s
      +			1:00	C-Eur	CE%sT	1945 Apr  2 2:00s
      +			1:00	1:00	CEST	1945 Apr 12 2:00s
      +			1:00	-	CET	1946
      +			1:00	Austria	CE%sT	1981
      +			1:00	EU	CE%sT
      +
      +# Belarus
      +# From Yauhen Kharuzhy (2011-09-16):
      +# By latest Belarus government act Europe/Minsk timezone was changed to
      +# GMT+3 without DST (was GMT+2 with DST).
      +#
      +# Sources (Russian language):
      +# 1.
      +# 
      +# http://www.belta.by/ru/all_news/society/V-Belarusi-otmenjaetsja-perexod-na-sezonnoe-vremja_i_572952.html
      +# 
      +# 2.
      +# 
      +# http://naviny.by/rubrics/society/2011/09/16/ic_articles_116_175144/
      +# 
      +# 3.
      +# 
      +# http://news.tut.by/society/250578.html
      +# 
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Europe/Minsk	1:50:16 -	LMT	1880
      +			1:50	-	MMT	1924 May 2 # Minsk Mean Time
      +			2:00	-	EET	1930 Jun 21
      +			3:00	-	MSK	1941 Jun 28
      +			1:00	C-Eur	CE%sT	1944 Jul  3
      +			3:00	Russia	MSK/MSD	1990
      +			3:00	-	MSK	1991 Mar 31 2:00s
      +			2:00	1:00	EEST	1991 Sep 29 2:00s
      +			2:00	-	EET	1992 Mar 29 0:00s
      +			2:00	1:00	EEST	1992 Sep 27 0:00s
      +			2:00	Russia	EE%sT	2011 Mar 27 2:00s
      +			3:00	-	FET # Further-eastern European Time
      +
      +# Belgium
      +#
      +# From Paul Eggert (1997-07-02):
      +# Entries from 1918 through 1991 are taken from:
      +#	Annuaire de L'Observatoire Royal de Belgique,
      +#	Avenue Circulaire, 3, B-1180 BRUXELLES, CLVIIe annee, 1991
      +#	(Imprimerie HAYEZ, s.p.r.l., Rue Fin, 4, 1080 BRUXELLES, MCMXC),
      +#	pp 8-9.
      +# LMT before 1892 was 0:17:30, according to the official journal of Belgium:
      +#	Moniteur Belge, Samedi 30 Avril 1892, N.121.
      +# Thanks to Pascal Delmoitie for these references.
      +# The 1918 rules are listed for completeness; they apply to unoccupied Belgium.
      +# Assume Brussels switched to WET in 1918 when the armistice took effect.
      +#
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Belgium	1918	only	-	Mar	 9	 0:00s	1:00	S
      +Rule	Belgium	1918	1919	-	Oct	Sat>=1	23:00s	0	-
      +Rule	Belgium	1919	only	-	Mar	 1	23:00s	1:00	S
      +Rule	Belgium	1920	only	-	Feb	14	23:00s	1:00	S
      +Rule	Belgium	1920	only	-	Oct	23	23:00s	0	-
      +Rule	Belgium	1921	only	-	Mar	14	23:00s	1:00	S
      +Rule	Belgium	1921	only	-	Oct	25	23:00s	0	-
      +Rule	Belgium	1922	only	-	Mar	25	23:00s	1:00	S
      +Rule	Belgium	1922	1927	-	Oct	Sat>=1	23:00s	0	-
      +Rule	Belgium	1923	only	-	Apr	21	23:00s	1:00	S
      +Rule	Belgium	1924	only	-	Mar	29	23:00s	1:00	S
      +Rule	Belgium	1925	only	-	Apr	 4	23:00s	1:00	S
      +# DSH writes that a royal decree of 1926-02-22 specified the Sun following 3rd
      +# Sat in Apr (except if it's Easter, in which case it's one Sunday earlier),
      +# to Sun following 1st Sat in Oct, and that a royal decree of 1928-09-15
      +# changed the transition times to 02:00 GMT.
      +Rule	Belgium	1926	only	-	Apr	17	23:00s	1:00	S
      +Rule	Belgium	1927	only	-	Apr	 9	23:00s	1:00	S
      +Rule	Belgium	1928	only	-	Apr	14	23:00s	1:00	S
      +Rule	Belgium	1928	1938	-	Oct	Sun>=2	 2:00s	0	-
      +Rule	Belgium	1929	only	-	Apr	21	 2:00s	1:00	S
      +Rule	Belgium	1930	only	-	Apr	13	 2:00s	1:00	S
      +Rule	Belgium	1931	only	-	Apr	19	 2:00s	1:00	S
      +Rule	Belgium	1932	only	-	Apr	 3	 2:00s	1:00	S
      +Rule	Belgium	1933	only	-	Mar	26	 2:00s	1:00	S
      +Rule	Belgium	1934	only	-	Apr	 8	 2:00s	1:00	S
      +Rule	Belgium	1935	only	-	Mar	31	 2:00s	1:00	S
      +Rule	Belgium	1936	only	-	Apr	19	 2:00s	1:00	S
      +Rule	Belgium	1937	only	-	Apr	 4	 2:00s	1:00	S
      +Rule	Belgium	1938	only	-	Mar	27	 2:00s	1:00	S
      +Rule	Belgium	1939	only	-	Apr	16	 2:00s	1:00	S
      +Rule	Belgium	1939	only	-	Nov	19	 2:00s	0	-
      +Rule	Belgium	1940	only	-	Feb	25	 2:00s	1:00	S
      +Rule	Belgium	1944	only	-	Sep	17	 2:00s	0	-
      +Rule	Belgium	1945	only	-	Apr	 2	 2:00s	1:00	S
      +Rule	Belgium	1945	only	-	Sep	16	 2:00s	0	-
      +Rule	Belgium	1946	only	-	May	19	 2:00s	1:00	S
      +Rule	Belgium	1946	only	-	Oct	 7	 2:00s	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Europe/Brussels	0:17:30 -	LMT	1880
      +			0:17:30	-	BMT	1892 May  1 12:00 # Brussels MT
      +			0:00	-	WET	1914 Nov  8
      +			1:00	-	CET	1916 May  1  0:00
      +			1:00	C-Eur	CE%sT	1918 Nov 11 11:00u
      +			0:00	Belgium	WE%sT	1940 May 20  2:00s
      +			1:00	C-Eur	CE%sT	1944 Sep  3
      +			1:00	Belgium	CE%sT	1977
      +			1:00	EU	CE%sT
      +
      +# Bosnia and Herzegovina
      +# see Serbia
      +
      +# Bulgaria
      +#
      +# From Plamen Simenov via Steffen Thorsen (1999-09-09):
      +# A document of Government of Bulgaria (No.94/1997) says:
      +# EET --> EETDST is in 03:00 Local time in last Sunday of March ...
      +# EETDST --> EET is in 04:00 Local time in last Sunday of October
      +#
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Bulg	1979	only	-	Mar	31	23:00	1:00	S
      +Rule	Bulg	1979	only	-	Oct	 1	 1:00	0	-
      +Rule	Bulg	1980	1982	-	Apr	Sat>=1	23:00	1:00	S
      +Rule	Bulg	1980	only	-	Sep	29	 1:00	0	-
      +Rule	Bulg	1981	only	-	Sep	27	 2:00	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Europe/Sofia	1:33:16 -	LMT	1880
      +			1:56:56	-	IMT	1894 Nov 30 # Istanbul MT?
      +			2:00	-	EET	1942 Nov  2  3:00
      +			1:00	C-Eur	CE%sT	1945
      +			1:00	-	CET	1945 Apr 2 3:00
      +			2:00	-	EET	1979 Mar 31 23:00
      +			2:00	Bulg	EE%sT	1982 Sep 26  2:00
      +			2:00	C-Eur	EE%sT	1991
      +			2:00	E-Eur	EE%sT	1997
      +			2:00	EU	EE%sT
      +
      +# Croatia
      +# see Serbia
      +
      +# Cyprus
      +# Please see the `asia' file for Asia/Nicosia.
      +
      +# Czech Republic
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Czech	1945	only	-	Apr	 8	2:00s	1:00	S
      +Rule	Czech	1945	only	-	Nov	18	2:00s	0	-
      +Rule	Czech	1946	only	-	May	 6	2:00s	1:00	S
      +Rule	Czech	1946	1949	-	Oct	Sun>=1	2:00s	0	-
      +Rule	Czech	1947	only	-	Apr	20	2:00s	1:00	S
      +Rule	Czech	1948	only	-	Apr	18	2:00s	1:00	S
      +Rule	Czech	1949	only	-	Apr	 9	2:00s	1:00	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Europe/Prague	0:57:44 -	LMT	1850
      +			0:57:44	-	PMT	1891 Oct     # Prague Mean Time
      +			1:00	C-Eur	CE%sT	1944 Sep 17 2:00s
      +			1:00	Czech	CE%sT	1979
      +			1:00	EU	CE%sT
      +
      +# Denmark, Faroe Islands, and Greenland
      +
      +# From Jesper Norgaard Welen (2005-04-26):
      +# http://www.hum.aau.dk/~poe/tid/tine/DanskTid.htm says that the law
      +# [introducing standard time] was in effect from 1894-01-01....
      +# The page http://www.retsinfo.dk/_GETDOCI_/ACCN/A18930008330-REGL
      +# confirms this, and states that the law was put forth 1893-03-29.
      +#
      +# The EU treaty with effect from 1973:
      +# http://www.retsinfo.dk/_GETDOCI_/ACCN/A19722110030-REGL
      +#
      +# This provoked a new law from 1974 to make possible summer time changes
      +# in subsequenet decrees with the law
      +# http://www.retsinfo.dk/_GETDOCI_/ACCN/A19740022330-REGL
      +#
      +# It seems however that no decree was set forward until 1980.  I have
      +# not found any decree, but in another related law, the effecting DST
      +# changes are stated explicitly to be from 1980-04-06 at 02:00 to
      +# 1980-09-28 at 02:00.  If this is true, this differs slightly from
      +# the EU rule in that DST runs to 02:00, not 03:00.  We don't know
      +# when Denmark began using the EU rule correctly, but we have only
      +# confirmation of the 1980-time, so I presume it was correct in 1981:
      +# The law is about the management of the extra hour, concerning
      +# working hours reported and effect on obligatory-rest rules (which
      +# was suspended on that night):
      +# http://www.retsinfo.dk/_GETDOCI_/ACCN/C19801120554-REGL
      +
      +# From Jesper Norgaard Welen (2005-06-11):
      +# The Herning Folkeblad (1980-09-26) reported that the night between
      +# Saturday and Sunday the clock is set back from three to two.
      +
      +# From Paul Eggert (2005-06-11):
      +# Hence the "02:00" of the 1980 law refers to standard time, not
      +# wall-clock time, and so the EU rules were in effect in 1980.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Denmark	1916	only	-	May	14	23:00	1:00	S
      +Rule	Denmark	1916	only	-	Sep	30	23:00	0	-
      +Rule	Denmark	1940	only	-	May	15	 0:00	1:00	S
      +Rule	Denmark	1945	only	-	Apr	 2	 2:00s	1:00	S
      +Rule	Denmark	1945	only	-	Aug	15	 2:00s	0	-
      +Rule	Denmark	1946	only	-	May	 1	 2:00s	1:00	S
      +Rule	Denmark	1946	only	-	Sep	 1	 2:00s	0	-
      +Rule	Denmark	1947	only	-	May	 4	 2:00s	1:00	S
      +Rule	Denmark	1947	only	-	Aug	10	 2:00s	0	-
      +Rule	Denmark	1948	only	-	May	 9	 2:00s	1:00	S
      +Rule	Denmark	1948	only	-	Aug	 8	 2:00s	0	-
      +#
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Europe/Copenhagen	 0:50:20 -	LMT	1890
      +			 0:50:20 -	CMT	1894 Jan  1 # Copenhagen MT
      +			 1:00	Denmark	CE%sT	1942 Nov  2 2:00s
      +			 1:00	C-Eur	CE%sT	1945 Apr  2 2:00
      +			 1:00	Denmark	CE%sT	1980
      +			 1:00	EU	CE%sT
      +Zone Atlantic/Faroe	-0:27:04 -	LMT	1908 Jan 11	# Torshavn
      +			 0:00	-	WET	1981
      +			 0:00	EU	WE%sT
      +#
      +# From Paul Eggert (2004-10-31):
      +# During World War II, Germany maintained secret manned weather stations in
      +# East Greenland and Franz Josef Land, but we don't know their time zones.
      +# My source for this is Wilhelm Dege's book mentioned under Svalbard.
      +#
      +# From Paul Eggert (2006-03-22):
      +# Greenland joined the EU as part of Denmark, obtained home rule on 1979-05-01,
      +# and left the EU on 1985-02-01.  It therefore should have been using EU
      +# rules at least through 1984.  Shanks & Pottenger say Scoresbysund and Godthab
      +# used C-Eur rules after 1980, but IATA SSIM (1991/1996) says they use EU
      +# rules since at least 1991.  Assume EU rules since 1980.
      +
      +# From Gwillin Law (2001-06-06), citing
      +#  (2001-03-15),
      +# and with translations corrected by Steffen Thorsen:
      +#
      +# Greenland has four local times, and the relation to UTC
      +# is according to the following time line:
      +#
      +# The military zone near Thule	UTC-4
      +# Standard Greenland time	UTC-3
      +# Scoresbysund			UTC-1
      +# Danmarkshavn			UTC
      +#
      +# In the military area near Thule and in Danmarkshavn DST will not be
      +# introduced.
      +
      +# From Rives McDow (2001-11-01):
      +#
      +# I correspond regularly with the Dansk Polarcenter, and wrote them at
      +# the time to clarify the situation in Thule.  Unfortunately, I have
      +# not heard back from them regarding my recent letter.  [But I have
      +# info from earlier correspondence.]
      +#
      +# According to the center, a very small local time zone around Thule
      +# Air Base keeps the time according to UTC-4, implementing daylight
      +# savings using North America rules, changing the time at 02:00 local time....
      +#
      +# The east coast of Greenland north of the community of Scoresbysund
      +# uses UTC in the same way as in Iceland, year round, with no dst.
      +# There are just a few stations on this coast, including the
      +# Danmarkshavn ICAO weather station mentioned in your September 29th
      +# email.  The other stations are two sledge patrol stations in
      +# Mestersvig and Daneborg, the air force base at Station Nord, and the
      +# DPC research station at Zackenberg.
      +#
      +# Scoresbysund and two small villages nearby keep time UTC-1 and use
      +# the same daylight savings time period as in West Greenland (Godthab).
      +#
      +# The rest of Greenland, including Godthab (this area, although it
      +# includes central Greenland, is known as west Greenland), keeps time
      +# UTC-3, with daylight savings methods according to European rules.
      +#
      +# It is common procedure to use UTC 0 in the wilderness of East and
      +# North Greenland, because it is mainly Icelandic aircraft operators
      +# maintaining traffic in these areas.  However, the official status of
      +# this area is that it sticks with Godthab time.  This area might be
      +# considered a dual time zone in some respects because of this.
      +
      +# From Rives McDow (2001-11-19):
      +# I heard back from someone stationed at Thule; the time change took place
      +# there at 2:00 AM.
      +
      +# From Paul Eggert (2006-03-22):
      +# From 1997 on the CIA map shows Danmarkshavn on GMT;
      +# the 1995 map as like Godthab.
      +# For lack of better info, assume they were like Godthab before 1996.
      +# startkart.no says Thule does not observe DST, but this is clearly an error,
      +# so go with Shanks & Pottenger for Thule transitions until this year.
      +# For 2007 on assume Thule will stay in sync with US DST rules.
      +#
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Thule	1991	1992	-	Mar	lastSun	2:00	1:00	D
      +Rule	Thule	1991	1992	-	Sep	lastSun	2:00	0	S
      +Rule	Thule	1993	2006	-	Apr	Sun>=1	2:00	1:00	D
      +Rule	Thule	1993	2006	-	Oct	lastSun	2:00	0	S
      +Rule	Thule	2007	max	-	Mar	Sun>=8	2:00	1:00	D
      +Rule	Thule	2007	max	-	Nov	Sun>=1	2:00	0	S
      +#
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Danmarkshavn -1:14:40 -	LMT	1916 Jul 28
      +			-3:00	-	WGT	1980 Apr  6 2:00
      +			-3:00	EU	WG%sT	1996
      +			0:00	-	GMT
      +Zone America/Scoresbysund -1:27:52 -	LMT	1916 Jul 28 # Ittoqqortoormiit
      +			-2:00	-	CGT	1980 Apr  6 2:00
      +			-2:00	C-Eur	CG%sT	1981 Mar 29
      +			-1:00	EU	EG%sT
      +Zone America/Godthab	-3:26:56 -	LMT	1916 Jul 28 # Nuuk
      +			-3:00	-	WGT	1980 Apr  6 2:00
      +			-3:00	EU	WG%sT
      +Zone America/Thule	-4:35:08 -	LMT	1916 Jul 28 # Pituffik air base
      +			-4:00	Thule	A%sT
      +
      +# Estonia
      +# From Peter Ilieve (1994-10-15):
      +# A relative in Tallinn confirms the accuracy of the data for 1989 onwards
      +# [through 1994] and gives the legal authority for it,
      +# a regulation of the Government of Estonia, No. 111 of 1989....
      +#
      +# From Peter Ilieve (1996-10-28):
      +# [IATA SSIM (1992/1996) claims that the Baltic republics switch at 01:00s,
      +# but a relative confirms that Estonia still switches at 02:00s, writing:]
      +# ``I do not [know] exactly but there are some little different
      +# (confusing) rules for International Air and Railway Transport Schedules
      +# conversion in Sunday connected with end of summer time in Estonia....
      +# A discussion is running about the summer time efficiency and effect on
      +# human physiology.  It seems that Estonia maybe will not change to
      +# summer time next spring.''
      +
      +# From Peter Ilieve (1998-11-04), heavily edited:
      +# 
      +# The 1998-09-22 Estonian time law
      +# 
      +# refers to the Eighth Directive and cites the association agreement between
      +# the EU and Estonia, ratified by the Estonian law (RT II 1995, 22--27, 120).
      +#
      +# I also asked [my relative] whether they use any standard abbreviation
      +# for their standard and summer times. He says no, they use "suveaeg"
      +# (summer time) and "talveaeg" (winter time).
      +
      +# From The Baltic Times (1999-09-09)
      +# via Steffen Thorsen:
      +# This year will mark the last time Estonia shifts to summer time,
      +# a council of the ruling coalition announced Sept. 6....
      +# But what this could mean for Estonia's chances of joining the European
      +# Union are still unclear.  In 1994, the EU declared summer time compulsory
      +# for all member states until 2001.  Brussels has yet to decide what to do
      +# after that.
      +
      +# From Mart Oruaas (2000-01-29):
      +# Regulation no. 301 (1999-10-12) obsoletes previous regulation
      +# no. 206 (1998-09-22) and thus sticks Estonia to +02:00 GMT for all
      +# the year round.  The regulation is effective 1999-11-01.
      +
      +# From Toomas Soome (2002-02-21):
      +# The Estonian government has changed once again timezone politics.
      +# Now we are using again EU rules.
      +#
      +# From Urmet Jaanes (2002-03-28):
      +# The legislative reference is Government decree No. 84 on 2002-02-21.
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Europe/Tallinn	1:39:00	-	LMT	1880
      +			1:39:00	-	TMT	1918 Feb # Tallinn Mean Time
      +			1:00	C-Eur	CE%sT	1919 Jul
      +			1:39:00	-	TMT	1921 May
      +			2:00	-	EET	1940 Aug  6
      +			3:00	-	MSK	1941 Sep 15
      +			1:00	C-Eur	CE%sT	1944 Sep 22
      +			3:00	Russia	MSK/MSD	1989 Mar 26 2:00s
      +			2:00	1:00	EEST	1989 Sep 24 2:00s
      +			2:00	C-Eur	EE%sT	1998 Sep 22
      +			2:00	EU	EE%sT	1999 Nov  1
      +			2:00	-	EET	2002 Feb 21
      +			2:00	EU	EE%sT
      +
      +# Finland
      +
      +# From Hannu Strang (1994-09-25 06:03:37 UTC):
      +# Well, here in Helsinki we're just changing from summer time to regular one,
      +# and it's supposed to change at 4am...
      +
      +# From Janne Snabb (2010-0715):
      +#
      +# I noticed that the Finland data is not accurate for years 1981 and 1982.
      +# During these two first trial years the DST adjustment was made one hour
      +# earlier than in forthcoming years. Starting 1983 the adjustment was made
      +# according to the central European standards.
      +#
      +# This is documented in Heikki Oja: Aikakirja 2007, published by The Almanac
      +# Office of University of Helsinki, ISBN 952-10-3221-9, available online (in
      +# Finnish) at
      +#
      +# 
      +# http://almanakka.helsinki.fi/aikakirja/Aikakirja2007kokonaan.pdf
      +# 
      +#
      +# Page 105 (56 in PDF version) has a handy table of all past daylight savings
      +# transitions. It is easy enough to interpret without Finnish skills.
      +#
      +# This is also confirmed by Finnish Broadcasting Company's archive at:
      +#
      +# 
      +# http://www.yle.fi/elavaarkisto/?s=s&g=1&ag=5&t=&a=3401
      +# 
      +#
      +# The news clip from 1981 says that "the time between 2 and 3 o'clock does not
      +# exist tonight."
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Finland	1942	only	-	Apr	3	0:00	1:00	S
      +Rule	Finland	1942	only	-	Oct	3	0:00	0	-
      +Rule	Finland	1981	1982	-	Mar	lastSun	2:00	1:00	S
      +Rule	Finland	1981	1982	-	Sep	lastSun	3:00	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Europe/Helsinki	1:39:52 -	LMT	1878 May 31
      +			1:39:52	-	HMT	1921 May    # Helsinki Mean Time
      +			2:00	Finland	EE%sT	1983
      +			2:00	EU	EE%sT
      +
      +# Aaland Is
      +Link	Europe/Helsinki	Europe/Mariehamn
      +
      +
      +# France
      +
      +# From Ciro Discepolo (2000-12-20):
      +#
      +# Henri Le Corre, Regimes Horaires pour le monde entier, Editions
      +# Traditionnelles - Paris 2 books, 1993
      +#
      +# Gabriel, Traite de l'heure dans le monde, Guy Tredaniel editeur,
      +# Paris, 1991
      +#
      +# Francoise Gauquelin, Problemes de l'heure resolus en astrologie,
      +# Guy tredaniel, Paris 1987
      +
      +
      +#
      +# Shank & Pottenger seem to use `24:00' ambiguously; resolve it with Whitman.
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	France	1916	only	-	Jun	14	23:00s	1:00	S
      +Rule	France	1916	1919	-	Oct	Sun>=1	23:00s	0	-
      +Rule	France	1917	only	-	Mar	24	23:00s	1:00	S
      +Rule	France	1918	only	-	Mar	 9	23:00s	1:00	S
      +Rule	France	1919	only	-	Mar	 1	23:00s	1:00	S
      +Rule	France	1920	only	-	Feb	14	23:00s	1:00	S
      +Rule	France	1920	only	-	Oct	23	23:00s	0	-
      +Rule	France	1921	only	-	Mar	14	23:00s	1:00	S
      +Rule	France	1921	only	-	Oct	25	23:00s	0	-
      +Rule	France	1922	only	-	Mar	25	23:00s	1:00	S
      +# DSH writes that a law of 1923-05-24 specified 3rd Sat in Apr at 23:00 to 1st
      +# Sat in Oct at 24:00; and that in 1930, because of Easter, the transitions
      +# were Apr 12 and Oct 5.  Go with Shanks & Pottenger.
      +Rule	France	1922	1938	-	Oct	Sat>=1	23:00s	0	-
      +Rule	France	1923	only	-	May	26	23:00s	1:00	S
      +Rule	France	1924	only	-	Mar	29	23:00s	1:00	S
      +Rule	France	1925	only	-	Apr	 4	23:00s	1:00	S
      +Rule	France	1926	only	-	Apr	17	23:00s	1:00	S
      +Rule	France	1927	only	-	Apr	 9	23:00s	1:00	S
      +Rule	France	1928	only	-	Apr	14	23:00s	1:00	S
      +Rule	France	1929	only	-	Apr	20	23:00s	1:00	S
      +Rule	France	1930	only	-	Apr	12	23:00s	1:00	S
      +Rule	France	1931	only	-	Apr	18	23:00s	1:00	S
      +Rule	France	1932	only	-	Apr	 2	23:00s	1:00	S
      +Rule	France	1933	only	-	Mar	25	23:00s	1:00	S
      +Rule	France	1934	only	-	Apr	 7	23:00s	1:00	S
      +Rule	France	1935	only	-	Mar	30	23:00s	1:00	S
      +Rule	France	1936	only	-	Apr	18	23:00s	1:00	S
      +Rule	France	1937	only	-	Apr	 3	23:00s	1:00	S
      +Rule	France	1938	only	-	Mar	26	23:00s	1:00	S
      +Rule	France	1939	only	-	Apr	15	23:00s	1:00	S
      +Rule	France	1939	only	-	Nov	18	23:00s	0	-
      +Rule	France	1940	only	-	Feb	25	 2:00	1:00	S
      +# The French rules for 1941-1944 were not used in Paris, but Shanks & Pottenger
      +# write that they were used in Monaco and in many French locations.
      +# Le Corre writes that the upper limit of the free zone was Arneguy, Orthez,
      +# Mont-de-Marsan, Bazas, Langon, Lamotte-Montravel, Marouil, La
      +# Rochefoucault, Champagne-Mouton, La Roche-Posay, La Haye-Descartes,
      +# Loches, Montrichard, Vierzon, Bourges, Moulins, Digoin,
      +# Paray-le-Monial, Montceau-les-Mines, Chalons-sur-Saone, Arbois,
      +# Dole, Morez, St-Claude, and Collonges (Haute-Savoie).
      +Rule	France	1941	only	-	May	 5	 0:00	2:00	M # Midsummer
      +# Shanks & Pottenger say this transition occurred at Oct 6 1:00,
      +# but go with Denis Excoffier (1997-12-12),
      +# who quotes the Ephemerides Astronomiques for 1998 from Bureau des Longitudes
      +# as saying 5/10/41 22hUT.
      +Rule	France	1941	only	-	Oct	 6	 0:00	1:00	S
      +Rule	France	1942	only	-	Mar	 9	 0:00	2:00	M
      +Rule	France	1942	only	-	Nov	 2	 3:00	1:00	S
      +Rule	France	1943	only	-	Mar	29	 2:00	2:00	M
      +Rule	France	1943	only	-	Oct	 4	 3:00	1:00	S
      +Rule	France	1944	only	-	Apr	 3	 2:00	2:00	M
      +Rule	France	1944	only	-	Oct	 8	 1:00	1:00	S
      +Rule	France	1945	only	-	Apr	 2	 2:00	2:00	M
      +Rule	France	1945	only	-	Sep	16	 3:00	0	-
      +# Shanks & Pottenger give Mar 28 2:00 and Sep 26 3:00;
      +# go with Excoffier's 28/3/76 0hUT and 25/9/76 23hUT.
      +Rule	France	1976	only	-	Mar	28	 1:00	1:00	S
      +Rule	France	1976	only	-	Sep	26	 1:00	0	-
      +# Shanks & Pottenger give 0:09:20 for Paris Mean Time, and Whitman 0:09:05,
      +# but Howse quotes the actual French legislation as saying 0:09:21.
      +# Go with Howse.  Howse writes that the time in France was officially based
      +# on PMT-0:09:21 until 1978-08-09, when the time base finally switched to UTC.
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Europe/Paris	0:09:21 -	LMT	1891 Mar 15  0:01
      +			0:09:21	-	PMT	1911 Mar 11  0:01  # Paris MT
      +# Shanks & Pottenger give 1940 Jun 14 0:00; go with Excoffier and Le Corre.
      +			0:00	France	WE%sT	1940 Jun 14 23:00
      +# Le Corre says Paris stuck with occupied-France time after the liberation;
      +# go with Shanks & Pottenger.
      +			1:00	C-Eur	CE%sT	1944 Aug 25
      +			0:00	France	WE%sT	1945 Sep 16  3:00
      +			1:00	France	CE%sT	1977
      +			1:00	EU	CE%sT
      +
      +# Germany
      +
      +# From Markus Kuhn (1998-09-29):
      +# The German time zone web site by the Physikalisch-Technische
      +# Bundesanstalt contains DST information back to 1916.
      +# [See tz-link.htm for the URL.]
      +
      +# From Joerg Schilling (2002-10-23):
      +# In 1945, Berlin was switched to Moscow Summer time (GMT+4) by
      +# 
      +# General [Nikolai] Bersarin.
      +
      +# From Paul Eggert (2003-03-08):
      +# 
      +# http://www.parlament-berlin.de/pds-fraktion.nsf/727459127c8b66ee8525662300459099/defc77cb784f180ac1256c2b0030274b/$FILE/bersarint.pdf
      +# 
      +# says that Bersarin issued an order to use Moscow time on May 20.
      +# However, Moscow did not observe daylight saving in 1945, so
      +# this was equivalent to CEMT (GMT+3), not GMT+4.
      +
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Germany	1946	only	-	Apr	14	2:00s	1:00	S
      +Rule	Germany	1946	only	-	Oct	 7	2:00s	0	-
      +Rule	Germany	1947	1949	-	Oct	Sun>=1	2:00s	0	-
      +# http://www.ptb.de/de/org/4/44/441/salt.htm says the following transition
      +# occurred at 3:00 MEZ, not the 2:00 MEZ given in Shanks & Pottenger.
      +# Go with the PTB.
      +Rule	Germany	1947	only	-	Apr	 6	3:00s	1:00	S
      +Rule	Germany	1947	only	-	May	11	2:00s	2:00	M
      +Rule	Germany	1947	only	-	Jun	29	3:00	1:00	S
      +Rule	Germany	1948	only	-	Apr	18	2:00s	1:00	S
      +Rule	Germany	1949	only	-	Apr	10	2:00s	1:00	S
      +
      +Rule SovietZone	1945	only	-	May	24	2:00	2:00	M # Midsummer
      +Rule SovietZone	1945	only	-	Sep	24	3:00	1:00	S
      +Rule SovietZone	1945	only	-	Nov	18	2:00s	0	-
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Europe/Berlin	0:53:28 -	LMT	1893 Apr
      +			1:00	C-Eur	CE%sT	1945 May 24 2:00
      +			1:00 SovietZone	CE%sT	1946
      +			1:00	Germany	CE%sT	1980
      +			1:00	EU	CE%sT
      +
      +# Georgia
      +# Please see the "asia" file for Asia/Tbilisi.
      +# Herodotus (Histories, IV.45) says Georgia north of the Phasis (now Rioni)
      +# is in Europe.  Our reference location Tbilisi is in the Asian part.
      +
      +# Gibraltar
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Europe/Gibraltar	-0:21:24 -	LMT	1880 Aug  2 0:00s
      +			0:00	GB-Eire	%s	1957 Apr 14 2:00
      +			1:00	-	CET	1982
      +			1:00	EU	CE%sT
      +
      +# Greece
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +# Whitman gives 1932 Jul 5 - Nov 1; go with Shanks & Pottenger.
      +Rule	Greece	1932	only	-	Jul	 7	0:00	1:00	S
      +Rule	Greece	1932	only	-	Sep	 1	0:00	0	-
      +# Whitman gives 1941 Apr 25 - ?; go with Shanks & Pottenger.
      +Rule	Greece	1941	only	-	Apr	 7	0:00	1:00	S
      +# Whitman gives 1942 Feb 2 - ?; go with Shanks & Pottenger.
      +Rule	Greece	1942	only	-	Nov	 2	3:00	0	-
      +Rule	Greece	1943	only	-	Mar	30	0:00	1:00	S
      +Rule	Greece	1943	only	-	Oct	 4	0:00	0	-
      +# Whitman gives 1944 Oct 3 - Oct 31; go with Shanks & Pottenger.
      +Rule	Greece	1952	only	-	Jul	 1	0:00	1:00	S
      +Rule	Greece	1952	only	-	Nov	 2	0:00	0	-
      +Rule	Greece	1975	only	-	Apr	12	0:00s	1:00	S
      +Rule	Greece	1975	only	-	Nov	26	0:00s	0	-
      +Rule	Greece	1976	only	-	Apr	11	2:00s	1:00	S
      +Rule	Greece	1976	only	-	Oct	10	2:00s	0	-
      +Rule	Greece	1977	1978	-	Apr	Sun>=1	2:00s	1:00	S
      +Rule	Greece	1977	only	-	Sep	26	2:00s	0	-
      +Rule	Greece	1978	only	-	Sep	24	4:00	0	-
      +Rule	Greece	1979	only	-	Apr	 1	9:00	1:00	S
      +Rule	Greece	1979	only	-	Sep	29	2:00	0	-
      +Rule	Greece	1980	only	-	Apr	 1	0:00	1:00	S
      +Rule	Greece	1980	only	-	Sep	28	0:00	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Europe/Athens	1:34:52 -	LMT	1895 Sep 14
      +			1:34:52	-	AMT	1916 Jul 28 0:01     # Athens MT
      +			2:00	Greece	EE%sT	1941 Apr 30
      +			1:00	Greece	CE%sT	1944 Apr  4
      +			2:00	Greece	EE%sT	1981
      +			# Shanks & Pottenger say it switched to C-Eur in 1981;
      +			# go with EU instead, since Greece joined it on Jan 1.
      +			2:00	EU	EE%sT
      +
      +# Hungary
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Hungary	1918	only	-	Apr	 1	 3:00	1:00	S
      +Rule	Hungary	1918	only	-	Sep	29	 3:00	0	-
      +Rule	Hungary	1919	only	-	Apr	15	 3:00	1:00	S
      +Rule	Hungary	1919	only	-	Sep	15	 3:00	0	-
      +Rule	Hungary	1920	only	-	Apr	 5	 3:00	1:00	S
      +Rule	Hungary	1920	only	-	Sep	30	 3:00	0	-
      +Rule	Hungary	1945	only	-	May	 1	23:00	1:00	S
      +Rule	Hungary	1945	only	-	Nov	 3	 0:00	0	-
      +Rule	Hungary	1946	only	-	Mar	31	 2:00s	1:00	S
      +Rule	Hungary	1946	1949	-	Oct	Sun>=1	 2:00s	0	-
      +Rule	Hungary	1947	1949	-	Apr	Sun>=4	 2:00s	1:00	S
      +Rule	Hungary	1950	only	-	Apr	17	 2:00s	1:00	S
      +Rule	Hungary	1950	only	-	Oct	23	 2:00s	0	-
      +Rule	Hungary	1954	1955	-	May	23	 0:00	1:00	S
      +Rule	Hungary	1954	1955	-	Oct	 3	 0:00	0	-
      +Rule	Hungary	1956	only	-	Jun	Sun>=1	 0:00	1:00	S
      +Rule	Hungary	1956	only	-	Sep	lastSun	 0:00	0	-
      +Rule	Hungary	1957	only	-	Jun	Sun>=1	 1:00	1:00	S
      +Rule	Hungary	1957	only	-	Sep	lastSun	 3:00	0	-
      +Rule	Hungary	1980	only	-	Apr	 6	 1:00	1:00	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Europe/Budapest	1:16:20 -	LMT	1890 Oct
      +			1:00	C-Eur	CE%sT	1918
      +			1:00	Hungary	CE%sT	1941 Apr  6  2:00
      +			1:00	C-Eur	CE%sT	1945
      +			1:00	Hungary	CE%sT	1980 Sep 28  2:00s
      +			1:00	EU	CE%sT
      +
      +# Iceland
      +#
      +# From Adam David (1993-11-06):
      +# The name of the timezone in Iceland for system / mail / news purposes is GMT.
      +#
      +# (1993-12-05):
      +# This material is paraphrased from the 1988 edition of the University of
      +# Iceland Almanak.
      +#
      +# From January 1st, 1908 the whole of Iceland was standardised at 1 hour
      +# behind GMT. Previously, local mean solar time was used in different parts
      +# of Iceland, the almanak had been based on Reykjavik mean solar time which
      +# was 1 hour and 28 minutes behind GMT.
      +#
      +# "first day of winter" referred to [below] means the first day of the 26 weeks
      +# of winter, according to the old icelandic calendar that dates back to the
      +# time the norsemen first settled Iceland.  The first day of winter is always
      +# Saturday, but is not dependent on the Julian or Gregorian calendars.
      +#
      +# (1993-12-10):
      +# I have a reference from the Oxford Icelandic-English dictionary for the
      +# beginning of winter, which ties it to the ecclesiastical calendar (and thus
      +# to the julian/gregorian calendar) over the period in question.
      +#	the winter begins on the Saturday next before St. Luke's day
      +#	(old style), or on St. Luke's day, if a Saturday.
      +# St. Luke's day ought to be traceable from ecclesiastical sources. "old style"
      +# might be a reference to the Julian calendar as opposed to Gregorian, or it
      +# might mean something else (???).
      +#
      +# From Paul Eggert (2006-03-22):
      +# The Iceland Almanak, Shanks & Pottenger, and Whitman disagree on many points.
      +# We go with the Almanak, except for one claim from Shanks & Pottenger, namely
      +# that Reykavik was 21W57 from 1837 to 1908, local mean time before that.
      +#
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Iceland	1917	1918	-	Feb	19	23:00	1:00	S
      +Rule	Iceland	1917	only	-	Oct	21	 1:00	0	-
      +Rule	Iceland	1918	only	-	Nov	16	 1:00	0	-
      +Rule	Iceland	1939	only	-	Apr	29	23:00	1:00	S
      +Rule	Iceland	1939	only	-	Nov	29	 2:00	0	-
      +Rule	Iceland	1940	only	-	Feb	25	 2:00	1:00	S
      +Rule	Iceland	1940	only	-	Nov	 3	 2:00	0	-
      +Rule	Iceland	1941	only	-	Mar	 2	 1:00s	1:00	S
      +Rule	Iceland	1941	only	-	Nov	 2	 1:00s	0	-
      +Rule	Iceland	1942	only	-	Mar	 8	 1:00s	1:00	S
      +Rule	Iceland	1942	only	-	Oct	25	 1:00s	0	-
      +# 1943-1946 - first Sunday in March until first Sunday in winter
      +Rule	Iceland	1943	1946	-	Mar	Sun>=1	 1:00s	1:00	S
      +Rule	Iceland	1943	1948	-	Oct	Sun>=22	 1:00s	0	-
      +# 1947-1967 - first Sunday in April until first Sunday in winter
      +Rule	Iceland	1947	1967	-	Apr	Sun>=1	 1:00s	1:00	S
      +# 1949 Oct transition delayed by 1 week
      +Rule	Iceland	1949	only	-	Oct	30	 1:00s	0	-
      +Rule	Iceland	1950	1966	-	Oct	Sun>=22	 1:00s	0	-
      +Rule	Iceland	1967	only	-	Oct	29	 1:00s	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Atlantic/Reykjavik	-1:27:24 -	LMT	1837
      +			-1:27:48 -	RMT	1908 # Reykjavik Mean Time?
      +			-1:00	Iceland	IS%sT	1968 Apr 7 1:00s
      +			 0:00	-	GMT
      +
      +# Italy
      +#
      +# From Paul Eggert (2001-03-06):
      +# Sicily and Sardinia each had their own time zones from 1866 to 1893,
      +# called Palermo Time (+00:53:28) and Cagliari Time (+00:36:32).
      +# During World War II, German-controlled Italy used German time.
      +# But these events all occurred before the 1970 cutoff,
      +# so record only the time in Rome.
      +#
      +# From Paul Eggert (2006-03-22):
      +# For Italian DST we have three sources: Shanks & Pottenger, Whitman, and
      +# F. Pollastri
      +# 
      +# Day-light Saving Time in Italy (2006-02-03)
      +# 
      +# (`FP' below), taken from an Italian National Electrotechnical Institute
      +# publication. When the three sources disagree, guess who's right, as follows:
      +#
      +# year	FP	Shanks&P. (S)	Whitman (W)	Go with:
      +# 1916	06-03	06-03 24:00	06-03 00:00	FP & W
      +#	09-30	09-30 24:00	09-30 01:00	FP; guess 24:00s
      +# 1917	04-01	03-31 24:00	03-31 00:00	FP & S
      +#	09-30	09-29 24:00	09-30 01:00	FP & W
      +# 1918	03-09	03-09 24:00	03-09 00:00	FP & S
      +#	10-06	10-05 24:00	10-06 01:00	FP & W
      +# 1919	03-01	03-01 24:00	03-01 00:00	FP & S
      +#	10-04	10-04 24:00	10-04 01:00	FP; guess 24:00s
      +# 1920	03-20	03-20 24:00	03-20 00:00	FP & S
      +#	09-18	09-18 24:00	10-01 01:00	FP; guess 24:00s
      +# 1944	04-02	04-03 02:00			S (see C-Eur)
      +#	09-16	10-02 03:00			FP; guess 24:00s
      +# 1945	09-14	09-16 24:00			FP; guess 24:00s
      +# 1970	05-21	05-31 00:00			S
      +#	09-20	09-27 00:00			S
      +#
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Italy	1916	only	-	Jun	 3	0:00s	1:00	S
      +Rule	Italy	1916	only	-	Oct	 1	0:00s	0	-
      +Rule	Italy	1917	only	-	Apr	 1	0:00s	1:00	S
      +Rule	Italy	1917	only	-	Sep	30	0:00s	0	-
      +Rule	Italy	1918	only	-	Mar	10	0:00s	1:00	S
      +Rule	Italy	1918	1919	-	Oct	Sun>=1	0:00s	0	-
      +Rule	Italy	1919	only	-	Mar	 2	0:00s	1:00	S
      +Rule	Italy	1920	only	-	Mar	21	0:00s	1:00	S
      +Rule	Italy	1920	only	-	Sep	19	0:00s	0	-
      +Rule	Italy	1940	only	-	Jun	15	0:00s	1:00	S
      +Rule	Italy	1944	only	-	Sep	17	0:00s	0	-
      +Rule	Italy	1945	only	-	Apr	 2	2:00	1:00	S
      +Rule	Italy	1945	only	-	Sep	15	0:00s	0	-
      +Rule	Italy	1946	only	-	Mar	17	2:00s	1:00	S
      +Rule	Italy	1946	only	-	Oct	 6	2:00s	0	-
      +Rule	Italy	1947	only	-	Mar	16	0:00s	1:00	S
      +Rule	Italy	1947	only	-	Oct	 5	0:00s	0	-
      +Rule	Italy	1948	only	-	Feb	29	2:00s	1:00	S
      +Rule	Italy	1948	only	-	Oct	 3	2:00s	0	-
      +Rule	Italy	1966	1968	-	May	Sun>=22	0:00	1:00	S
      +Rule	Italy	1966	1969	-	Sep	Sun>=22	0:00	0	-
      +Rule	Italy	1969	only	-	Jun	 1	0:00	1:00	S
      +Rule	Italy	1970	only	-	May	31	0:00	1:00	S
      +Rule	Italy	1970	only	-	Sep	lastSun	0:00	0	-
      +Rule	Italy	1971	1972	-	May	Sun>=22	0:00	1:00	S
      +Rule	Italy	1971	only	-	Sep	lastSun	1:00	0	-
      +Rule	Italy	1972	only	-	Oct	 1	0:00	0	-
      +Rule	Italy	1973	only	-	Jun	 3	0:00	1:00	S
      +Rule	Italy	1973	1974	-	Sep	lastSun	0:00	0	-
      +Rule	Italy	1974	only	-	May	26	0:00	1:00	S
      +Rule	Italy	1975	only	-	Jun	 1	0:00s	1:00	S
      +Rule	Italy	1975	1977	-	Sep	lastSun	0:00s	0	-
      +Rule	Italy	1976	only	-	May	30	0:00s	1:00	S
      +Rule	Italy	1977	1979	-	May	Sun>=22	0:00s	1:00	S
      +Rule	Italy	1978	only	-	Oct	 1	0:00s	0	-
      +Rule	Italy	1979	only	-	Sep	30	0:00s	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Europe/Rome	0:49:56 -	LMT	1866 Sep 22
      +			0:49:56	-	RMT	1893 Nov  1 0:00s # Rome Mean
      +			1:00	Italy	CE%sT	1942 Nov  2 2:00s
      +			1:00	C-Eur	CE%sT	1944 Jul
      +			1:00	Italy	CE%sT	1980
      +			1:00	EU	CE%sT
      +
      +Link	Europe/Rome	Europe/Vatican
      +Link	Europe/Rome	Europe/San_Marino
      +
      +# Latvia
      +
      +# From Liene Kanepe (1998-09-17):
      +
      +# I asked about this matter Scientific Secretary of the Institute of Astronomy
      +# of The University of Latvia Dr. paed Mr. Ilgonis Vilks. I also searched the
      +# correct data in juridical acts and I found some juridical documents about
      +# changes in the counting of time in Latvia from 1981....
      +#
      +# Act No.35 of the Council of Ministers of Latvian SSR of 1981-01-22 ...
      +# according to the Act No.925 of the Council of Ministers of USSR of 1980-10-24
      +# ...: all year round the time of 2nd time zone + 1 hour, in addition turning
      +# the hands of the clock 1 hour forward on 1 April at 00:00 (GMT 31 March 21:00)
      +# and 1 hour backward on the 1 October at 00:00 (GMT 30 September 20:00).
      +#
      +# Act No.592 of the Council of Ministers of Latvian SSR of 1984-09-24 ...
      +# according to the Act No.967 of the Council of Ministers of USSR of 1984-09-13
      +# ...: all year round the time of 2nd time zone + 1 hour, in addition turning
      +# the hands of the clock 1 hour forward on the last Sunday of March at 02:00
      +# (GMT 23:00 on the previous day) and 1 hour backward on the last Sunday of
      +# September at 03:00 (GMT 23:00 on the previous day).
      +#
      +# Act No.81 of the Council of Ministers of Latvian SSR of 1989-03-22 ...
      +# according to the Act No.227 of the Council of Ministers of USSR of 1989-03-14
      +# ...: since the last Sunday of March 1989 in Lithuanian SSR, Latvian SSR,
      +# Estonian SSR and Kaliningrad region of Russian Federation all year round the
      +# time of 2nd time zone (Moscow time minus one hour). On the territory of Latvia
      +# transition to summer time is performed on the last Sunday of March at 02:00
      +# (GMT 00:00), turning the hands of the clock 1 hour forward.  The end of
      +# daylight saving time is performed on the last Sunday of September at 03:00
      +# (GMT 00:00), turning the hands of the clock 1 hour backward. Exception is
      +# 1989-03-26, when we must not turn the hands of the clock....
      +#
      +# The Regulations of the Cabinet of Ministers of the Republic of Latvia of
      +# 1997-01-21 on transition to Summer time ... established the same order of
      +# daylight savings time settings as in the States of the European Union.
      +
      +# From Andrei Ivanov (2000-03-06):
      +# This year Latvia will not switch to Daylight Savings Time (as specified in
      +# 
      +# The Regulations of the Cabinet of Ministers of the Rep. of Latvia of
      +# 29-Feb-2000 (#79), in Latvian for subscribers only).
      +
      +# 
      +# From RFE/RL Newsline (2001-01-03), noted after a heads-up by Rives McDow:
      +# 
      +# The Latvian government on 2 January decided that the country will
      +# institute daylight-saving time this spring, LETA reported.
      +# Last February the three Baltic states decided not to turn back their
      +# clocks one hour in the spring....
      +# Minister of Economy Aigars Kalvitis noted that Latvia had too few
      +# daylight hours and thus decided to comply with a draft European
      +# Commission directive that provides for instituting daylight-saving
      +# time in EU countries between 2002 and 2006. The Latvian government
      +# urged Lithuania and Estonia to adopt a similar time policy, but it
      +# appears that they will not do so....
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Latvia	1989	1996	-	Mar	lastSun	 2:00s	1:00	S
      +Rule	Latvia	1989	1996	-	Sep	lastSun	 2:00s	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Europe/Riga	1:36:24	-	LMT	1880
      +			1:36:24	-	RMT	1918 Apr 15 2:00 #Riga Mean Time
      +			1:36:24	1:00	LST	1918 Sep 16 3:00 #Latvian Summer
      +			1:36:24	-	RMT	1919 Apr  1 2:00
      +			1:36:24	1:00	LST	1919 May 22 3:00
      +			1:36:24	-	RMT	1926 May 11
      +			2:00	-	EET	1940 Aug  5
      +			3:00	-	MSK	1941 Jul
      +			1:00	C-Eur	CE%sT	1944 Oct 13
      +			3:00	Russia	MSK/MSD	1989 Mar lastSun 2:00s
      +			2:00	1:00	EEST	1989 Sep lastSun 2:00s
      +			2:00	Latvia	EE%sT	1997 Jan 21
      +			2:00	EU	EE%sT	2000 Feb 29
      +			2:00	-	EET	2001 Jan  2
      +			2:00	EU	EE%sT
      +
      +# Liechtenstein
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Europe/Vaduz	0:38:04 -	LMT	1894 Jun
      +			1:00	-	CET	1981
      +			1:00	EU	CE%sT
      +
      +# Lithuania
      +
      +# From Paul Eggert (1996-11-22):
      +# IATA SSIM (1992/1996) says Lithuania uses W-Eur rules, but since it is
      +# known to be wrong about Estonia and Latvia, assume it's wrong here too.
      +
      +# From Marius Gedminas (1998-08-07):
      +# I would like to inform that in this year Lithuanian time zone
      +# (Europe/Vilnius) was changed.
      +
      +# From ELTA No. 972 (2582) (1999-09-29),
      +# via Steffen Thorsen:
      +# Lithuania has shifted back to the second time zone (GMT plus two hours)
      +# to be valid here starting from October 31,
      +# as decided by the national government on Wednesday....
      +# The Lithuanian government also announced plans to consider a
      +# motion to give up shifting to summer time in spring, as it was
      +# already done by Estonia.
      +
      +# From the 
      +# Fact File, Lithuanian State Department of Tourism
      +#  (2000-03-27): Local time is GMT+2 hours ..., no daylight saving.
      +
      +# From a user via Klaus Marten (2003-02-07):
      +# As a candidate for membership of the European Union, Lithuania will
      +# observe Summer Time in 2003, changing its clocks at the times laid
      +# down in EU Directive 2000/84 of 19.I.01 (i.e. at the same times as its
      +# neighbour Latvia). The text of the Lithuanian government Order of
      +# 7.XI.02 to this effect can be found at
      +# http://www.lrvk.lt/nut/11/n1749.htm
      +
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Europe/Vilnius	1:41:16	-	LMT	1880
      +			1:24:00	-	WMT	1917	    # Warsaw Mean Time
      +			1:35:36	-	KMT	1919 Oct 10 # Kaunas Mean Time
      +			1:00	-	CET	1920 Jul 12
      +			2:00	-	EET	1920 Oct  9
      +			1:00	-	CET	1940 Aug  3
      +			3:00	-	MSK	1941 Jun 24
      +			1:00	C-Eur	CE%sT	1944 Aug
      +			3:00	Russia	MSK/MSD	1991 Mar 31 2:00s
      +			2:00	1:00	EEST	1991 Sep 29 2:00s
      +			2:00	C-Eur	EE%sT	1998
      +			2:00	-	EET	1998 Mar 29 1:00u
      +			1:00	EU	CE%sT	1999 Oct 31 1:00u
      +			2:00	-	EET	2003 Jan  1
      +			2:00	EU	EE%sT
      +
      +# Luxembourg
      +# Whitman disagrees with most of these dates in minor ways;
      +# go with Shanks & Pottenger.
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Lux	1916	only	-	May	14	23:00	1:00	S
      +Rule	Lux	1916	only	-	Oct	 1	 1:00	0	-
      +Rule	Lux	1917	only	-	Apr	28	23:00	1:00	S
      +Rule	Lux	1917	only	-	Sep	17	 1:00	0	-
      +Rule	Lux	1918	only	-	Apr	Mon>=15	 2:00s	1:00	S
      +Rule	Lux	1918	only	-	Sep	Mon>=15	 2:00s	0	-
      +Rule	Lux	1919	only	-	Mar	 1	23:00	1:00	S
      +Rule	Lux	1919	only	-	Oct	 5	 3:00	0	-
      +Rule	Lux	1920	only	-	Feb	14	23:00	1:00	S
      +Rule	Lux	1920	only	-	Oct	24	 2:00	0	-
      +Rule	Lux	1921	only	-	Mar	14	23:00	1:00	S
      +Rule	Lux	1921	only	-	Oct	26	 2:00	0	-
      +Rule	Lux	1922	only	-	Mar	25	23:00	1:00	S
      +Rule	Lux	1922	only	-	Oct	Sun>=2	 1:00	0	-
      +Rule	Lux	1923	only	-	Apr	21	23:00	1:00	S
      +Rule	Lux	1923	only	-	Oct	Sun>=2	 2:00	0	-
      +Rule	Lux	1924	only	-	Mar	29	23:00	1:00	S
      +Rule	Lux	1924	1928	-	Oct	Sun>=2	 1:00	0	-
      +Rule	Lux	1925	only	-	Apr	 5	23:00	1:00	S
      +Rule	Lux	1926	only	-	Apr	17	23:00	1:00	S
      +Rule	Lux	1927	only	-	Apr	 9	23:00	1:00	S
      +Rule	Lux	1928	only	-	Apr	14	23:00	1:00	S
      +Rule	Lux	1929	only	-	Apr	20	23:00	1:00	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Europe/Luxembourg	0:24:36 -	LMT	1904 Jun
      +			1:00	Lux	CE%sT	1918 Nov 25
      +			0:00	Lux	WE%sT	1929 Oct  6 2:00s
      +			0:00	Belgium	WE%sT	1940 May 14 3:00
      +			1:00	C-Eur	WE%sT	1944 Sep 18 3:00
      +			1:00	Belgium	CE%sT	1977
      +			1:00	EU	CE%sT
      +
      +# Macedonia
      +# see Serbia
      +
      +# Malta
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Malta	1973	only	-	Mar	31	0:00s	1:00	S
      +Rule	Malta	1973	only	-	Sep	29	0:00s	0	-
      +Rule	Malta	1974	only	-	Apr	21	0:00s	1:00	S
      +Rule	Malta	1974	only	-	Sep	16	0:00s	0	-
      +Rule	Malta	1975	1979	-	Apr	Sun>=15	2:00	1:00	S
      +Rule	Malta	1975	1980	-	Sep	Sun>=15	2:00	0	-
      +Rule	Malta	1980	only	-	Mar	31	2:00	1:00	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Europe/Malta	0:58:04 -	LMT	1893 Nov  2 0:00s # Valletta
      +			1:00	Italy	CE%sT	1942 Nov  2 2:00s
      +			1:00	C-Eur	CE%sT	1945 Apr  2 2:00s
      +			1:00	Italy	CE%sT	1973 Mar 31
      +			1:00	Malta	CE%sT	1981
      +			1:00	EU	CE%sT
      +
      +# Moldova
      +
      +# From Paul Eggert (2006-03-22):
      +# A previous version of this database followed Shanks & Pottenger, who write
      +# that Tiraspol switched to Moscow time on 1992-01-19 at 02:00.
      +# However, this is most likely an error, as Moldova declared independence
      +# on 1991-08-27 (the 1992-01-19 date is that of a Russian decree).
      +# In early 1992 there was large-scale interethnic violence in the area
      +# and it's possible that some Russophones continued to observe Moscow time.
      +# But [two people] separately reported via
      +# Jesper Norgaard that as of 2001-01-24 Tiraspol was like Chisinau.
      +# The Tiraspol entry has therefore been removed for now.
      +#
      +# From Alexander Krivenyshev (2011-10-17):
      +# Pridnestrovian Moldavian Republic (PMR, also known as
      +# "Pridnestrovie") has abolished seasonal clock change (no transition
      +# to the Winter Time).
      +#
      +# News (in Russian):
      +# 
      +# http://www.kyivpost.ua/russia/news/pridnestrove-otkazalos-ot-perehoda-na-zimnee-vremya-30954.html
      +# 
      +#
      +# 
      +# http://www.allmoldova.com/moldova-news/1249064116.html
      +# 
      +#
      +# The substance of this change (reinstatement of the Tiraspol entry)
      +# is from a patch from Petr Machata (2011-10-17)
      +#
      +# From Tim Parenti (2011-10-19)
      +# In addition, being situated at +4651+2938 would give Tiraspol
      +# a pre-1880 LMT offset of 1:58:32.
      +#
      +# (which agrees with the earlier entry that had been removed)
      +#
      +# From Alexander Krivenyshev (2011-10-26)
      +# NO need to divide Moldova into two timezones at this point.
      +# As of today, Transnistria (Pridnestrovie)- Tiraspol reversed its own
      +# decision to abolish DST this winter.
      +# Following Moldova and neighboring Ukraine- Transnistria (Pridnestrovie)-
      +# Tiraspol will go back to winter time on October 30, 2011.
      +# News from Moldova (in russian):
      +# 
      +# http://ru.publika.md/link_317061.html
      +# 
      +
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Europe/Chisinau	1:55:20 -	LMT	1880
      +			1:55	-	CMT	1918 Feb 15 # Chisinau MT
      +			1:44:24	-	BMT	1931 Jul 24 # Bucharest MT
      +			2:00	Romania	EE%sT	1940 Aug 15
      +			2:00	1:00	EEST	1941 Jul 17
      +			1:00	C-Eur	CE%sT	1944 Aug 24
      +			3:00	Russia	MSK/MSD	1990
      +			3:00	-	MSK	1990 May 6
      +			2:00	-	EET	1991
      +			2:00	Russia	EE%sT	1992
      +			2:00	E-Eur	EE%sT	1997
      +# See Romania commentary for the guessed 1997 transition to EU rules.
      +			2:00	EU	EE%sT
      +
      +# Monaco
      +# Shanks & Pottenger give 0:09:20 for Paris Mean Time; go with Howse's
      +# more precise 0:09:21.
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Europe/Monaco	0:29:32 -	LMT	1891 Mar 15
      +			0:09:21	-	PMT	1911 Mar 11    # Paris Mean Time
      +			0:00	France	WE%sT	1945 Sep 16 3:00
      +			1:00	France	CE%sT	1977
      +			1:00	EU	CE%sT
      +
      +# Montenegro
      +# see Serbia
      +
      +# Netherlands
      +
      +# Howse writes that the Netherlands' railways used GMT between 1892 and 1940,
      +# but for other purposes the Netherlands used Amsterdam mean time.
      +
      +# However, Robert H. van Gent writes (2001-04-01):
      +# Howse's statement is only correct up to 1909. From 1909-05-01 (00:00:00
      +# Amsterdam mean time) onwards, the whole of the Netherlands (including
      +# the Dutch railways) was required by law to observe Amsterdam mean time
      +# (19 minutes 32.13 seconds ahead of GMT). This had already been the
      +# common practice (except for the railways) for many decades but it was
      +# not until 1909 when the Dutch government finally defined this by law.
      +# On 1937-07-01 this was changed to 20 minutes (exactly) ahead of GMT and
      +# was generally known as Dutch Time ("Nederlandse Tijd").
      +#
      +# (2001-04-08):
      +# 1892-05-01 was the date when the Dutch railways were by law required to
      +# observe GMT while the remainder of the Netherlands adhered to the common
      +# practice of following Amsterdam mean time.
      +#
      +# (2001-04-09):
      +# In 1835 the authorities of the province of North Holland requested the
      +# municipal authorities of the towns and cities in the province to observe
      +# Amsterdam mean time but I do not know in how many cases this request was
      +# actually followed.
      +#
      +# From 1852 onwards the Dutch telegraph offices were by law required to
      +# observe Amsterdam mean time. As the time signals from the observatory of
      +# Leiden were also distributed by the telegraph system, I assume that most
      +# places linked up with the telegraph (and railway) system automatically
      +# adopted Amsterdam mean time.
      +#
      +# Although the early Dutch railway companies initially observed a variety
      +# of times, most of them had adopted Amsterdam mean time by 1858 but it
      +# was not until 1866 when they were all required by law to observe
      +# Amsterdam mean time.
      +
      +# The data before 1945 are taken from
      +# .
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Neth	1916	only	-	May	 1	0:00	1:00	NST	# Netherlands Summer Time
      +Rule	Neth	1916	only	-	Oct	 1	0:00	0	AMT	# Amsterdam Mean Time
      +Rule	Neth	1917	only	-	Apr	16	2:00s	1:00	NST
      +Rule	Neth	1917	only	-	Sep	17	2:00s	0	AMT
      +Rule	Neth	1918	1921	-	Apr	Mon>=1	2:00s	1:00	NST
      +Rule	Neth	1918	1921	-	Sep	lastMon	2:00s	0	AMT
      +Rule	Neth	1922	only	-	Mar	lastSun	2:00s	1:00	NST
      +Rule	Neth	1922	1936	-	Oct	Sun>=2	2:00s	0	AMT
      +Rule	Neth	1923	only	-	Jun	Fri>=1	2:00s	1:00	NST
      +Rule	Neth	1924	only	-	Mar	lastSun	2:00s	1:00	NST
      +Rule	Neth	1925	only	-	Jun	Fri>=1	2:00s	1:00	NST
      +# From 1926 through 1939 DST began 05-15, except that it was delayed by a week
      +# in years when 05-15 fell in the Pentecost weekend.
      +Rule	Neth	1926	1931	-	May	15	2:00s	1:00	NST
      +Rule	Neth	1932	only	-	May	22	2:00s	1:00	NST
      +Rule	Neth	1933	1936	-	May	15	2:00s	1:00	NST
      +Rule	Neth	1937	only	-	May	22	2:00s	1:00	NST
      +Rule	Neth	1937	only	-	Jul	 1	0:00	1:00	S
      +Rule	Neth	1937	1939	-	Oct	Sun>=2	2:00s	0	-
      +Rule	Neth	1938	1939	-	May	15	2:00s	1:00	S
      +Rule	Neth	1945	only	-	Apr	 2	2:00s	1:00	S
      +Rule	Neth	1945	only	-	Sep	16	2:00s	0	-
      +#
      +# Amsterdam Mean Time was +00:19:32.13 exactly, but the .13 is omitted
      +# below because the current format requires GMTOFF to be an integer.
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Europe/Amsterdam	0:19:32 -	LMT	1835
      +			0:19:32	Neth	%s	1937 Jul  1
      +			0:20	Neth	NE%sT	1940 May 16 0:00 # Dutch Time
      +			1:00	C-Eur	CE%sT	1945 Apr  2 2:00
      +			1:00	Neth	CE%sT	1977
      +			1:00	EU	CE%sT
      +
      +# Norway
      +# http://met.no/met/met_lex/q_u/sommertid.html (2004-01) agrees with Shanks &
      +# Pottenger.
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Norway	1916	only	-	May	22	1:00	1:00	S
      +Rule	Norway	1916	only	-	Sep	30	0:00	0	-
      +Rule	Norway	1945	only	-	Apr	 2	2:00s	1:00	S
      +Rule	Norway	1945	only	-	Oct	 1	2:00s	0	-
      +Rule	Norway	1959	1964	-	Mar	Sun>=15	2:00s	1:00	S
      +Rule	Norway	1959	1965	-	Sep	Sun>=15	2:00s	0	-
      +Rule	Norway	1965	only	-	Apr	25	2:00s	1:00	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Europe/Oslo	0:43:00 -	LMT	1895 Jan  1
      +			1:00	Norway	CE%sT	1940 Aug 10 23:00
      +			1:00	C-Eur	CE%sT	1945 Apr  2  2:00
      +			1:00	Norway	CE%sT	1980
      +			1:00	EU	CE%sT
      +
      +# Svalbard & Jan Mayen
      +
      +# From Steffen Thorsen (2001-05-01):
      +# Although I could not find it explicitly, it seems that Jan Mayen and
      +# Svalbard have been using the same time as Norway at least since the
      +# time they were declared as parts of Norway.  Svalbard was declared
      +# as a part of Norway by law of 1925-07-17 no 11, section 4 and Jan
      +# Mayen by law of 1930-02-27 no 2, section 2. (From
      +# http://www.lovdata.no/all/nl-19250717-011.html and
      +# http://www.lovdata.no/all/nl-19300227-002.html).  The law/regulation
      +# for normal/standard time in Norway is from 1894-06-29 no 1 (came
      +# into operation on 1895-01-01) and Svalbard/Jan Mayen seem to be a
      +# part of this law since 1925/1930. (From
      +# http://www.lovdata.no/all/nl-18940629-001.html ) I have not been
      +# able to find if Jan Mayen used a different time zone (e.g. -0100)
      +# before 1930. Jan Mayen has only been "inhabitated" since 1921 by
      +# Norwegian meteorologists and maybe used the same time as Norway ever
      +# since 1921.  Svalbard (Arctic/Longyearbyen) has been inhabited since
      +# before 1895, and therefore probably changed the local time somewhere
      +# between 1895 and 1925 (inclusive).
      +
      +# From Paul Eggert (2001-05-01):
      +#
      +# Actually, Jan Mayen was never occupied by Germany during World War II,
      +# so it must have diverged from Oslo time during the war, as Oslo was
      +# keeping Berlin time.
      +#
      +#  says that the meteorologists
      +# burned down their station in 1940 and left the island, but returned in
      +# 1941 with a small Norwegian garrison and continued operations despite
      +# frequent air ttacks from Germans.  In 1943 the Americans established a
      +# radiolocating station on the island, called "Atlantic City".  Possibly
      +# the UTC offset changed during the war, but I think it unlikely that
      +# Jan Mayen used German daylight-saving rules.
      +#
      +# Svalbard is more complicated, as it was raided in August 1941 by an
      +# Allied party that evacuated the civilian population to England (says
      +# ).  The Svalbard FAQ
      +#  says that the Germans were
      +# expelled on 1942-05-14.  However, small parties of Germans did return,
      +# and according to Wilhelm Dege's book "War North of 80" (1954)
      +# 
      +# the German armed forces at the Svalbard weather station code-named
      +# Haudegen did not surrender to the Allies until September 1945.
      +#
      +# All these events predate our cutoff date of 1970.  Unless we can
      +# come up with more definitive info about the timekeeping during the
      +# war years it's probably best just do...the following for now:
      +Link	Europe/Oslo	Arctic/Longyearbyen
      +
      +# Poland
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Poland	1918	1919	-	Sep	16	2:00s	0	-
      +Rule	Poland	1919	only	-	Apr	15	2:00s	1:00	S
      +Rule	Poland	1944	only	-	Apr	 3	2:00s	1:00	S
      +# Whitman gives 1944 Nov 30; go with Shanks & Pottenger.
      +Rule	Poland	1944	only	-	Oct	 4	2:00	0	-
      +# For 1944-1948 Whitman gives the previous day; go with Shanks & Pottenger.
      +Rule	Poland	1945	only	-	Apr	29	0:00	1:00	S
      +Rule	Poland	1945	only	-	Nov	 1	0:00	0	-
      +# For 1946 on the source is Kazimierz Borkowski,
      +# Torun Center for Astronomy, Dept. of Radio Astronomy, Nicolaus Copernicus U.,
      +# 
      +# Thanks to Przemyslaw Augustyniak (2005-05-28) for this reference.
      +# He also gives these further references:
      +# Mon Pol nr 13, poz 162 (1995) 
      +# Druk nr 2180 (2003) 
      +Rule	Poland	1946	only	-	Apr	14	0:00s	1:00	S
      +Rule	Poland	1946	only	-	Oct	 7	2:00s	0	-
      +Rule	Poland	1947	only	-	May	 4	2:00s	1:00	S
      +Rule	Poland	1947	1949	-	Oct	Sun>=1	2:00s	0	-
      +Rule	Poland	1948	only	-	Apr	18	2:00s	1:00	S
      +Rule	Poland	1949	only	-	Apr	10	2:00s	1:00	S
      +Rule	Poland	1957	only	-	Jun	 2	1:00s	1:00	S
      +Rule	Poland	1957	1958	-	Sep	lastSun	1:00s	0	-
      +Rule	Poland	1958	only	-	Mar	30	1:00s	1:00	S
      +Rule	Poland	1959	only	-	May	31	1:00s	1:00	S
      +Rule	Poland	1959	1961	-	Oct	Sun>=1	1:00s	0	-
      +Rule	Poland	1960	only	-	Apr	 3	1:00s	1:00	S
      +Rule	Poland	1961	1964	-	May	lastSun	1:00s	1:00	S
      +Rule	Poland	1962	1964	-	Sep	lastSun	1:00s	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Europe/Warsaw	1:24:00 -	LMT	1880
      +			1:24:00	-	WMT	1915 Aug  5   # Warsaw Mean Time
      +			1:00	C-Eur	CE%sT	1918 Sep 16 3:00
      +			2:00	Poland	EE%sT	1922 Jun
      +			1:00	Poland	CE%sT	1940 Jun 23 2:00
      +			1:00	C-Eur	CE%sT	1944 Oct
      +			1:00	Poland	CE%sT	1977
      +			1:00	W-Eur	CE%sT	1988
      +			1:00	EU	CE%sT
      +
      +# Portugal
      +#
      +# From Rui Pedro Salgueiro (1992-11-12):
      +# Portugal has recently (September, 27) changed timezone
      +# (from WET to MET or CET) to harmonize with EEC.
      +#
      +# Martin Bruckmann (1996-02-29) reports via Peter Ilieve
      +# that Portugal is reverting to 0:00 by not moving its clocks this spring.
      +# The new Prime Minister was fed up with getting up in the dark in the winter.
      +#
      +# From Paul Eggert (1996-11-12):
      +# IATA SSIM (1991-09) reports several 1991-09 and 1992-09 transitions
      +# at 02:00u, not 01:00u.  Assume that these are typos.
      +# IATA SSIM (1991/1992) reports that the Azores were at -1:00.
      +# IATA SSIM (1993-02) says +0:00; later issues (through 1996-09) say -1:00.
      +# Guess that the Azores changed to EU rules in 1992 (since that's when Portugal
      +# harmonized with the EU), and that they stayed +0:00 that winter.
      +#
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +# DSH writes that despite Decree 1,469 (1915), the change to the clocks was not
      +# done every year, depending on what Spain did, because of railroad schedules.
      +# Go with Shanks & Pottenger.
      +Rule	Port	1916	only	-	Jun	17	23:00	1:00	S
      +# Whitman gives 1916 Oct 31; go with Shanks & Pottenger.
      +Rule	Port	1916	only	-	Nov	 1	 1:00	0	-
      +Rule	Port	1917	only	-	Feb	28	23:00s	1:00	S
      +Rule	Port	1917	1921	-	Oct	14	23:00s	0	-
      +Rule	Port	1918	only	-	Mar	 1	23:00s	1:00	S
      +Rule	Port	1919	only	-	Feb	28	23:00s	1:00	S
      +Rule	Port	1920	only	-	Feb	29	23:00s	1:00	S
      +Rule	Port	1921	only	-	Feb	28	23:00s	1:00	S
      +Rule	Port	1924	only	-	Apr	16	23:00s	1:00	S
      +Rule	Port	1924	only	-	Oct	14	23:00s	0	-
      +Rule	Port	1926	only	-	Apr	17	23:00s	1:00	S
      +Rule	Port	1926	1929	-	Oct	Sat>=1	23:00s	0	-
      +Rule	Port	1927	only	-	Apr	 9	23:00s	1:00	S
      +Rule	Port	1928	only	-	Apr	14	23:00s	1:00	S
      +Rule	Port	1929	only	-	Apr	20	23:00s	1:00	S
      +Rule	Port	1931	only	-	Apr	18	23:00s	1:00	S
      +# Whitman gives 1931 Oct 8; go with Shanks & Pottenger.
      +Rule	Port	1931	1932	-	Oct	Sat>=1	23:00s	0	-
      +Rule	Port	1932	only	-	Apr	 2	23:00s	1:00	S
      +Rule	Port	1934	only	-	Apr	 7	23:00s	1:00	S
      +# Whitman gives 1934 Oct 5; go with Shanks & Pottenger.
      +Rule	Port	1934	1938	-	Oct	Sat>=1	23:00s	0	-
      +# Shanks & Pottenger give 1935 Apr 30; go with Whitman.
      +Rule	Port	1935	only	-	Mar	30	23:00s	1:00	S
      +Rule	Port	1936	only	-	Apr	18	23:00s	1:00	S
      +# Whitman gives 1937 Apr 2; go with Shanks & Pottenger.
      +Rule	Port	1937	only	-	Apr	 3	23:00s	1:00	S
      +Rule	Port	1938	only	-	Mar	26	23:00s	1:00	S
      +Rule	Port	1939	only	-	Apr	15	23:00s	1:00	S
      +# Whitman gives 1939 Oct 7; go with Shanks & Pottenger.
      +Rule	Port	1939	only	-	Nov	18	23:00s	0	-
      +Rule	Port	1940	only	-	Feb	24	23:00s	1:00	S
      +# Shanks & Pottenger give 1940 Oct 7; go with Whitman.
      +Rule	Port	1940	1941	-	Oct	 5	23:00s	0	-
      +Rule	Port	1941	only	-	Apr	 5	23:00s	1:00	S
      +Rule	Port	1942	1945	-	Mar	Sat>=8	23:00s	1:00	S
      +Rule	Port	1942	only	-	Apr	25	22:00s	2:00	M # Midsummer
      +Rule	Port	1942	only	-	Aug	15	22:00s	1:00	S
      +Rule	Port	1942	1945	-	Oct	Sat>=24	23:00s	0	-
      +Rule	Port	1943	only	-	Apr	17	22:00s	2:00	M
      +Rule	Port	1943	1945	-	Aug	Sat>=25	22:00s	1:00	S
      +Rule	Port	1944	1945	-	Apr	Sat>=21	22:00s	2:00	M
      +Rule	Port	1946	only	-	Apr	Sat>=1	23:00s	1:00	S
      +Rule	Port	1946	only	-	Oct	Sat>=1	23:00s	0	-
      +Rule	Port	1947	1949	-	Apr	Sun>=1	 2:00s	1:00	S
      +Rule	Port	1947	1949	-	Oct	Sun>=1	 2:00s	0	-
      +# Shanks & Pottenger say DST was observed in 1950; go with Whitman.
      +# Whitman gives Oct lastSun for 1952 on; go with Shanks & Pottenger.
      +Rule	Port	1951	1965	-	Apr	Sun>=1	 2:00s	1:00	S
      +Rule	Port	1951	1965	-	Oct	Sun>=1	 2:00s	0	-
      +Rule	Port	1977	only	-	Mar	27	 0:00s	1:00	S
      +Rule	Port	1977	only	-	Sep	25	 0:00s	0	-
      +Rule	Port	1978	1979	-	Apr	Sun>=1	 0:00s	1:00	S
      +Rule	Port	1978	only	-	Oct	 1	 0:00s	0	-
      +Rule	Port	1979	1982	-	Sep	lastSun	 1:00s	0	-
      +Rule	Port	1980	only	-	Mar	lastSun	 0:00s	1:00	S
      +Rule	Port	1981	1982	-	Mar	lastSun	 1:00s	1:00	S
      +Rule	Port	1983	only	-	Mar	lastSun	 2:00s	1:00	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +# Shanks & Pottenger say the transition from LMT to WET occurred 1911-05-24;
      +# Willett says 1912-01-01.  Go with Willett.
      +Zone	Europe/Lisbon	-0:36:32 -	LMT	1884
      +			-0:36:32 -	LMT	1912 Jan  1  # Lisbon Mean Time
      +			 0:00	Port	WE%sT	1966 Apr  3 2:00
      +			 1:00	-	CET	1976 Sep 26 1:00
      +			 0:00	Port	WE%sT	1983 Sep 25 1:00s
      +			 0:00	W-Eur	WE%sT	1992 Sep 27 1:00s
      +			 1:00	EU	CE%sT	1996 Mar 31 1:00u
      +			 0:00	EU	WE%sT
      +Zone Atlantic/Azores	-1:42:40 -	LMT	1884		# Ponta Delgada
      +			-1:54:32 -	HMT	1911 May 24  # Horta Mean Time
      +			-2:00	Port	AZO%sT	1966 Apr  3 2:00 # Azores Time
      +			-1:00	Port	AZO%sT	1983 Sep 25 1:00s
      +			-1:00	W-Eur	AZO%sT	1992 Sep 27 1:00s
      +			 0:00	EU	WE%sT	1993 Mar 28 1:00u
      +			-1:00	EU	AZO%sT
      +Zone Atlantic/Madeira	-1:07:36 -	LMT	1884		# Funchal
      +			-1:07:36 -	FMT	1911 May 24  # Funchal Mean Time
      +			-1:00	Port	MAD%sT	1966 Apr  3 2:00 # Madeira Time
      +			 0:00	Port	WE%sT	1983 Sep 25 1:00s
      +			 0:00	EU	WE%sT
      +
      +# Romania
      +#
      +# From Paul Eggert (1999-10-07):
      +# 
      +# Nine O'clock (1998-10-23) reports that the switch occurred at
      +# 04:00 local time in fall 1998.  For lack of better info,
      +# assume that Romania and Moldova switched to EU rules in 1997,
      +# the same year as Bulgaria.
      +#
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Romania	1932	only	-	May	21	 0:00s	1:00	S
      +Rule	Romania	1932	1939	-	Oct	Sun>=1	 0:00s	0	-
      +Rule	Romania	1933	1939	-	Apr	Sun>=2	 0:00s	1:00	S
      +Rule	Romania	1979	only	-	May	27	 0:00	1:00	S
      +Rule	Romania	1979	only	-	Sep	lastSun	 0:00	0	-
      +Rule	Romania	1980	only	-	Apr	 5	23:00	1:00	S
      +Rule	Romania	1980	only	-	Sep	lastSun	 1:00	0	-
      +Rule	Romania	1991	1993	-	Mar	lastSun	 0:00s	1:00	S
      +Rule	Romania	1991	1993	-	Sep	lastSun	 0:00s	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Europe/Bucharest	1:44:24 -	LMT	1891 Oct
      +			1:44:24	-	BMT	1931 Jul 24	# Bucharest MT
      +			2:00	Romania	EE%sT	1981 Mar 29 2:00s
      +			2:00	C-Eur	EE%sT	1991
      +			2:00	Romania	EE%sT	1994
      +			2:00	E-Eur	EE%sT	1997
      +			2:00	EU	EE%sT
      +
      +# Russia
      +
      +# From Paul Eggert (2006-03-22):
      +# Except for Moscow after 1919-07-01, I invented the time zone abbreviations.
      +# Moscow time zone abbreviations after 1919-07-01, and Moscow rules after 1991,
      +# are from Andrey A. Chernov.  The rest is from Shanks & Pottenger,
      +# except we follow Chernov's report that 1992 DST transitions were Sat
      +# 23:00, not Sun 02:00s.
      +#
      +# From Stanislaw A. Kuzikowski (1994-06-29):
      +# But now it is some months since Novosibirsk is 3 hours ahead of Moscow!
      +# I do not know why they have decided to make this change;
      +# as far as I remember it was done exactly during winter->summer switching
      +# so we (Novosibirsk) simply did not switch.
      +#
      +# From Andrey A. Chernov (1996-10-04):
      +# `MSK' and `MSD' were born and used initially on Moscow computers with
      +# UNIX-like OSes by several developer groups (e.g. Demos group, Kiae group)....
      +# The next step was the UUCP network, the Relcom predecessor
      +# (used mainly for mail), and MSK/MSD was actively used there.
      +#
      +# From Chris Carrier (1996-10-30):
      +# According to a friend of mine who rode the Trans-Siberian Railroad from
      +# Moscow to Irkutsk in 1995, public air and rail transport in Russia ...
      +# still follows Moscow time, no matter where in Russia it is located.
      +#
      +# For Grozny, Chechnya, we have the following story from
      +# John Daniszewski, "Scavengers in the Rubble", Los Angeles Times (2001-02-07):
      +# News--often false--is spread by word of mouth.  A rumor that it was
      +# time to move the clocks back put this whole city out of sync with
      +# the rest of Russia for two weeks--even soldiers stationed here began
      +# enforcing curfew at the wrong time.
      +#
      +# From Gwillim Law (2001-06-05):
      +# There's considerable evidence that Sakhalin Island used to be in
      +# UTC+11, and has changed to UTC+10, in this decade.  I start with the
      +# SSIM, which listed Yuzhno-Sakhalinsk in zone RU10 along with Magadan
      +# until February 1997, and then in RU9 with Khabarovsk and Vladivostok
      +# since September 1997....  Although the Kuril Islands are
      +# administratively part of Sakhalin oblast', they appear to have
      +# remained on UTC+11 along with Magadan.
      +#
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +#
      +# Kaliningradskaya oblast'.
      +Zone Europe/Kaliningrad	 1:22:00 -	LMT	1893 Apr
      +			 1:00	C-Eur	CE%sT	1945
      +			 2:00	Poland	CE%sT	1946
      +			 3:00	Russia	MSK/MSD	1991 Mar 31 2:00s
      +			 2:00	Russia	EE%sT	2011 Mar 27 2:00s
      +			 3:00	-	FET # Further-eastern European Time
      +#
      +# From Oscar van Vlijmen (2001-08-25): [This region consists of]
      +# Respublika Adygeya, Arkhangel'skaya oblast',
      +# Belgorodskaya oblast', Bryanskaya oblast', Vladimirskaya oblast',
      +# Vologodskaya oblast', Voronezhskaya oblast',
      +# Respublika Dagestan, Ivanovskaya oblast', Respublika Ingushetiya,
      +# Kabarbino-Balkarskaya Respublika, Respublika Kalmykiya,
      +# Kalyzhskaya oblast', Respublika Karachaevo-Cherkessiya,
      +# Respublika Kareliya, Respublika Komi,
      +# Kostromskaya oblast', Krasnodarskij kraj, Kurskaya oblast',
      +# Leningradskaya oblast', Lipetskaya oblast', Respublika Marij El,
      +# Respublika Mordoviya, Moskva, Moskovskaya oblast',
      +# Murmanskaya oblast', Nenetskij avtonomnyj okrug,
      +# Nizhegorodskaya oblast', Novgorodskaya oblast', Orlovskaya oblast',
      +# Penzenskaya oblast', Pskovskaya oblast', Rostovskaya oblast',
      +# Ryazanskaya oblast', Sankt-Peterburg,
      +# Respublika Severnaya Osetiya, Smolenskaya oblast',
      +# Stavropol'skij kraj, Tambovskaya oblast', Respublika Tatarstan,
      +# Tverskaya oblast', Tyl'skaya oblast', Ul'yanovskaya oblast',
      +# Chechenskaya Respublika, Chuvashskaya oblast',
      +# Yaroslavskaya oblast'
      +Zone Europe/Moscow	 2:30:20 -	LMT	1880
      +			 2:30	-	MMT	1916 Jul  3 # Moscow Mean Time
      +			 2:30:48 Russia	%s	1919 Jul  1 2:00
      +			 3:00	Russia	MSK/MSD	1922 Oct
      +			 2:00	-	EET	1930 Jun 21
      +			 3:00	Russia	MSK/MSD	1991 Mar 31 2:00s
      +			 2:00	Russia	EE%sT	1992 Jan 19 2:00s
      +			 3:00	Russia	MSK/MSD	2011 Mar 27 2:00s
      +			 4:00	-	MSK
      +#
      +# Astrakhanskaya oblast', Kirovskaya oblast', Saratovskaya oblast',
      +# Volgogradskaya oblast'.  Shanks & Pottenger say Kirov is still at +0400
      +# but Wikipedia (2006-05-09) says +0300.  Perhaps it switched after the
      +# others?  But we have no data.
      +Zone Europe/Volgograd	 2:57:40 -	LMT	1920 Jan  3
      +			 3:00	-	TSAT	1925 Apr  6 # Tsaritsyn Time
      +			 3:00	-	STAT	1930 Jun 21 # Stalingrad Time
      +			 4:00	-	STAT	1961 Nov 11
      +			 4:00	Russia	VOL%sT	1989 Mar 26 2:00s # Volgograd T
      +			 3:00	Russia	VOL%sT	1991 Mar 31 2:00s
      +			 4:00	-	VOLT	1992 Mar 29 2:00s
      +			 3:00	Russia	VOL%sT	2011 Mar 27 2:00s
      +			 4:00	-	VOLT
      +#
      +# From Oscar van Vlijmen (2001-08-25): [This region consists of]
      +# Samarskaya oblast', Udmyrtskaya respublika
      +Zone Europe/Samara	 3:20:36 -	LMT	1919 Jul  1 2:00
      +			 3:00	-	SAMT	1930 Jun 21
      +			 4:00	-	SAMT	1935 Jan 27
      +			 4:00	Russia	KUY%sT	1989 Mar 26 2:00s # Kuybyshev
      +			 3:00	Russia	KUY%sT	1991 Mar 31 2:00s
      +			 2:00	Russia	KUY%sT	1991 Sep 29 2:00s
      +			 3:00	-	KUYT	1991 Oct 20 3:00
      +			 4:00	Russia	SAM%sT	2010 Mar 28 2:00s # Samara Time
      +			 3:00	Russia	SAM%sT	2011 Mar 27 2:00s
      +			 4:00	-	SAMT
      +
      +#
      +# From Oscar van Vlijmen (2001-08-25): [This region consists of]
      +# Respublika Bashkortostan, Komi-Permyatskij avtonomnyj okrug,
      +# Kurganskaya oblast', Orenburgskaya oblast', Permskaya oblast',
      +# Sverdlovskaya oblast', Tyumenskaya oblast',
      +# Khanty-Manskijskij avtonomnyj okrug, Chelyabinskaya oblast',
      +# Yamalo-Nenetskij avtonomnyj okrug.
      +Zone Asia/Yekaterinburg	 4:02:24 -	LMT	1919 Jul 15 4:00
      +			 4:00	-	SVET	1930 Jun 21 # Sverdlovsk Time
      +			 5:00	Russia	SVE%sT	1991 Mar 31 2:00s
      +			 4:00	Russia	SVE%sT	1992 Jan 19 2:00s
      +			 5:00	Russia	YEK%sT	2011 Mar 27 2:00s
      +			 6:00	-	YEKT	# Yekaterinburg Time
      +#
      +# From Oscar van Vlijmen (2001-08-25): [This region consists of]
      +# Respublika Altaj, Altajskij kraj, Omskaya oblast'.
      +Zone Asia/Omsk		 4:53:36 -	LMT	1919 Nov 14
      +			 5:00	-	OMST	1930 Jun 21 # Omsk TIme
      +			 6:00	Russia	OMS%sT	1991 Mar 31 2:00s
      +			 5:00	Russia	OMS%sT	1992 Jan 19 2:00s
      +			 6:00	Russia	OMS%sT	2011 Mar 27 2:00s
      +			 7:00	-	OMST
      +#
      +# From Paul Eggert (2006-08-19): I'm guessing about Tomsk here; it's
      +# not clear when it switched from +7 to +6.
      +# Novosibirskaya oblast', Tomskaya oblast'.
      +Zone Asia/Novosibirsk	 5:31:40 -	LMT	1919 Dec 14 6:00
      +			 6:00	-	NOVT	1930 Jun 21 # Novosibirsk Time
      +			 7:00	Russia	NOV%sT	1991 Mar 31 2:00s
      +			 6:00	Russia	NOV%sT	1992 Jan 19 2:00s
      +			 7:00	Russia	NOV%sT	1993 May 23 # say Shanks & P.
      +			 6:00	Russia	NOV%sT	2011 Mar 27 2:00s
      +			 7:00	-	NOVT
      +
      +# From Alexander Krivenyshev (2009-10-13):
      +# Kemerovo oblast' (Kemerovo region) in Russia will change current time zone on
      +# March 28, 2010:
      +# from current Russia Zone 6 - Krasnoyarsk Time Zone (KRA) UTC +0700
      +# to Russia Zone 5 - Novosibirsk Time Zone (NOV) UTC +0600
      +#
      +# This is according to Government of Russia decree # 740, on September
      +# 14, 2009 "Application in the territory of the Kemerovo region the Fifth
      +# time zone." ("Russia Zone 5" or old "USSR Zone 5" is GMT +0600)
      +#
      +# Russian Government web site (Russian language)
      +# 
      +# http://www.government.ru/content/governmentactivity/rfgovernmentdecisions/archive/2009/09/14/991633.htm
      +# 
      +# or Russian-English translation by WorldTimeZone.com with reference
      +# map to local region and new Russia Time Zone map after March 28, 2010
      +# 
      +# http://www.worldtimezone.com/dst_news/dst_news_russia03.html
      +# 
      +#
      +# Thus, when Russia will switch to DST on the night of March 28, 2010
      +# Kemerovo region (Kemerovo oblast') will not change the clock.
      +#
      +# As a result, Kemerovo oblast' will be in the same time zone as
      +# Novosibirsk, Omsk, Tomsk, Barnaul and Altai Republic.
      +
      +Zone Asia/Novokuznetsk	 5:48:48 -	NMT	1920 Jan  6
      +			 6:00	-	KRAT	1930 Jun 21 # Krasnoyarsk Time
      +			 7:00	Russia	KRA%sT	1991 Mar 31 2:00s
      +			 6:00	Russia	KRA%sT	1992 Jan 19 2:00s
      +			 7:00	Russia	KRA%sT	2010 Mar 28 2:00s
      +			 6:00	Russia	NOV%sT	2011 Mar 27 2:00s
      +			 7:00	-	NOVT # Novosibirsk/Novokuznetsk Time
      +
      +#
      +# From Oscar van Vlijmen (2001-08-25): [This region consists of]
      +# Krasnoyarskij kraj,
      +# Tajmyrskij (Dolgano-Nenetskij) avtonomnyj okrug,
      +# Respublika Tuva, Respublika Khakasiya, Evenkijskij avtonomnyj okrug.
      +Zone Asia/Krasnoyarsk	 6:11:20 -	LMT	1920 Jan  6
      +			 6:00	-	KRAT	1930 Jun 21 # Krasnoyarsk Time
      +			 7:00	Russia	KRA%sT	1991 Mar 31 2:00s
      +			 6:00	Russia	KRA%sT	1992 Jan 19 2:00s
      +			 7:00	Russia	KRA%sT	2011 Mar 27 2:00s
      +			 8:00	-	KRAT
      +#
      +# From Oscar van Vlijmen (2001-08-25): [This region consists of]
      +# Respublika Buryatiya, Irkutskaya oblast',
      +# Ust'-Ordynskij Buryatskij avtonomnyj okrug.
      +Zone Asia/Irkutsk	 6:57:20 -	LMT	1880
      +			 6:57:20 -	IMT	1920 Jan 25 # Irkutsk Mean Time
      +			 7:00	-	IRKT	1930 Jun 21 # Irkutsk Time
      +			 8:00	Russia	IRK%sT	1991 Mar 31 2:00s
      +			 7:00	Russia	IRK%sT	1992 Jan 19 2:00s
      +			 8:00	Russia	IRK%sT	2011 Mar 27 2:00s
      +			 9:00	-	IRKT
      +#
      +# From Oscar van Vlijmen (2003-10-18): [This region consists of]
      +# Aginskij Buryatskij avtonomnyj okrug, Amurskaya oblast',
      +# [parts of] Respublika Sakha (Yakutiya), Chitinskaya oblast'.
      +
      +# From Oscar van Vlijmen (2009-11-29):
      +# ...some regions of [Russia] were merged with others since 2005...
      +# Some names were changed, no big deal, except for one instance: a new name.
      +# YAK/YAKST: UTC+9 Zabajkal'skij kraj.
      +
      +# From Oscar van Vlijmen (2009-11-29):
      +# The Sakha districts are: Aldanskij, Amginskij, Anabarskij,
      +# Verkhnevilyujskij, Vilyujskij, Gornyj,
      +# Zhiganskij, Kobyajskij, Lenskij, Megino-Kangalasskij, Mirninskij,
      +# Namskij, Nyurbinskij, Olenyokskij, Olyokminskij,
      +# Suntarskij, Tattinskij, Ust'-Aldanskij, Khangalasskij,
      +# Churapchinskij, Eveno-Bytantajskij Natsional'nij.
      +
      +Zone Asia/Yakutsk	 8:38:40 -	LMT	1919 Dec 15
      +			 8:00	-	YAKT	1930 Jun 21 # Yakutsk Time
      +			 9:00	Russia	YAK%sT	1991 Mar 31 2:00s
      +			 8:00	Russia	YAK%sT	1992 Jan 19 2:00s
      +			 9:00	Russia	YAK%sT	2011 Mar 27 2:00s
      +			 10:00	-	YAKT
      +#
      +# From Oscar van Vlijmen (2003-10-18): [This region consists of]
      +# Evrejskaya avtonomnaya oblast', Khabarovskij kraj, Primorskij kraj,
      +# [parts of] Respublika Sakha (Yakutiya).
      +
      +# From Oscar van Vlijmen (2009-11-29):
      +# The Sakha districts are: Bulunskij, Verkhoyanskij, Tomponskij, Ust'-Majskij,
      +# Ust'-Yanskij.
      +Zone Asia/Vladivostok	 8:47:44 -	LMT	1922 Nov 15
      +			 9:00	-	VLAT	1930 Jun 21 # Vladivostok Time
      +			10:00	Russia	VLA%sT	1991 Mar 31 2:00s
      +			 9:00	Russia	VLA%sST	1992 Jan 19 2:00s
      +			10:00	Russia	VLA%sT	2011 Mar 27 2:00s
      +			11:00	-	VLAT
      +#
      +# Sakhalinskaya oblast'.
      +# The Zone name should be Yuzhno-Sakhalinsk, but that's too long.
      +Zone Asia/Sakhalin	 9:30:48 -	LMT	1905 Aug 23
      +			 9:00	-	CJT	1938
      +			 9:00	-	JST	1945 Aug 25
      +			11:00	Russia	SAK%sT	1991 Mar 31 2:00s # Sakhalin T.
      +			10:00	Russia	SAK%sT	1992 Jan 19 2:00s
      +			11:00	Russia	SAK%sT	1997 Mar lastSun 2:00s
      +			10:00	Russia	SAK%sT	2011 Mar 27 2:00s
      +			11:00	-	SAKT
      +#
      +# From Oscar van Vlijmen (2003-10-18): [This region consists of]
      +# Magadanskaya oblast', Respublika Sakha (Yakutiya).
      +# Probably also: Kuril Islands.
      +
      +# From Oscar van Vlijmen (2009-11-29):
      +# The Sakha districts are: Abyjskij, Allaikhovskij, Verkhhhnekolymskij, Momskij,
      +# Nizhnekolymskij, Ojmyakonskij, Srednekolymskij.
      +Zone Asia/Magadan	10:03:12 -	LMT	1924 May  2
      +			10:00	-	MAGT	1930 Jun 21 # Magadan Time
      +			11:00	Russia	MAG%sT	1991 Mar 31 2:00s
      +			10:00	Russia	MAG%sT	1992 Jan 19 2:00s
      +			11:00	Russia	MAG%sT	2011 Mar 27 2:00s
      +			12:00	-	MAGT
      +#
      +# From Oscar van Vlijmen (2001-08-25): [This region consists of]
      +# Kamchatskaya oblast', Koryakskij avtonomnyj okrug.
      +#
      +# The Zone name should be Asia/Petropavlovsk-Kamchatski, but that's too long.
      +Zone Asia/Kamchatka	10:34:36 -	LMT	1922 Nov 10
      +			11:00	-	PETT	1930 Jun 21 # P-K Time
      +			12:00	Russia	PET%sT	1991 Mar 31 2:00s
      +			11:00	Russia	PET%sT	1992 Jan 19 2:00s
      +			12:00	Russia	PET%sT	2010 Mar 28 2:00s
      +			11:00	Russia	PET%sT	2011 Mar 27 2:00s
      +			12:00	-	PETT
      +#
      +# Chukotskij avtonomnyj okrug
      +Zone Asia/Anadyr	11:49:56 -	LMT	1924 May  2
      +			12:00	-	ANAT	1930 Jun 21 # Anadyr Time
      +			13:00	Russia	ANA%sT	1982 Apr  1 0:00s
      +			12:00	Russia	ANA%sT	1991 Mar 31 2:00s
      +			11:00	Russia	ANA%sT	1992 Jan 19 2:00s
      +			12:00	Russia	ANA%sT	2010 Mar 28 2:00s
      +			11:00	Russia	ANA%sT	2011 Mar 27 2:00s
      +			12:00	-	ANAT
      +
      +# Serbia
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Europe/Belgrade	1:22:00	-	LMT	1884
      +			1:00	-	CET	1941 Apr 18 23:00
      +			1:00	C-Eur	CE%sT	1945
      +			1:00	-	CET	1945 May 8 2:00s
      +			1:00	1:00	CEST	1945 Sep 16  2:00s
      +# Metod Kozelj reports that the legal date of
      +# transition to EU rules was 1982-11-27, for all of Yugoslavia at the time.
      +# Shanks & Pottenger don't give as much detail, so go with Kozelj.
      +			1:00	-	CET	1982 Nov 27
      +			1:00	EU	CE%sT
      +Link Europe/Belgrade Europe/Ljubljana	# Slovenia
      +Link Europe/Belgrade Europe/Podgorica	# Montenegro
      +Link Europe/Belgrade Europe/Sarajevo	# Bosnia and Herzegovina
      +Link Europe/Belgrade Europe/Skopje	# Macedonia
      +Link Europe/Belgrade Europe/Zagreb	# Croatia
      +
      +# Slovakia
      +Link Europe/Prague Europe/Bratislava
      +
      +# Slovenia
      +# see Serbia
      +
      +# Spain
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +# For 1917-1919 Whitman gives Apr Sat>=1 - Oct Sat>=1;
      +# go with Shanks & Pottenger.
      +Rule	Spain	1917	only	-	May	 5	23:00s	1:00	S
      +Rule	Spain	1917	1919	-	Oct	 6	23:00s	0	-
      +Rule	Spain	1918	only	-	Apr	15	23:00s	1:00	S
      +Rule	Spain	1919	only	-	Apr	 5	23:00s	1:00	S
      +# Whitman gives 1921 Feb 28 - Oct 14; go with Shanks & Pottenger.
      +Rule	Spain	1924	only	-	Apr	16	23:00s	1:00	S
      +# Whitman gives 1924 Oct 14; go with Shanks & Pottenger.
      +Rule	Spain	1924	only	-	Oct	 4	23:00s	0	-
      +Rule	Spain	1926	only	-	Apr	17	23:00s	1:00	S
      +# Whitman says no DST in 1929; go with Shanks & Pottenger.
      +Rule	Spain	1926	1929	-	Oct	Sat>=1	23:00s	0	-
      +Rule	Spain	1927	only	-	Apr	 9	23:00s	1:00	S
      +Rule	Spain	1928	only	-	Apr	14	23:00s	1:00	S
      +Rule	Spain	1929	only	-	Apr	20	23:00s	1:00	S
      +# Whitman gives 1937 Jun 16, 1938 Apr 16, 1940 Apr 13;
      +# go with Shanks & Pottenger.
      +Rule	Spain	1937	only	-	May	22	23:00s	1:00	S
      +Rule	Spain	1937	1939	-	Oct	Sat>=1	23:00s	0	-
      +Rule	Spain	1938	only	-	Mar	22	23:00s	1:00	S
      +Rule	Spain	1939	only	-	Apr	15	23:00s	1:00	S
      +Rule	Spain	1940	only	-	Mar	16	23:00s	1:00	S
      +# Whitman says no DST 1942-1945; go with Shanks & Pottenger.
      +Rule	Spain	1942	only	-	May	 2	22:00s	2:00	M # Midsummer
      +Rule	Spain	1942	only	-	Sep	 1	22:00s	1:00	S
      +Rule	Spain	1943	1946	-	Apr	Sat>=13	22:00s	2:00	M
      +Rule	Spain	1943	only	-	Oct	 3	22:00s	1:00	S
      +Rule	Spain	1944	only	-	Oct	10	22:00s	1:00	S
      +Rule	Spain	1945	only	-	Sep	30	 1:00	1:00	S
      +Rule	Spain	1946	only	-	Sep	30	 0:00	0	-
      +Rule	Spain	1949	only	-	Apr	30	23:00	1:00	S
      +Rule	Spain	1949	only	-	Sep	30	 1:00	0	-
      +Rule	Spain	1974	1975	-	Apr	Sat>=13	23:00	1:00	S
      +Rule	Spain	1974	1975	-	Oct	Sun>=1	 1:00	0	-
      +Rule	Spain	1976	only	-	Mar	27	23:00	1:00	S
      +Rule	Spain	1976	1977	-	Sep	lastSun	 1:00	0	-
      +Rule	Spain	1977	1978	-	Apr	 2	23:00	1:00	S
      +Rule	Spain	1978	only	-	Oct	 1	 1:00	0	-
      +# The following rules are copied from Morocco from 1967 through 1978.
      +Rule SpainAfrica 1967	only	-	Jun	 3	12:00	1:00	S
      +Rule SpainAfrica 1967	only	-	Oct	 1	 0:00	0	-
      +Rule SpainAfrica 1974	only	-	Jun	24	 0:00	1:00	S
      +Rule SpainAfrica 1974	only	-	Sep	 1	 0:00	0	-
      +Rule SpainAfrica 1976	1977	-	May	 1	 0:00	1:00	S
      +Rule SpainAfrica 1976	only	-	Aug	 1	 0:00	0	-
      +Rule SpainAfrica 1977	only	-	Sep	28	 0:00	0	-
      +Rule SpainAfrica 1978	only	-	Jun	 1	 0:00	1:00	S
      +Rule SpainAfrica 1978	only	-	Aug	 4	 0:00	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Europe/Madrid	-0:14:44 -	LMT	1901 Jan  1  0:00s
      +			 0:00	Spain	WE%sT	1946 Sep 30
      +			 1:00	Spain	CE%sT	1979
      +			 1:00	EU	CE%sT
      +Zone	Africa/Ceuta	-0:21:16 -	LMT	1901
      +			 0:00	-	WET	1918 May  6 23:00
      +			 0:00	1:00	WEST	1918 Oct  7 23:00
      +			 0:00	-	WET	1924
      +			 0:00	Spain	WE%sT	1929
      +			 0:00 SpainAfrica WE%sT 1984 Mar 16
      +			 1:00	-	CET	1986
      +			 1:00	EU	CE%sT
      +Zone	Atlantic/Canary	-1:01:36 -	LMT	1922 Mar # Las Palmas de Gran C.
      +			-1:00	-	CANT	1946 Sep 30 1:00 # Canaries Time
      +			 0:00	-	WET	1980 Apr  6 0:00s
      +			 0:00	1:00	WEST	1980 Sep 28 0:00s
      +			 0:00	EU	WE%sT
      +# IATA SSIM (1996-09) says the Canaries switch at 2:00u, not 1:00u.
      +# Ignore this for now, as the Canaries are part of the EU.
      +
      +# Sweden
      +
      +# From Ivan Nilsson (2001-04-13), superseding Shanks & Pottenger:
      +#
      +# The law "Svensk forfattningssamling 1878, no 14" about standard time in 1879:
      +# From the beginning of 1879 (that is 01-01 00:00) the time for all
      +# places in the country is "the mean solar time for the meridian at
      +# three degrees, or twelve minutes of time, to the west of the
      +# meridian of the Observatory of Stockholm".  The law is dated 1878-05-31.
      +#
      +# The observatory at that time had the meridian 18 degrees 03' 30"
      +# eastern longitude = 01:12:14 in time.  Less 12 minutes gives the
      +# national standard time as 01:00:14 ahead of GMT....
      +#
      +# About the beginning of CET in Sweden. The lawtext ("Svensk
      +# forfattningssamling 1899, no 44") states, that "from the beginning
      +# of 1900... ... the same as the mean solar time for the meridian at
      +# the distance of one hour of time from the meridian of the English
      +# observatory at Greenwich, or at 12 minutes 14 seconds to the west
      +# from the meridian of the Observatory of Stockholm". The law is dated
      +# 1899-06-16.  In short: At 1900-01-01 00:00:00 the new standard time
      +# in Sweden is 01:00:00 ahead of GMT.
      +#
      +# 1916: The lawtext ("Svensk forfattningssamling 1916, no 124") states
      +# that "1916-05-15 is considered to begin one hour earlier". It is
      +# pretty obvious that at 05-14 23:00 the clocks are set to 05-15 00:00....
      +# Further the law says, that "1916-09-30 is considered to end one hour later".
      +#
      +# The laws regulating [DST] are available on the site of the Swedish
      +# Parliament beginning with 1985 - the laws regulating 1980/1984 are
      +# not available on the site (to my knowledge they are only available
      +# in Swedish):  (type
      +# "sommartid" without the quotes in the field "Fritext" and then click
      +# the Sok-button).
      +#
      +# (2001-05-13):
      +#
      +# I have now found a newspaper stating that at 1916-10-01 01:00
      +# summertime the church-clocks etc were set back one hour to show
      +# 1916-10-01 00:00 standard time.  The article also reports that some
      +# people thought the switch to standard time would take place already
      +# at 1916-10-01 00:00 summer time, but they had to wait for another
      +# hour before the event took place.
      +#
      +# Source: The newspaper "Dagens Nyheter", 1916-10-01, page 7 upper left.
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Europe/Stockholm	1:12:12 -	LMT	1879 Jan  1
      +			1:00:14	-	SET	1900 Jan  1	# Swedish Time
      +			1:00	-	CET	1916 May 14 23:00
      +			1:00	1:00	CEST	1916 Oct  1 01:00
      +			1:00	-	CET	1980
      +			1:00	EU	CE%sT
      +
      +# Switzerland
      +# From Howse:
      +# By the end of the 18th century clocks and watches became commonplace
      +# and their performance improved enormously.  Communities began to keep
      +# mean time in preference to apparent time -- Geneva from 1780 ....
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +# From Whitman (who writes ``Midnight?''):
      +# Rule	Swiss	1940	only	-	Nov	 2	0:00	1:00	S
      +# Rule	Swiss	1940	only	-	Dec	31	0:00	0	-
      +# From Shanks & Pottenger:
      +# Rule	Swiss	1941	1942	-	May	Sun>=1	2:00	1:00	S
      +# Rule	Swiss	1941	1942	-	Oct	Sun>=1	0:00	0	-
      +
      +# From Alois Treindl (2008-12-17):
      +# I have researched the DST usage in Switzerland during the 1940ies.
      +#
      +# As I wrote in an earlier message, I suspected the current tzdata values
      +# to be wrong. This is now verified.
      +#
      +# I have found copies of the original ruling by the Swiss Federal
      +# government, in 'Eidgen[o]ssische Gesetzessammlung 1941 and 1942' (Swiss
      +# federal law collection)...
      +#
      +# DST began on Monday 5 May 1941, 1:00 am by shifting the clocks to 2:00 am
      +# DST ended on Monday 6 Oct 1941, 2:00 am by shifting the clocks to 1:00 am.
      +#
      +# DST began on Monday, 4 May 1942 at 01:00 am
      +# DST ended on Monday, 5 Oct 1942 at 02:00 am
      +#
      +# There was no DST in 1940, I have checked the law collection carefully.
      +# It is also indicated by the fact that the 1942 entry in the law
      +# collection points back to 1941 as a reference, but no reference to any
      +# other years are made.
      +#
      +# Newspaper articles I have read in the archives on 6 May 1941 reported
      +# about the introduction of DST (Sommerzeit in German) during the previous
      +# night as an absolute novelty, because this was the first time that such
      +# a thing had happened in Switzerland.
      +#
      +# I have also checked 1916, because one book source (Gabriel, Traite de
      +# l'heure dans le monde) claims that Switzerland had DST in 1916. This is
      +# false, no official document could be found. Probably Gabriel got misled
      +# by references to Germany, which introduced DST in 1916 for the first time.
      +#
      +# The tzdata rules for Switzerland must be changed to:
      +# Rule  Swiss   1941    1942    -       May     Mon>=1  1:00    1:00    S
      +# Rule  Swiss   1941    1942    -       Oct     Mon>=1  2:00    0       -
      +#
      +# The 1940 rules must be deleted.
      +#
      +# One further detail for Switzerland, which is probably out of scope for
      +# most users of tzdata:
      +# The zone file
      +# Zone    Europe/Zurich   0:34:08 -       LMT     1848 Sep 12
      +#                          0:29:44 -       BMT     1894 Jun #Bern Mean Time
      +#                          1:00    Swiss   CE%sT   1981
      +#                          1:00    EU      CE%sT
      +# describes all of Switzerland correctly, with the exception of
      +# the Cantone Geneve (Geneva, Genf). Between 1848 and 1894 Geneve did not
      +# follow Bern Mean Time but kept its own local mean time.
      +# To represent this, an extra zone would be needed.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Swiss	1941	1942	-	May	Mon>=1	1:00	1:00	S
      +Rule	Swiss	1941	1942	-	Oct	Mon>=1	2:00	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Europe/Zurich	0:34:08 -	LMT	1848 Sep 12
      +			0:29:44	-	BMT	1894 Jun # Bern Mean Time
      +			1:00	Swiss	CE%sT	1981
      +			1:00	EU	CE%sT
      +
      +# Turkey
      +
      +# From Amar Devegowda (2007-01-03):
      +# The time zone rules for Istanbul, Turkey have not been changed for years now.
      +# ... The latest rules are available at -
      +# http://www.timeanddate.com/worldclock/timezone.html?n=107
      +# From Steffen Thorsen (2007-01-03):
      +# I have been able to find press records back to 1996 which all say that
      +# DST started 01:00 local time and end at 02:00 local time.  I am not sure
      +# what happened before that.  One example for each year from 1996 to 2001:
      +# http://newspot.byegm.gov.tr/arsiv/1996/21/N4.htm
      +# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING97/03/97X03X25.TXT
      +# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING98/03/98X03X02.HTM
      +# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING99/10/99X10X26.HTM#%2016
      +# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING2000/03/00X03X06.HTM#%2021
      +# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING2001/03/23x03x01.HTM#%2027
      +# From Paul Eggert (2007-01-03):
      +# Prefer the above source to Shanks & Pottenger for time stamps after 1990.
      +
      +# From Steffen Thorsen (2007-03-09):
      +# Starting 2007 though, it seems that they are adopting EU's 1:00 UTC
      +# start/end time, according to the following page (2007-03-07):
      +# http://www.ntvmsnbc.com/news/402029.asp
      +# The official document is located here - it is in Turkish...:
      +# http://rega.basbakanlik.gov.tr/eskiler/2007/03/20070307-7.htm
      +# I was able to locate the following seemingly official document
      +# (on a non-government server though) describing dates between 2002 and 2006:
      +# http://www.alomaliye.com/bkk_2002_3769.htm
      +
      +# From Gökdeniz Karadağ (2011-03-10):
      +#
      +# According to the articles linked below, Turkey will change into summer
      +# time zone (GMT+3) on March 28, 2011 at 3:00 a.m. instead of March 27.
      +# This change is due to a nationwide exam on 27th.
      +#
      +# 
      +# http://www.worldbulletin.net/?aType=haber&ArticleID=70872
      +# 
      +# Turkish:
      +# 
      +# http://www.hurriyet.com.tr/ekonomi/17230464.asp?gid=373
      +# 
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Turkey	1916	only	-	May	 1	0:00	1:00	S
      +Rule	Turkey	1916	only	-	Oct	 1	0:00	0	-
      +Rule	Turkey	1920	only	-	Mar	28	0:00	1:00	S
      +Rule	Turkey	1920	only	-	Oct	25	0:00	0	-
      +Rule	Turkey	1921	only	-	Apr	 3	0:00	1:00	S
      +Rule	Turkey	1921	only	-	Oct	 3	0:00	0	-
      +Rule	Turkey	1922	only	-	Mar	26	0:00	1:00	S
      +Rule	Turkey	1922	only	-	Oct	 8	0:00	0	-
      +# Whitman gives 1923 Apr 28 - Sep 16 and no DST in 1924-1925;
      +# go with Shanks & Pottenger.
      +Rule	Turkey	1924	only	-	May	13	0:00	1:00	S
      +Rule	Turkey	1924	1925	-	Oct	 1	0:00	0	-
      +Rule	Turkey	1925	only	-	May	 1	0:00	1:00	S
      +Rule	Turkey	1940	only	-	Jun	30	0:00	1:00	S
      +Rule	Turkey	1940	only	-	Oct	 5	0:00	0	-
      +Rule	Turkey	1940	only	-	Dec	 1	0:00	1:00	S
      +Rule	Turkey	1941	only	-	Sep	21	0:00	0	-
      +Rule	Turkey	1942	only	-	Apr	 1	0:00	1:00	S
      +# Whitman omits the next two transition and gives 1945 Oct 1;
      +# go with Shanks & Pottenger.
      +Rule	Turkey	1942	only	-	Nov	 1	0:00	0	-
      +Rule	Turkey	1945	only	-	Apr	 2	0:00	1:00	S
      +Rule	Turkey	1945	only	-	Oct	 8	0:00	0	-
      +Rule	Turkey	1946	only	-	Jun	 1	0:00	1:00	S
      +Rule	Turkey	1946	only	-	Oct	 1	0:00	0	-
      +Rule	Turkey	1947	1948	-	Apr	Sun>=16	0:00	1:00	S
      +Rule	Turkey	1947	1950	-	Oct	Sun>=2	0:00	0	-
      +Rule	Turkey	1949	only	-	Apr	10	0:00	1:00	S
      +Rule	Turkey	1950	only	-	Apr	19	0:00	1:00	S
      +Rule	Turkey	1951	only	-	Apr	22	0:00	1:00	S
      +Rule	Turkey	1951	only	-	Oct	 8	0:00	0	-
      +Rule	Turkey	1962	only	-	Jul	15	0:00	1:00	S
      +Rule	Turkey	1962	only	-	Oct	 8	0:00	0	-
      +Rule	Turkey	1964	only	-	May	15	0:00	1:00	S
      +Rule	Turkey	1964	only	-	Oct	 1	0:00	0	-
      +Rule	Turkey	1970	1972	-	May	Sun>=2	0:00	1:00	S
      +Rule	Turkey	1970	1972	-	Oct	Sun>=2	0:00	0	-
      +Rule	Turkey	1973	only	-	Jun	 3	1:00	1:00	S
      +Rule	Turkey	1973	only	-	Nov	 4	3:00	0	-
      +Rule	Turkey	1974	only	-	Mar	31	2:00	1:00	S
      +Rule	Turkey	1974	only	-	Nov	 3	5:00	0	-
      +Rule	Turkey	1975	only	-	Mar	30	0:00	1:00	S
      +Rule	Turkey	1975	1976	-	Oct	lastSun	0:00	0	-
      +Rule	Turkey	1976	only	-	Jun	 1	0:00	1:00	S
      +Rule	Turkey	1977	1978	-	Apr	Sun>=1	0:00	1:00	S
      +Rule	Turkey	1977	only	-	Oct	16	0:00	0	-
      +Rule	Turkey	1979	1980	-	Apr	Sun>=1	3:00	1:00	S
      +Rule	Turkey	1979	1982	-	Oct	Mon>=11	0:00	0	-
      +Rule	Turkey	1981	1982	-	Mar	lastSun	3:00	1:00	S
      +Rule	Turkey	1983	only	-	Jul	31	0:00	1:00	S
      +Rule	Turkey	1983	only	-	Oct	 2	0:00	0	-
      +Rule	Turkey	1985	only	-	Apr	20	0:00	1:00	S
      +Rule	Turkey	1985	only	-	Sep	28	0:00	0	-
      +Rule	Turkey	1986	1990	-	Mar	lastSun	2:00s	1:00	S
      +Rule	Turkey	1986	1990	-	Sep	lastSun	2:00s	0	-
      +Rule	Turkey	1991	2006	-	Mar	lastSun	1:00s	1:00	S
      +Rule	Turkey	1991	1995	-	Sep	lastSun	1:00s	0	-
      +Rule	Turkey	1996	2006	-	Oct	lastSun	1:00s	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	Europe/Istanbul	1:55:52 -	LMT	1880
      +			1:56:56	-	IMT	1910 Oct # Istanbul Mean Time?
      +			2:00	Turkey	EE%sT	1978 Oct 15
      +			3:00	Turkey	TR%sT	1985 Apr 20 # Turkey Time
      +			2:00	Turkey	EE%sT	2007
      +			2:00	EU	EE%sT	2011 Mar 27 1:00u
      +			2:00	-	EET	2011 Mar 28 1:00u
      +			2:00	EU	EE%sT
      +Link	Europe/Istanbul	Asia/Istanbul	# Istanbul is in both continents.
      +
      +# Ukraine
      +#
      +# From Igor Karpov, who works for the Ukranian Ministry of Justice,
      +# via Garrett Wollman (2003-01-27):
      +# BTW, I've found the official document on this matter. It's goverment
      +# regulations number 509, May 13, 1996. In my poor translation it says:
      +# "Time in Ukraine is set to second timezone (Kiev time). Each last Sunday
      +# of March at 3am the time is changing to 4am and each last Sunday of
      +# October the time at 4am is changing to 3am"
      +
      +# From Alexander Krivenyshev (2011-09-20):
      +# On September 20, 2011 the deputies of the Verkhovna Rada agreed to
      +# abolish the transfer clock to winter time.
      +#
      +# Bill number 8330 of MP from the Party of Regions Oleg Nadoshi got
      +# approval from 266 deputies.
      +#
      +# Ukraine abolishes transter back to the winter time (in Russian)
      +# 
      +# http://news.mail.ru/politics/6861560/
      +# 
      +#
      +# The Ukrainians will no longer change the clock (in Russian)
      +# 
      +# http://www.segodnya.ua/news/14290482.html
      +# 
      +#
      +# Deputies cancelled the winter time (in Russian)
      +# 
      +# http://www.pravda.com.ua/rus/news/2011/09/20/6600616/
      +# 
      +#
      +# From Philip Pizzey (2011-10-18):
      +# Today my Ukrainian colleagues have informed me that the
      +# Ukrainian parliament have decided that they will go to winter
      +# time this year after all.
      +#
      +# From Udo Schwedt (2011-10-18):
      +# As far as I understand, the recent change to the Ukranian time zone
      +# (Europe/Kiev) to introduce permanent daylight saving time (similar
      +# to Russia) was reverted today:
      +#
      +# 
      +# http://portal.rada.gov.ua/rada/control/en/publish/article/info_left?art_id=287324&cat_id=105995
      +# 
      +#
      +# Also reported by Alexander Bokovoy (2011-10-18) who also noted:
      +# The law documents themselves are at
      +#
      +# 
      +# http://w1.c1.rada.gov.ua/pls/zweb_n/webproc4_1?id=&pf3511=41484
      +# 
      +
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +# Most of Ukraine since 1970 has been like Kiev.
      +# "Kyiv" is the transliteration of the Ukrainian name, but
      +# "Kiev" is more common in English.
      +Zone Europe/Kiev	2:02:04 -	LMT	1880
      +			2:02:04	-	KMT	1924 May  2 # Kiev Mean Time
      +			2:00	-	EET	1930 Jun 21
      +			3:00	-	MSK	1941 Sep 20
      +			1:00	C-Eur	CE%sT	1943 Nov  6
      +			3:00	Russia	MSK/MSD	1990
      +			3:00	-	MSK	1990 Jul  1 2:00
      +			2:00	-	EET	1992
      +			2:00	E-Eur	EE%sT	1995
      +			2:00	EU	EE%sT
      +# Ruthenia used CET 1990/1991.
      +# "Uzhhorod" is the transliteration of the Ukrainian name, but
      +# "Uzhgorod" is more common in English.
      +Zone Europe/Uzhgorod	1:29:12 -	LMT	1890 Oct
      +			1:00	-	CET	1940
      +			1:00	C-Eur	CE%sT	1944 Oct
      +			1:00	1:00	CEST	1944 Oct 26
      +			1:00	-	CET	1945 Jun 29
      +			3:00	Russia	MSK/MSD	1990
      +			3:00	-	MSK	1990 Jul  1 2:00
      +			1:00	-	CET	1991 Mar 31 3:00
      +			2:00	-	EET	1992
      +			2:00	E-Eur	EE%sT	1995
      +			2:00	EU	EE%sT
      +# Zaporozh'ye and eastern Lugansk oblasts observed DST 1990/1991.
      +# "Zaporizhia" is the transliteration of the Ukrainian name, but
      +# "Zaporozh'ye" is more common in English.  Use the common English
      +# spelling, except omit the apostrophe as it is not allowed in
      +# portable Posix file names.
      +Zone Europe/Zaporozhye	2:20:40 -	LMT	1880
      +			2:20	-	CUT	1924 May  2 # Central Ukraine T
      +			2:00	-	EET	1930 Jun 21
      +			3:00	-	MSK	1941 Aug 25
      +			1:00	C-Eur	CE%sT	1943 Oct 25
      +			3:00	Russia	MSK/MSD	1991 Mar 31 2:00
      +			2:00	E-Eur	EE%sT	1995
      +			2:00	EU	EE%sT
      +# Central Crimea used Moscow time 1994/1997.
      +Zone Europe/Simferopol	2:16:24 -	LMT	1880
      +			2:16	-	SMT	1924 May  2 # Simferopol Mean T
      +			2:00	-	EET	1930 Jun 21
      +			3:00	-	MSK	1941 Nov
      +			1:00	C-Eur	CE%sT	1944 Apr 13
      +			3:00	Russia	MSK/MSD	1990
      +			3:00	-	MSK	1990 Jul  1 2:00
      +			2:00	-	EET	1992
      +# From Paul Eggert (2006-03-22):
      +# The _Economist_ (1994-05-28, p 45) reports that central Crimea switched
      +# from Kiev to Moscow time sometime after the January 1994 elections.
      +# Shanks (1999) says ``date of change uncertain'', but implies that it happened
      +# sometime between the 1994 DST switches.  Shanks & Pottenger simply say
      +# 1994-09-25 03:00, but that can't be right.  For now, guess it
      +# changed in May.
      +			2:00	E-Eur	EE%sT	1994 May
      +# From IATA SSIM (1994/1997), which also says that Kerch is still like Kiev.
      +			3:00	E-Eur	MSK/MSD	1996 Mar 31 3:00s
      +			3:00	1:00	MSD	1996 Oct 27 3:00s
      +# IATA SSIM (1997-09) says Crimea switched to EET/EEST.
      +# Assume it happened in March by not changing the clocks.
      +			3:00	Russia	MSK/MSD	1997
      +			3:00	-	MSK	1997 Mar lastSun 1:00u
      +			2:00	EU	EE%sT
      +
      +###############################################################################
      +
      +# One source shows that Bulgaria, Cyprus, Finland, and Greece observe DST from
      +# the last Sunday in March to the last Sunday in September in 1986.
      +# The source shows Romania changing a day later than everybody else.
      +#
      +# According to Bernard Sieloff's source, Poland is in the MET time zone but
      +# uses the WE DST rules.  The Western USSR uses EET+1 and ME DST rules.
      +# Bernard Sieloff's source claims Romania switches on the same day, but at
      +# 00:00 standard time (i.e., 01:00 DST).  It also claims that Turkey
      +# switches on the same day, but switches on at 01:00 standard time
      +# and off at 00:00 standard time (i.e., 01:00 DST)
      +
      +# ...
      +# Date: Wed, 28 Jan 87 16:56:27 -0100
      +# From: Tom Hofmann
      +# ...
      +#
      +# ...the European time rules are...standardized since 1981, when
      +# most European coun[tr]ies started DST.  Before that year, only
      +# a few countries (UK, France, Italy) had DST, each according
      +# to own national rules.  In 1981, however, DST started on
      +# 'Apr firstSun', and not on 'Mar lastSun' as in the following
      +# years...
      +# But also since 1981 there are some more national exceptions
      +# than listed in 'europe': Switzerland, for example, joined DST
      +# one year later, Denmark ended DST on 'Oct 1' instead of 'Sep
      +# lastSun' in 1981---I don't know how they handle now.
      +#
      +# Finally, DST ist always from 'Apr 1' to 'Oct 1' in the
      +# Soviet Union (as far as I know).
      +#
      +# Tom Hofmann, Scientific Computer Center, CIBA-GEIGY AG,
      +# 4002 Basle, Switzerland
      +# ...
      +
      +# ...
      +# Date: Wed, 4 Feb 87 22:35:22 +0100
      +# From: Dik T. Winter
      +# ...
      +#
      +# The information from Tom Hofmann is (as far as I know) not entirely correct.
      +# After a request from chongo at amdahl I tried to retrieve all information
      +# about DST in Europe.  I was able to find all from about 1969.
      +#
      +# ...standardization on DST in Europe started in about 1977 with switches on
      +# first Sunday in April and last Sunday in September...
      +# In 1981 UK joined Europe insofar that
      +# the starting day for both shifted to last Sunday in March.  And from 1982
      +# the whole of Europe used DST, with switch dates April 1 and October 1 in
      +# the Sov[i]et Union.  In 1985 the SU reverted to standard Europe[a]n switch
      +# dates...
      +#
      +# It should also be remembered that time-zones are not constants; e.g.
      +# Portugal switched in 1976 from MET (or CET) to WET with DST...
      +# Note also that though there were rules for switch dates not
      +# all countries abided to these dates, and many individual deviations
      +# occurred, though not since 1982 I believe.  Another note: it is always
      +# assumed that DST is 1 hour ahead of normal time, this need not be the
      +# case; at least in the Netherlands there have been times when DST was 2 hours
      +# in advance of normal time.
      +#
      +# ...
      +# dik t. winter, cwi, amsterdam, nederland
      +# ...
      +
      +# From Bob Devine (1988-01-28):
      +# ...
      +# Greece: Last Sunday in April to last Sunday in September (iffy on dates).
      +# Since 1978.  Change at midnight.
      +# ...
      +# Monaco: has same DST as France.
      +# ...
      diff --git a/jdk/test/sun/util/calendar/zi/tzdata/factory b/jdk/test/sun/util/calendar/zi/tzdata/factory
      new file mode 100644
      index 00000000000..53ca3aa5d31
      --- /dev/null
      +++ b/jdk/test/sun/util/calendar/zi/tzdata/factory
      @@ -0,0 +1,33 @@
      +#
      +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      +#  
      +# This code is free software; you can redistribute it and/or modify it
      +# under the terms of the GNU General Public License version 2 only, as
      +# published by the Free Software Foundation.  Oracle designates this
      +# particular file as subject to the "Classpath" exception as provided
      +# by Oracle in the LICENSE file that accompanied this code.
      +#  
      +# This code is distributed in the hope that it will be useful, but WITHOUT
      +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      +# version 2 for more details (a copy is included in the LICENSE file that
      +# accompanied this code).
      +#  
      +# You should have received a copy of the GNU General Public License version
      +# 2 along with this work; if not, write to the Free Software Foundation,
      +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      +#  
      +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      +# or visit www.oracle.com if you need additional information or have any
      +# questions.
      +#
      +# 
      +# This file is in the public domain, so clarified as of
      +# 2009-05-17 by Arthur David Olson.
      +
      +# For companies who don't want to put time zone specification in
      +# their installation procedures.  When users run date, they'll get the message.
      +# Also useful for the "comp.sources" version.
      +
      +# Zone	NAME	GMTOFF	RULES	FORMAT
      +Zone	Factory	0	- "Local time zone must be set--see zic manual page"
      diff --git a/jdk/test/sun/util/calendar/zi/tzdata/gmt b/jdk/test/sun/util/calendar/zi/tzdata/gmt
      new file mode 100644
      index 00000000000..0be31797d7f
      --- /dev/null
      +++ b/jdk/test/sun/util/calendar/zi/tzdata/gmt
      @@ -0,0 +1,27 @@
      +#
      +# Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
      +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      +#
      +# This code is free software; you can redistribute it and/or modify it
      +# under the terms of the GNU General Public License version 2 only, as
      +# published by the Free Software Foundation.  Oracle designates this
      +# particular file as subject to the "Classpath" exception as provided
      +# by Oracle in the LICENSE file that accompanied this code.
      +#
      +# This code is distributed in the hope that it will be useful, but WITHOUT
      +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      +# version 2 for more details (a copy is included in the LICENSE file that
      +# accompanied this code).
      +#
      +# You should have received a copy of the GNU General Public License version
      +# 2 along with this work; if not, write to the Free Software Foundation,
      +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      +#
      +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      +# or visit www.oracle.com if you need additional information or have any
      +# questions.
      +#
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	GMT		0:00	-	GMT
      diff --git a/jdk/test/sun/util/calendar/zi/tzdata/iso3166.tab b/jdk/test/sun/util/calendar/zi/tzdata/iso3166.tab
      new file mode 100644
      index 00000000000..fee3f33911a
      --- /dev/null
      +++ b/jdk/test/sun/util/calendar/zi/tzdata/iso3166.tab
      @@ -0,0 +1,299 @@
      +#
      +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      +#  
      +# This code is free software; you can redistribute it and/or modify it
      +# under the terms of the GNU General Public License version 2 only, as
      +# published by the Free Software Foundation.  Oracle designates this
      +# particular file as subject to the "Classpath" exception as provided
      +# by Oracle in the LICENSE file that accompanied this code.
      +#  
      +# This code is distributed in the hope that it will be useful, but WITHOUT
      +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      +# version 2 for more details (a copy is included in the LICENSE file that
      +# accompanied this code).
      +#  
      +# You should have received a copy of the GNU General Public License version
      +# 2 along with this work; if not, write to the Free Software Foundation,
      +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      +#  
      +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      +# or visit www.oracle.com if you need additional information or have any
      +# questions.
      +#
      +# 
      +# This file is in the public domain, so clarified as of
      +# 2009-05-17 by Arthur David Olson.
      +# ISO 3166 alpha-2 country codes
      +#
      +# From Paul Eggert (2006-09-27):
      +#
      +# This file contains a table with the following columns:
      +# 1.  ISO 3166-1 alpha-2 country code, current as of
      +#     ISO 3166-1 Newsletter VI-1 (2007-09-21).  See:
      +#     
      +#     ISO 3166 Maintenance agency (ISO 3166/MA)
      +#     .
      +# 2.  The usual English name for the country,
      +#     chosen so that alphabetic sorting of subsets produces helpful lists.
      +#     This is not the same as the English name in the ISO 3166 tables.
      +#
      +# Columns are separated by a single tab.
      +# The table is sorted by country code.
      +#
      +# Lines beginning with `#' are comments.
      +#
      +# From Arthur David Olson (2011-08-17):
      +# Resynchronized today with the ISO 3166 site (adding SS for South Sudan).
      +#
      +#country-
      +#code	country name
      +AD	Andorra
      +AE	United Arab Emirates
      +AF	Afghanistan
      +AG	Antigua & Barbuda
      +AI	Anguilla
      +AL	Albania
      +AM	Armenia
      +AO	Angola
      +AQ	Antarctica
      +AR	Argentina
      +AS	Samoa (American)
      +AT	Austria
      +AU	Australia
      +AW	Aruba
      +AX	Aaland Islands
      +AZ	Azerbaijan
      +BA	Bosnia & Herzegovina
      +BB	Barbados
      +BD	Bangladesh
      +BE	Belgium
      +BF	Burkina Faso
      +BG	Bulgaria
      +BH	Bahrain
      +BI	Burundi
      +BJ	Benin
      +BL	St Barthelemy
      +BM	Bermuda
      +BN	Brunei
      +BO	Bolivia
      +BQ	Bonaire Sint Eustatius & Saba
      +BR	Brazil
      +BS	Bahamas
      +BT	Bhutan
      +BV	Bouvet Island
      +BW	Botswana
      +BY	Belarus
      +BZ	Belize
      +CA	Canada
      +CC	Cocos (Keeling) Islands
      +CD	Congo (Dem. Rep.)
      +CF	Central African Rep.
      +CG	Congo (Rep.)
      +CH	Switzerland
      +CI	Cote d'Ivoire
      +CK	Cook Islands
      +CL	Chile
      +CM	Cameroon
      +CN	China
      +CO	Colombia
      +CR	Costa Rica
      +CU	Cuba
      +CV	Cape Verde
      +CW	Curacao
      +CX	Christmas Island
      +CY	Cyprus
      +CZ	Czech Republic
      +DE	Germany
      +DJ	Djibouti
      +DK	Denmark
      +DM	Dominica
      +DO	Dominican Republic
      +DZ	Algeria
      +EC	Ecuador
      +EE	Estonia
      +EG	Egypt
      +EH	Western Sahara
      +ER	Eritrea
      +ES	Spain
      +ET	Ethiopia
      +FI	Finland
      +FJ	Fiji
      +FK	Falkland Islands
      +FM	Micronesia
      +FO	Faroe Islands
      +FR	France
      +GA	Gabon
      +GB	Britain (UK)
      +GD	Grenada
      +GE	Georgia
      +GF	French Guiana
      +GG	Guernsey
      +GH	Ghana
      +GI	Gibraltar
      +GL	Greenland
      +GM	Gambia
      +GN	Guinea
      +GP	Guadeloupe
      +GQ	Equatorial Guinea
      +GR	Greece
      +GS	South Georgia & the South Sandwich Islands
      +GT	Guatemala
      +GU	Guam
      +GW	Guinea-Bissau
      +GY	Guyana
      +HK	Hong Kong
      +HM	Heard Island & McDonald Islands
      +HN	Honduras
      +HR	Croatia
      +HT	Haiti
      +HU	Hungary
      +ID	Indonesia
      +IE	Ireland
      +IL	Israel
      +IM	Isle of Man
      +IN	India
      +IO	British Indian Ocean Territory
      +IQ	Iraq
      +IR	Iran
      +IS	Iceland
      +IT	Italy
      +JE	Jersey
      +JM	Jamaica
      +JO	Jordan
      +JP	Japan
      +KE	Kenya
      +KG	Kyrgyzstan
      +KH	Cambodia
      +KI	Kiribati
      +KM	Comoros
      +KN	St Kitts & Nevis
      +KP	Korea (North)
      +KR	Korea (South)
      +KW	Kuwait
      +KY	Cayman Islands
      +KZ	Kazakhstan
      +LA	Laos
      +LB	Lebanon
      +LC	St Lucia
      +LI	Liechtenstein
      +LK	Sri Lanka
      +LR	Liberia
      +LS	Lesotho
      +LT	Lithuania
      +LU	Luxembourg
      +LV	Latvia
      +LY	Libya
      +MA	Morocco
      +MC	Monaco
      +MD	Moldova
      +ME	Montenegro
      +MF	St Martin (French part)
      +MG	Madagascar
      +MH	Marshall Islands
      +MK	Macedonia
      +ML	Mali
      +MM	Myanmar (Burma)
      +MN	Mongolia
      +MO	Macau
      +MP	Northern Mariana Islands
      +MQ	Martinique
      +MR	Mauritania
      +MS	Montserrat
      +MT	Malta
      +MU	Mauritius
      +MV	Maldives
      +MW	Malawi
      +MX	Mexico
      +MY	Malaysia
      +MZ	Mozambique
      +NA	Namibia
      +NC	New Caledonia
      +NE	Niger
      +NF	Norfolk Island
      +NG	Nigeria
      +NI	Nicaragua
      +NL	Netherlands
      +NO	Norway
      +NP	Nepal
      +NR	Nauru
      +NU	Niue
      +NZ	New Zealand
      +OM	Oman
      +PA	Panama
      +PE	Peru
      +PF	French Polynesia
      +PG	Papua New Guinea
      +PH	Philippines
      +PK	Pakistan
      +PL	Poland
      +PM	St Pierre & Miquelon
      +PN	Pitcairn
      +PR	Puerto Rico
      +PS	Palestine
      +PT	Portugal
      +PW	Palau
      +PY	Paraguay
      +QA	Qatar
      +RE	Reunion
      +RO	Romania
      +RS	Serbia
      +RU	Russia
      +RW	Rwanda
      +SA	Saudi Arabia
      +SB	Solomon Islands
      +SC	Seychelles
      +SD	Sudan
      +SE	Sweden
      +SG	Singapore
      +SH	St Helena
      +SI	Slovenia
      +SJ	Svalbard & Jan Mayen
      +SK	Slovakia
      +SL	Sierra Leone
      +SM	San Marino
      +SN	Senegal
      +SO	Somalia
      +SR	Suriname
      +SS	South Sudan
      +ST	Sao Tome & Principe
      +SV	El Salvador
      +SX	Sint Maarten
      +SY	Syria
      +SZ	Swaziland
      +TC	Turks & Caicos Is
      +TD	Chad
      +TF	French Southern & Antarctic Lands
      +TG	Togo
      +TH	Thailand
      +TJ	Tajikistan
      +TK	Tokelau
      +TL	East Timor
      +TM	Turkmenistan
      +TN	Tunisia
      +TO	Tonga
      +TR	Turkey
      +TT	Trinidad & Tobago
      +TV	Tuvalu
      +TW	Taiwan
      +TZ	Tanzania
      +UA	Ukraine
      +UG	Uganda
      +UM	US minor outlying islands
      +US	United States
      +UY	Uruguay
      +UZ	Uzbekistan
      +VA	Vatican City
      +VC	St Vincent
      +VE	Venezuela
      +VG	Virgin Islands (UK)
      +VI	Virgin Islands (US)
      +VN	Vietnam
      +VU	Vanuatu
      +WF	Wallis & Futuna
      +WS	Samoa (western)
      +YE	Yemen
      +YT	Mayotte
      +ZA	South Africa
      +ZM	Zambia
      +ZW	Zimbabwe
      diff --git a/jdk/test/sun/util/calendar/zi/tzdata/jdk11_backward b/jdk/test/sun/util/calendar/zi/tzdata/jdk11_backward
      new file mode 100644
      index 00000000000..5404ceaae4c
      --- /dev/null
      +++ b/jdk/test/sun/util/calendar/zi/tzdata/jdk11_backward
      @@ -0,0 +1,51 @@
      +#
      +# Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
      +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      +#
      +# This code is free software; you can redistribute it and/or modify it
      +# under the terms of the GNU General Public License version 2 only, as
      +# published by the Free Software Foundation.  Oracle designates this
      +# particular file as subject to the "Classpath" exception as provided
      +# by Oracle in the LICENSE file that accompanied this code.
      +#
      +# This code is distributed in the hope that it will be useful, but WITHOUT
      +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      +# version 2 for more details (a copy is included in the LICENSE file that
      +# accompanied this code).
      +#
      +# You should have received a copy of the GNU General Public License version
      +# 2 along with this work; if not, write to the Free Software Foundation,
      +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      +#
      +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      +# or visit www.oracle.com if you need additional information or have any
      +# questions.
      +#
      +# JDK 1.1.x compatible time zone IDs
      +#
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	SystemV	min	1973	-	Apr	lastSun	2:00	1:00	D
      +Rule	SystemV	min	1973	-	Oct	lastSun	2:00	0	S
      +Rule	SystemV	1974	only	-	Jan	6	2:00	1:00	D
      +Rule	SystemV	1974	only	-	Nov	lastSun	2:00	0	S
      +Rule	SystemV	1975	only	-	Feb	23	2:00	1:00	D
      +Rule	SystemV	1975	only	-	Oct	lastSun	2:00	0	S
      +Rule	SystemV	1976	max	-	Apr	lastSun	2:00	1:00	D
      +Rule	SystemV	1976	max	-	Oct	lastSun	2:00	0	S
      +
      +# Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
      +Zone	SystemV/AST4ADT	-4:00	SystemV		A%sT
      +Zone	SystemV/EST5EDT	-5:00	SystemV		E%sT
      +Zone	SystemV/CST6CDT	-6:00	SystemV		C%sT
      +Zone	SystemV/MST7MDT	-7:00	SystemV		M%sT
      +Zone	SystemV/PST8PDT	-8:00	SystemV		P%sT
      +Zone	SystemV/YST9YDT	-9:00	SystemV		Y%sT
      +Zone	SystemV/AST4	-4:00	-		AST
      +Zone	SystemV/EST5	-5:00	-		EST
      +Zone	SystemV/CST6	-6:00	-		CST
      +Zone	SystemV/MST7	-7:00	-		MST
      +Zone	SystemV/PST8	-8:00	-		PST
      +Zone	SystemV/YST9	-9:00	-		YST
      +Zone	SystemV/HST10	-10:00	-		HST
      diff --git a/jdk/test/sun/util/calendar/zi/tzdata/leapseconds b/jdk/test/sun/util/calendar/zi/tzdata/leapseconds
      new file mode 100644
      index 00000000000..ab6720ded58
      --- /dev/null
      +++ b/jdk/test/sun/util/calendar/zi/tzdata/leapseconds
      @@ -0,0 +1,123 @@
      +#
      +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      +#  
      +# This code is free software; you can redistribute it and/or modify it
      +# under the terms of the GNU General Public License version 2 only, as
      +# published by the Free Software Foundation.  Oracle designates this
      +# particular file as subject to the "Classpath" exception as provided
      +# by Oracle in the LICENSE file that accompanied this code.
      +#  
      +# This code is distributed in the hope that it will be useful, but WITHOUT
      +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      +# version 2 for more details (a copy is included in the LICENSE file that
      +# accompanied this code).
      +#  
      +# You should have received a copy of the GNU General Public License version
      +# 2 along with this work; if not, write to the Free Software Foundation,
      +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      +#  
      +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      +# or visit www.oracle.com if you need additional information or have any
      +# questions.
      +#
      +# 
      +# This file is in the public domain, so clarified as of
      +# 2009-05-17 by Arthur David Olson.
      +
      +# Allowance for leapseconds added to each timezone file.
      +
      +# The International Earth Rotation Service periodically uses leap seconds
      +# to keep UTC to within 0.9 s of UT1
      +# (which measures the true angular orientation of the earth in space); see
      +# Terry J Quinn, The BIPM and the accurate measure of time,
      +# Proc IEEE 79, 7 (July 1991), 894-905.
      +# There were no leap seconds before 1972, because the official mechanism
      +# accounting for the discrepancy between atomic time and the earth's rotation
      +# did not exist until the early 1970s.
      +
      +# The correction (+ or -) is made at the given time, so lines
      +# will typically look like:
      +#	Leap	YEAR	MON	DAY	23:59:60	+	R/S
      +# or
      +#	Leap	YEAR	MON	DAY	23:59:59	-	R/S
      +
      +# If the leapsecond is Rolling (R) the given time is local time
      +# If the leapsecond is Stationary (S) the given time is UTC
      +
      +# Leap	YEAR	MONTH	DAY	HH:MM:SS	CORR	R/S
      +Leap	1972	Jun	30	23:59:60	+	S
      +Leap	1972	Dec	31	23:59:60	+	S
      +Leap	1973	Dec	31	23:59:60	+	S
      +Leap	1974	Dec	31	23:59:60	+	S
      +Leap	1975	Dec	31	23:59:60	+	S
      +Leap	1976	Dec	31	23:59:60	+	S
      +Leap	1977	Dec	31	23:59:60	+	S
      +Leap	1978	Dec	31	23:59:60	+	S
      +Leap	1979	Dec	31	23:59:60	+	S
      +Leap	1981	Jun	30	23:59:60	+	S
      +Leap	1982	Jun	30	23:59:60	+	S
      +Leap	1983	Jun	30	23:59:60	+	S
      +Leap	1985	Jun	30	23:59:60	+	S
      +Leap	1987	Dec	31	23:59:60	+	S
      +Leap	1989	Dec	31	23:59:60	+	S
      +Leap	1990	Dec	31	23:59:60	+	S
      +Leap	1992	Jun	30	23:59:60	+	S
      +Leap	1993	Jun	30	23:59:60	+	S
      +Leap	1994	Jun	30	23:59:60	+	S
      +Leap	1995	Dec	31	23:59:60	+	S
      +Leap	1997	Jun	30	23:59:60	+	S
      +Leap	1998	Dec	31	23:59:60	+	S
      +Leap	2005	Dec	31	23:59:60	+	S
      +Leap	2008	Dec	31	23:59:60	+	S
      +Leap	2012	Jun	30	23:59:60	+	S
      +
      +# INTERNATIONAL EARTH ROTATION AND REFERENCE SYSTEMS SERVICE (IERS)
      +#
      +# SERVICE INTERNATIONAL DE LA ROTATION TERRESTRE ET DES SYSTEMES DE REFERENCE
      +#
      +#
      +# SERVICE DE LA ROTATION TERRESTRE
      +# OBSERVATOIRE DE PARIS
      +# 61, Av. de l'Observatoire 75014 PARIS (France)
      +# Tel.      : 33 (0) 1 40 51 22 26
      +# FAX       : 33 (0) 1 40 51 22 91
      +# e-mail    : (E-Mail Removed)
      +# http://hpiers.obspm.fr/eop-pc
      +#
      +# Paris, 5 January 2012
      +#
      +#
      +# Bulletin C 43
      +#
      +# To authorities responsible
      +# for the measurement and
      +# distribution of time
      +#
      +#
      +# UTC TIME STEP
      +# on the 1st of July 2012
      +#
      +#
      +# A positive leap second will be introduced at the end of June 2012.
      +# The sequence of dates of the UTC second markers will be:
      +#
      +#                          2012 June 30,     23h 59m 59s
      +#                          2012 June 30,     23h 59m 60s
      +#                          2012 July  1,      0h  0m  0s
      +#
      +# The difference between UTC and the International Atomic Time TAI is:
      +#
      +# from 2009 January 1, 0h UTC, to 2012 July 1  0h UTC  : UTC-TAI = - 34s
      +# from 2012 July 1,    0h UTC, until further notice    : UTC-TAI = - 35s
      +#
      +# Leap seconds can be introduced in UTC at the end of the months of December
      +# or June, depending on the evolution of UT1-TAI. Bulletin C is mailed every
      +# six months, either to announce a time step in UTC or to confirm that there
      +# will be no time step at the next possible date.
      +#
      +#
      +# Daniel GAMBIS
      +# Head
      +# Earth Orientation Center of IERS
      +# Observatoire de Paris, France
      diff --git a/jdk/test/sun/util/calendar/zi/tzdata/northamerica b/jdk/test/sun/util/calendar/zi/tzdata/northamerica
      new file mode 100644
      index 00000000000..c3033267404
      --- /dev/null
      +++ b/jdk/test/sun/util/calendar/zi/tzdata/northamerica
      @@ -0,0 +1,3258 @@
      +#
      +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      +#  
      +# This code is free software; you can redistribute it and/or modify it
      +# under the terms of the GNU General Public License version 2 only, as
      +# published by the Free Software Foundation.  Oracle designates this
      +# particular file as subject to the "Classpath" exception as provided
      +# by Oracle in the LICENSE file that accompanied this code.
      +#  
      +# This code is distributed in the hope that it will be useful, but WITHOUT
      +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      +# version 2 for more details (a copy is included in the LICENSE file that
      +# accompanied this code).
      +#  
      +# You should have received a copy of the GNU General Public License version
      +# 2 along with this work; if not, write to the Free Software Foundation,
      +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      +#  
      +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      +# or visit www.oracle.com if you need additional information or have any
      +# questions.
      +#
      +# 
      +# This file is in the public domain, so clarified as of
      +# 2009-05-17 by Arthur David Olson.
      +
      +# also includes Central America and the Caribbean
      +
      +# This data is by no means authoritative; if you think you know better,
      +# go ahead and edit the file (and please send any changes to
      +# tz@elsie.nci.nih.gov for general use in the future).
      +
      +# From Paul Eggert (1999-03-22):
      +# A reliable and entertaining source about time zones is
      +# Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
      +
      +###############################################################################
      +
      +# United States
      +
      +# From Paul Eggert (1999-03-31):
      +# Howse writes (pp 121-125) that time zones were invented by
      +# Professor Charles Ferdinand Dowd (1825-1904),
      +# Principal of Temple Grove Ladies' Seminary (Saratoga Springs, NY).
      +# His pamphlet ``A System of National Time for Railroads'' (1870)
      +# was the result of his proposals at the Convention of Railroad Trunk Lines
      +# in New York City (1869-10).  His 1870 proposal was based on Washington, DC,
      +# but in 1872-05 he moved the proposed origin to Greenwich.
      +# His proposal was adopted by the railroads on 1883-11-18 at 12:00,
      +# and the most of the country soon followed suit.
      +
      +# From Paul Eggert (2005-04-16):
      +# That 1883 transition occurred at 12:00 new time, not at 12:00 old time.
      +# See p 46 of David Prerau, Seize the daylight, Thunder's Mouth Press (2005).
      +
      +# From Paul Eggert (2006-03-22):
      +# A good source for time zone historical data in the US is
      +# Thomas G. Shanks, The American Atlas (5th edition),
      +# San Diego: ACS Publications, Inc. (1991).
      +# Make sure you have the errata sheet; the book is somewhat useless without it.
      +# It is the source for most of the pre-1991 US entries below.
      +
      +# From Paul Eggert (2001-03-06):
      +# Daylight Saving Time was first suggested as a joke by Benjamin Franklin
      +# in his whimsical essay ``An Economical Project for Diminishing the Cost
      +# of Light'' published in the Journal de Paris (1784-04-26).
      +# Not everyone is happy with the results:
      +#
      +#	I don't really care how time is reckoned so long as there is some
      +#	agreement about it, but I object to being told that I am saving
      +#	daylight when my reason tells me that I am doing nothing of the kind.
      +#	I even object to the implication that I am wasting something
      +#	valuable if I stay in bed after the sun has risen.  As an admirer
      +#	of moonlight I resent the bossy insistence of those who want to
      +#	reduce my time for enjoying it.  At the back of the Daylight Saving
      +#	scheme I detect the bony, blue-fingered hand of Puritanism, eager
      +#	to push people into bed earlier, and get them up earlier, to make
      +#	them healthy, wealthy and wise in spite of themselves.
      +#
      +#	-- Robertson Davies, The diary of Samuel Marchbanks,
      +#	   Clarke, Irwin (1947), XIX, Sunday
      +#
      +# For more about the first ten years of DST in the United States, see
      +# Robert Garland's 
      +# Ten years of daylight saving from the Pittsburgh standpoint
      +# (Carnegie Library of Pittsburgh, 1927).
      +#
      +# Shanks says that DST was called "War Time" in the US in 1918 and 1919.
      +# However, DST was imposed by the Standard Time Act of 1918, which
      +# was the first nationwide legal time standard, and apparently
      +# time was just called "Standard Time" or "Daylight Saving Time".
      +
      +# From Arthur David Olson:
      +# US Daylight Saving Time ended on the last Sunday of *October* in 1974.
      +# See, for example, the front page of the Saturday, 1974-10-26
      +# and Sunday, 1974-10-27 editions of the Washington Post.
      +
      +# From Arthur David Olson:
      +# Before the Uniform Time Act of 1966 took effect in 1967, observance of
      +# Daylight Saving Time in the US was by local option, except during wartime.
      +
      +# From Arthur David Olson (2000-09-25):
      +# Last night I heard part of a rebroadcast of a 1945 Arch Oboler radio drama.
      +# In the introduction, Oboler spoke of "Eastern Peace Time."
      +# An AltaVista search turned up
      +# :
      +# "When the time is announced over the radio now, it is 'Eastern Peace
      +# Time' instead of the old familiar 'Eastern War Time.'  Peace is wonderful."
      +#  (August 1945) by way of confirmation.
      +
      +# From Joseph Gallant citing
      +# George H. Douglas, _The Early Days of Radio Broadcasting_ (1987):
      +# At 7 P.M. (Eastern War Time) [on 1945-08-14], the networks were set
      +# to switch to London for Attlee's address, but the American people
      +# never got to hear his speech live. According to one press account,
      +# CBS' Bob Trout was first to announce the word of Japan's surrender,
      +# but a few seconds later, NBC, ABC and Mutual also flashed the word
      +# of surrender, all of whom interrupting the bells of Big Ben in
      +# London which were to precede Mr. Attlee's speech.
      +
      +# From Paul Eggert (2003-02-09): It was Robert St John, not Bob Trout.  From
      +# Myrna Oliver's obituary of St John on page B16 of today's Los Angeles Times:
      +#
      +# ... a war-weary U.S. clung to radios, awaiting word of Japan's surrender.
      +# Any announcement from Asia would reach St. John's New York newsroom on a
      +# wire service teletype machine, which had prescribed signals for major news.
      +# Associated Press, for example, would ring five bells before spewing out
      +# typed copy of an important story, and 10 bells for news "of transcendental
      +# importance."
      +#
      +# On Aug. 14, stalling while talking steadily into the NBC networks' open
      +# microphone, St. John heard five bells and waited only to hear a sixth bell,
      +# before announcing confidently: "Ladies and gentlemen, World War II is over.
      +# The Japanese have agreed to our surrender terms."
      +#
      +# He had scored a 20-second scoop on other broadcasters.
      +
      +# From Arthur David Olson (2005-08-22):
      +# Paul has been careful to use the "US" rules only in those locations
      +# that are part of the United States; this reflects the real scope of
      +# U.S. government action.  So even though the "US" rules have changed
      +# in the latest release, other countries won't be affected.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	US	1918	1919	-	Mar	lastSun	2:00	1:00	D
      +Rule	US	1918	1919	-	Oct	lastSun	2:00	0	S
      +Rule	US	1942	only	-	Feb	9	2:00	1:00	W # War
      +Rule	US	1945	only	-	Aug	14	23:00u	1:00	P # Peace
      +Rule	US	1945	only	-	Sep	30	2:00	0	S
      +Rule	US	1967	2006	-	Oct	lastSun	2:00	0	S
      +Rule	US	1967	1973	-	Apr	lastSun	2:00	1:00	D
      +Rule	US	1974	only	-	Jan	6	2:00	1:00	D
      +Rule	US	1975	only	-	Feb	23	2:00	1:00	D
      +Rule	US	1976	1986	-	Apr	lastSun	2:00	1:00	D
      +Rule	US	1987	2006	-	Apr	Sun>=1	2:00	1:00	D
      +Rule	US	2007	max	-	Mar	Sun>=8	2:00	1:00	D
      +Rule	US	2007	max	-	Nov	Sun>=1	2:00	0	S
      +
      +# From Arthur David Olson, 2005-12-19
      +# We generate the files specified below to guard against old files with
      +# obsolete information being left in the time zone binary directory.
      +# We limit the list to names that have appeared in previous versions of
      +# this time zone package.
      +# We do these as separate Zones rather than as Links to avoid problems if
      +# a particular place changes whether it observes DST.
      +# We put these specifications here in the northamerica file both to
      +# increase the chances that they'll actually get compiled and to
      +# avoid the need to duplicate the US rules in another file.
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	EST		 -5:00	-	EST
      +Zone	MST		 -7:00	-	MST
      +Zone	HST		-10:00	-	HST
      +Zone	EST5EDT		 -5:00	US	E%sT
      +Zone	CST6CDT		 -6:00	US	C%sT
      +Zone	MST7MDT		 -7:00	US	M%sT
      +Zone	PST8PDT		 -8:00	US	P%sT
      +
      +# From Bob Devine (1988-01-28):
      +# ...Alaska (and Hawaii) had the timezone names changed in 1967.
      +#    old			 new
      +#    Pacific Standard Time(PST)  -same-
      +#    Yukon Standard Time(YST)    -same-
      +#    Central Alaska S.T. (CAT)   Alaska-Hawaii St[an]dard Time (AHST)
      +#    Nome Standard Time (NT)     Bering Standard Time (BST)
      +#
      +# ...Alaska's timezone lines were redrawn in 1983 to give only 2 tz.
      +#    The YST zone now covers nearly all of the state, AHST just part
      +#    of the Aleutian islands.   No DST.
      +
      +# From Paul Eggert (1995-12-19):
      +# The tables below use `NST', not `NT', for Nome Standard Time.
      +# I invented `CAWT' for Central Alaska War Time.
      +
      +# From U. S. Naval Observatory (1989-01-19):
      +# USA  EASTERN       5 H  BEHIND UTC    NEW YORK, WASHINGTON
      +# USA  EASTERN       4 H  BEHIND UTC    APR 3 - OCT 30
      +# USA  CENTRAL       6 H  BEHIND UTC    CHICAGO, HOUSTON
      +# USA  CENTRAL       5 H  BEHIND UTC    APR 3 - OCT 30
      +# USA  MOUNTAIN      7 H  BEHIND UTC    DENVER
      +# USA  MOUNTAIN      6 H  BEHIND UTC    APR 3 - OCT 30
      +# USA  PACIFIC       8 H  BEHIND UTC    L.A., SAN FRANCISCO
      +# USA  PACIFIC       7 H  BEHIND UTC    APR 3 - OCT 30
      +# USA  ALASKA STD    9 H  BEHIND UTC    MOST OF ALASKA     (AKST)
      +# USA  ALASKA STD    8 H  BEHIND UTC    APR 3 - OCT 30 (AKDT)
      +# USA  ALEUTIAN     10 H  BEHIND UTC    ISLANDS WEST OF 170W
      +# USA  - " -         9 H  BEHIND UTC    APR 3 - OCT 30
      +# USA  HAWAII       10 H  BEHIND UTC
      +# USA  BERING       11 H  BEHIND UTC    SAMOA, MIDWAY
      +
      +# From Arthur David Olson (1989-01-21):
      +# The above dates are for 1988.
      +# Note the "AKST" and "AKDT" abbreviations, the claim that there's
      +# no DST in Samoa, and the claim that there is DST in Alaska and the
      +# Aleutians.
      +
      +# From Arthur David Olson (1988-02-13):
      +# Legal standard time zone names, from United States Code (1982 Edition and
      +# Supplement III), Title 15, Chapter 6, Section 260 and forward.  First, names
      +# up to 1967-04-01 (when most provisions of the Uniform Time Act of 1966
      +# took effect), as explained in sections 263 and 261:
      +#	(none)
      +#	United States standard eastern time
      +#	United States standard mountain time
      +#	United States standard central time
      +#	United States standard Pacific time
      +#	(none)
      +#	United States standard Alaska time
      +#	(none)
      +# Next, names from 1967-04-01 until 1983-11-30 (the date for
      +# public law 98-181):
      +#	Atlantic standard time
      +#	eastern standard time
      +#	central standard time
      +#	mountain standard time
      +#	Pacific standard time
      +#	Yukon standard time
      +#	Alaska-Hawaii standard time
      +#	Bering standard time
      +# And after 1983-11-30:
      +#	Atlantic standard time
      +#	eastern standard time
      +#	central standard time
      +#	mountain standard time
      +#	Pacific standard time
      +#	Alaska standard time
      +#	Hawaii-Aleutian standard time
      +#	Samoa standard time
      +# The law doesn't give abbreviations.
      +#
      +# From Paul Eggert (2000-01-08), following a heads-up from Rives McDow:
      +# Public law 106-564 (2000-12-23) introduced the abbreviation
      +# "Chamorro Standard Time" for time in Guam and the Northern Marianas.
      +# See the file "australasia".
      +
      +# From Arthur David Olson, 2005-08-09
      +# The following was signed into law on 2005-08-08.
      +#
      +# H.R. 6, Energy Policy Act of 2005, SEC. 110. DAYLIGHT SAVINGS.
      +#   (a) Amendment- Section 3(a) of the Uniform Time Act of 1966 (15
      +#   U.S.C. 260a(a)) is amended--
      +#     (1) by striking `first Sunday of April' and inserting `second
      +#     Sunday of March'; and
      +#     (2) by striking `last Sunday of October' and inserting `first
      +#     Sunday of November'.
      +#   (b) Effective Date- Subsection (a) shall take effect 1 year after the
      +#   date of enactment of this Act or March 1, 2007, whichever is later.
      +#   (c) Report to Congress- Not later than 9 months after the effective
      +#   date stated in subsection (b), the Secretary shall report to Congress
      +#   on the impact of this section on energy consumption in the United
      +#   States.
      +#   (d) Right to Revert- Congress retains the right to revert the
      +#   Daylight Saving Time back to the 2005 time schedules once the
      +#   Department study is complete.
      +
      +# US eastern time, represented by New York
      +
      +# Connecticut, Delaware, District of Columbia, most of Florida,
      +# Georgia, southeast Indiana (Dearborn and Ohio counties), eastern Kentucky
      +# (except America/Kentucky/Louisville below), Maine, Maryland, Massachusetts,
      +# New Hampshire, New Jersey, New York, North Carolina, Ohio,
      +# Pennsylvania, Rhode Island, South Carolina, eastern Tennessee,
      +# Vermont, Virginia, West Virginia
      +
      +# From Dave Cantor (2004-11-02):
      +# Early this summer I had the occasion to visit the Mount Washington
      +# Observatory weather station atop (of course!) Mount Washington [, NH]....
      +# One of the staff members said that the station was on Eastern Standard Time
      +# and didn't change their clocks for Daylight Saving ... so that their
      +# reports will always have times which are 5 hours behind UTC.
      +
      +# From Paul Eggert (2005-08-26):
      +# According to today's Huntsville Times
      +# 
      +# a few towns on Alabama's "eastern border with Georgia, such as Phenix City
      +# in Russell County, Lanett in Chambers County and some towns in Lee County,
      +# set their watches and clocks on Eastern time."  It quotes H.H. "Bubba"
      +# Roberts, city administrator in Phenix City. as saying "We are in the Central
      +# time zone, but we do go by the Eastern time zone because so many people work
      +# in Columbus."
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
      +Rule	NYC	1920	only	-	Mar	lastSun	2:00	1:00	D
      +Rule	NYC	1920	only	-	Oct	lastSun	2:00	0	S
      +Rule	NYC	1921	1966	-	Apr	lastSun	2:00	1:00	D
      +Rule	NYC	1921	1954	-	Sep	lastSun	2:00	0	S
      +Rule	NYC	1955	1966	-	Oct	lastSun	2:00	0	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/New_York	-4:56:02 -	LMT	1883 Nov 18 12:03:58
      +			-5:00	US	E%sT	1920
      +			-5:00	NYC	E%sT	1942
      +			-5:00	US	E%sT	1946
      +			-5:00	NYC	E%sT	1967
      +			-5:00	US	E%sT
      +
      +# US central time, represented by Chicago
      +
      +# Alabama, Arkansas, Florida panhandle (Bay, Calhoun, Escambia,
      +# Gulf, Holmes, Jackson, Okaloosa, Santa Rosa, Walton, and
      +# Washington counties), Illinois, western Indiana
      +# (Gibson, Jasper, Lake, LaPorte, Newton, Porter, Posey, Spencer,
      +# Vanderburgh, and Warrick counties), Iowa, most of Kansas, western
      +# Kentucky, Louisiana, Minnesota, Mississippi, Missouri, eastern
      +# Nebraska, eastern North Dakota, Oklahoma, eastern South Dakota,
      +# western Tennessee, most of Texas, Wisconsin
      +
      +# From Larry M. Smith (2006-04-26) re Wisconsin:
      +# http://www.legis.state.wi.us/statutes/Stat0175.pdf ...
      +# is currently enforced at the 01:00 time of change.  Because the local
      +# "bar time" in the state corresponds to 02:00, a number of citations
      +# are issued for the "sale of class 'B' alcohol after prohibited
      +# hours" within the deviated hour of this change every year....
      +#
      +# From Douglas R. Bomberg (2007-03-12):
      +# Wisconsin has enacted (nearly eleventh-hour) legislation to get WI
      +# Statue 175 closer in synch with the US Congress' intent....
      +# http://www.legis.state.wi.us/2007/data/acts/07Act3.pdf
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
      +Rule	Chicago	1920	only	-	Jun	13	2:00	1:00	D
      +Rule	Chicago	1920	1921	-	Oct	lastSun	2:00	0	S
      +Rule	Chicago	1921	only	-	Mar	lastSun	2:00	1:00	D
      +Rule	Chicago	1922	1966	-	Apr	lastSun	2:00	1:00	D
      +Rule	Chicago	1922	1954	-	Sep	lastSun	2:00	0	S
      +Rule	Chicago	1955	1966	-	Oct	lastSun	2:00	0	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Chicago	-5:50:36 -	LMT	1883 Nov 18 12:09:24
      +			-6:00	US	C%sT	1920
      +			-6:00	Chicago	C%sT	1936 Mar  1 2:00
      +			-5:00	-	EST	1936 Nov 15 2:00
      +			-6:00	Chicago	C%sT	1942
      +			-6:00	US	C%sT	1946
      +			-6:00	Chicago	C%sT	1967
      +			-6:00	US	C%sT
      +# Oliver County, ND switched from mountain to central time on 1992-10-25.
      +Zone America/North_Dakota/Center -6:45:12 - LMT	1883 Nov 18 12:14:48
      +			-7:00	US	M%sT	1992 Oct 25 02:00
      +			-6:00	US	C%sT
      +# Morton County, ND, switched from mountain to central time on
      +# 2003-10-26, except for the area around Mandan which was already central time.
      +# See .
      +# Officially this switch also included part of Sioux County, and
      +# Jones, Mellette, and Todd Counties in South Dakota;
      +# but in practice these other counties were already observing central time.
      +# See .
      +Zone America/North_Dakota/New_Salem -6:45:39 - LMT 1883 Nov 18 12:14:21
      +			-7:00	US	M%sT	2003 Oct 26 02:00
      +			-6:00	US	C%sT
      +
      +# From Josh Findley (2011-01-21):
      +# ...it appears that Mercer County, North Dakota, changed from the
      +# mountain time zone to the central time zone at the last transition from
      +# daylight-saving to standard time (on Nov. 7, 2010):
      +# 
      +# http://www.gpo.gov/fdsys/pkg/FR-2010-09-29/html/2010-24376.htm
      +# 
      +# 
      +# http://www.bismarcktribune.com/news/local/article_1eb1b588-c758-11df-b472-001cc4c03286.html
      +# 
      +
      +# From Andy Lipscomb (2011-01-24):
      +# ...according to the Census Bureau, the largest city is Beulah (although
      +# it's commonly referred to as Beulah-Hazen, with Hazen being the next
      +# largest city in Mercer County).  Google Maps places Beulah's city hall
      +# at 4715'51" north, 10146'40" west, which yields an offset of 6h47'07".
      +
      +Zone America/North_Dakota/Beulah -6:47:07 - LMT 1883 Nov 18 12:12:53
      +			-7:00	US	M%sT	2010 Nov  7 2:00
      +			-6:00	US	C%sT
      +
      +# US mountain time, represented by Denver
      +#
      +# Colorado, far western Kansas, Montana, western
      +# Nebraska, Nevada border (Jackpot, Owyhee, and Mountain City),
      +# New Mexico, southwestern North Dakota,
      +# western South Dakota, far western Texas (El Paso County, Hudspeth County,
      +# and Pine Springs and Nickel Creek in Culberson County), Utah, Wyoming
      +#
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
      +Rule	Denver	1920	1921	-	Mar	lastSun	2:00	1:00	D
      +Rule	Denver	1920	only	-	Oct	lastSun	2:00	0	S
      +Rule	Denver	1921	only	-	May	22	2:00	0	S
      +Rule	Denver	1965	1966	-	Apr	lastSun	2:00	1:00	D
      +Rule	Denver	1965	1966	-	Oct	lastSun	2:00	0	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Denver	-6:59:56 -	LMT	1883 Nov 18 12:00:04
      +			-7:00	US	M%sT	1920
      +			-7:00	Denver	M%sT	1942
      +			-7:00	US	M%sT	1946
      +			-7:00	Denver	M%sT	1967
      +			-7:00	US	M%sT
      +
      +# US Pacific time, represented by Los Angeles
      +#
      +# California, northern Idaho (Benewah, Bonner, Boundary, Clearwater,
      +# Idaho, Kootenai, Latah, Lewis, Nez Perce, and Shoshone counties,
      +# and the northern three-quarters of Idaho county),
      +# most of Nevada, most of Oregon, and Washington
      +#
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
      +Rule	CA	1948	only	-	Mar	14	2:00	1:00	D
      +Rule	CA	1949	only	-	Jan	 1	2:00	0	S
      +Rule	CA	1950	1966	-	Apr	lastSun	2:00	1:00	D
      +Rule	CA	1950	1961	-	Sep	lastSun	2:00	0	S
      +Rule	CA	1962	1966	-	Oct	lastSun	2:00	0	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Los_Angeles -7:52:58 -	LMT	1883 Nov 18 12:07:02
      +			-8:00	US	P%sT	1946
      +			-8:00	CA	P%sT	1967
      +			-8:00	US	P%sT
      +
      +# Alaska
      +# AK%sT is the modern abbreviation for -9:00 per USNO.
      +#
      +# From Paul Eggert (2001-05-30):
      +# Howse writes that Alaska switched from the Julian to the Gregorian calendar,
      +# and from east-of-GMT to west-of-GMT days, when the US bought it from Russia.
      +# This was on 1867-10-18, a Friday; the previous day was 1867-10-06 Julian,
      +# also a Friday.  Include only the time zone part of this transition,
      +# ignoring the switch from Julian to Gregorian, since we can't represent
      +# the Julian calendar.
      +#
      +# As far as we know, none of the exact locations mentioned below were
      +# permanently inhabited in 1867 by anyone using either calendar.
      +# (Yakutat was colonized by the Russians in 1799, but the settlement
      +# was destroyed in 1805 by a Yakutat-kon war party.)  However, there
      +# were nearby inhabitants in some cases and for our purposes perhaps
      +# it's best to simply use the official transition.
      +#
      +
      +# From Steve Ferguson (2011-01-31):
      +# The author lives in Alaska and many of the references listed are only
      +# available to Alaskan residents.
      +#
      +# 
      +# http://www.alaskahistoricalsociety.org/index.cfm?section=discover%20alaska&page=Glimpses%20of%20the%20Past&viewpost=2&ContentId=98
      +# 
      +
      +# From Arthur David Olson (2011-02-01):
      +# Here's database-relevant material from the 2001 "Alaska History" article:
      +#
      +# On September 20 [1979]...DOT...officials decreed that on April 27,
      +# 1980, Juneau and other nearby communities would move to Yukon Time.
      +# Sitka, Petersburg, Wrangell, and Ketchikan, however, would remain on
      +# Pacific Time.
      +#
      +# ...on September 22, 1980, DOT Secretary Neil E. Goldschmidt rescinded the
      +# Department's September 1979 decision. Juneau and other communities in
      +# northern Southeast reverted to Pacific Time on October 26.
      +#
      +# On October 28 [1983]...the Metlakatla Indian Community Council voted
      +# unanimously to keep the reservation on Pacific Time.
      +#
      +# According to DOT official Joanne Petrie, Indian reservations are not
      +# bound to follow time zones imposed by neighboring jurisdictions.
      +#
      +# (The last is consistent with how the database now handles the Navajo
      +# Nation.)
      +
      +# From Arthur David Olson (2011-02-09):
      +# I just spoke by phone with a staff member at the Metlakatla Indian
      +# Community office (using contact information available at
      +# 
      +# http://www.commerce.state.ak.us/dca/commdb/CIS.cfm?Comm_Boro_name=Metlakatla
      +# ).
      +# It's shortly after 1:00 here on the east coast of the United States;
      +# the staffer said it was shortly after 10:00 there. When I asked whether
      +# that meant they were on Pacific time, they said no--they were on their
      +# own time. I asked about daylight saving; they said it wasn't used. I
      +# did not inquire about practices in the past.
      +
      +# From Arthur David Olson (2011-08-17):
      +# For lack of better information, assume that Metlakatla's
      +# abandonment of use of daylight saving resulted from the 1983 vote.
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Juneau	 15:02:19 -	LMT	1867 Oct 18
      +			 -8:57:41 -	LMT	1900 Aug 20 12:00
      +			 -8:00	-	PST	1942
      +			 -8:00	US	P%sT	1946
      +			 -8:00	-	PST	1969
      +			 -8:00	US	P%sT	1980 Apr 27 2:00
      +			 -9:00	US	Y%sT	1980 Oct 26 2:00
      +			 -8:00	US	P%sT	1983 Oct 30 2:00
      +			 -9:00	US	Y%sT	1983 Nov 30
      +			 -9:00	US	AK%sT
      +Zone America/Sitka	 14:58:47 -	LMT	1867 Oct 18
      +			 -9:01:13 -	LMT	1900 Aug 20 12:00
      +			 -8:00	-	PST	1942
      +			 -8:00	US	P%sT	1946
      +			 -8:00	-	PST	1969
      +			 -8:00	US	P%sT	1983 Oct 30 2:00
      +			 -9:00	US	Y%sT	1983 Nov 30
      +			 -9:00	US	AK%sT
      +Zone America/Metlakatla	 15:13:42 -	LMT	1867 Oct 18
      +			 -8:46:18 -	LMT	1900 Aug 20 12:00
      +			 -8:00	-	PST	1942
      +			 -8:00	US	P%sT	1946
      +			 -8:00	-	PST	1969
      +			 -8:00	US	P%sT	1983 Oct 30 2:00
      +			 -8:00	-	MeST
      +Zone America/Yakutat	 14:41:05 -	LMT	1867 Oct 18
      +			 -9:18:55 -	LMT	1900 Aug 20 12:00
      +			 -9:00	-	YST	1942
      +			 -9:00	US	Y%sT	1946
      +			 -9:00	-	YST	1969
      +			 -9:00	US	Y%sT	1983 Nov 30
      +			 -9:00	US	AK%sT
      +Zone America/Anchorage	 14:00:24 -	LMT	1867 Oct 18
      +			 -9:59:36 -	LMT	1900 Aug 20 12:00
      +			-10:00	-	CAT	1942
      +			-10:00	US	CAT/CAWT 1945 Aug 14 23:00u
      +			-10:00	US	CAT/CAPT 1946 # Peace
      +			-10:00	-	CAT	1967 Apr
      +			-10:00	-	AHST	1969
      +			-10:00	US	AH%sT	1983 Oct 30 2:00
      +			 -9:00	US	Y%sT	1983 Nov 30
      +			 -9:00	US	AK%sT
      +Zone America/Nome	 12:58:21 -	LMT	1867 Oct 18
      +			-11:01:38 -	LMT	1900 Aug 20 12:00
      +			-11:00	-	NST	1942
      +			-11:00	US	N%sT	1946
      +			-11:00	-	NST	1967 Apr
      +			-11:00	-	BST	1969
      +			-11:00	US	B%sT	1983 Oct 30 2:00
      +			 -9:00	US	Y%sT	1983 Nov 30
      +			 -9:00	US	AK%sT
      +Zone America/Adak	 12:13:21 -	LMT	1867 Oct 18
      +			-11:46:38 -	LMT	1900 Aug 20 12:00
      +			-11:00	-	NST	1942
      +			-11:00	US	N%sT	1946
      +			-11:00	-	NST	1967 Apr
      +			-11:00	-	BST	1969
      +			-11:00	US	B%sT	1983 Oct 30 2:00
      +			-10:00	US	AH%sT	1983 Nov 30
      +			-10:00	US	HA%sT
      +# The following switches don't quite make our 1970 cutoff.
      +#
      +# Shanks writes that part of southwest Alaska (e.g. Aniak)
      +# switched from -11:00 to -10:00 on 1968-09-22 at 02:00,
      +# and another part (e.g. Akiak) made the same switch five weeks later.
      +#
      +# From David Flater (2004-11-09):
      +# In e-mail, 2004-11-02, Ray Hudson, historian/liaison to the Unalaska
      +# Historic Preservation Commission, provided this information, which
      +# suggests that Unalaska deviated from statutory time from early 1967
      +# possibly until 1983:
      +#
      +#  Minutes of the Unalaska City Council Meeting, January 10, 1967:
      +#  "Except for St. Paul and Akutan, Unalaska is the only important
      +#  location not on Alaska Standard Time.  The following resolution was
      +#  made by William Robinson and seconded by Henry Swanson:  Be it
      +#  resolved that the City of Unalaska hereby goes to Alaska Standard
      +#  Time as of midnight Friday, January 13, 1967 (1 A.M. Saturday,
      +#  January 14, Alaska Standard Time.)  This resolution was passed with
      +#  three votes for and one against."
      +
      +# Hawaii
      +
      +# From Arthur David Olson (2010-12-09):
      +# "Hawaiian Time" by Robert C. Schmitt and Doak C. Cox appears on pages 207-225
      +# of volume 26 of The Hawaiian Journal of History (1992). As of 2010-12-09,
      +# the article is available at
      +# 
      +# http://evols.library.manoa.hawaii.edu/bitstream/10524/239/2/JL26215.pdf
      +# 
      +# and indicates that standard time was adopted effective noon, January
      +# 13, 1896 (page 218), that in "1933, the Legislature decreed daylight
      +# saving for the period between the last Sunday of each April and the
      +# last Sunday of each September, but less than a month later repealed the
      +# act," (page 220), that year-round daylight saving time was in effect
      +# from 1942-02-09 to 1945-09-30 (page 221, with no time of day given for
      +# when clocks changed) and that clocks were changed by 30 minutes
      +# effective the second Sunday of June, 1947 (page 219, with no time of
      +# day given for when clocks changed). A footnote for the 1933 changes
      +# cites Session Laws of Hawaii 1933, "Act. 90 (approved 26 Apr. 1933)
      +# and Act 163 (approved 21 May 1933)."
      +
      +# From Arthur David Olson (2011-01-19):
      +# The following is from "Laws of the Territory of Hawaii Passed by the
      +# Seventeenth Legislature: Regular Session 1933," available (as of
      +# 2011-01-19) at American University's Pence Law Library. Page 85: "Act
      +# 90...At 2 o'clock ante meridian of the last Sunday in April of each
      +# year, the standard time of this Territory shall be advanced one
      +# hour...This Act shall take effect upon its approval. Approved this 26th
      +# day of April, A. D. 1933. LAWRENCE M JUDD, Governor of the Territory of
      +# Hawaii." Page 172:  "Act 163...Act 90 of the Session Laws of 1933 is
      +# hereby repealed...This Act shall take effect upon its approval, upon
      +# which date the standard time of this Territory shall be restored to
      +# that existing immediately prior to the taking effect of said Act 90.
      +# Approved this 21st day of May, A. D. 1933. LAWRENCE M. JUDD, Governor
      +# of the Territory of Hawaii."
      +#
      +# Note that 1933-05-21 was a Sunday.
      +# We're left to guess the time of day when Act 163 was approved; guess noon.
      +
      +Zone Pacific/Honolulu	-10:31:26 -	LMT	1896 Jan 13 12:00 #Schmitt&Cox
      +			-10:30	-	HST	1933 Apr 30 2:00 #Laws 1933
      +			-10:30	1:00	HDT	1933 May 21 12:00 #Laws 1933+12
      +			-10:30	-	HST	1942 Feb 09 2:00 #Schmitt&Cox+2
      +			-10:30	1:00	HDT	1945 Sep 30 2:00 #Schmitt&Cox+2
      +			-10:30	-	HST	1947 Jun  8 2:00 #Schmitt&Cox+2
      +			-10:00	-	HST
      +
      +# Now we turn to US areas that have diverged from the consensus since 1970.
      +
      +# Arizona mostly uses MST.
      +
      +# From Paul Eggert (2002-10-20):
      +#
      +# The information in the rest of this paragraph is derived from the
      +# 
      +# Daylight Saving Time web page (2002-01-23) maintained by the
      +# Arizona State Library, Archives and Public Records.
      +# Between 1944-01-01 and 1944-04-01 the State of Arizona used standard
      +# time, but by federal law railroads, airlines, bus lines, military
      +# personnel, and some engaged in interstate commerce continued to
      +# observe war (i.e., daylight saving) time.  The 1944-03-17 Phoenix
      +# Gazette says that was the date the law changed, and that 04-01 was
      +# the date the state's clocks would change.  In 1945 the State of
      +# Arizona used standard time all year, again with exceptions only as
      +# mandated by federal law.  Arizona observed DST in 1967, but Arizona
      +# Laws 1968, ch. 183 (effective 1968-03-21) repealed DST.
      +#
      +# Shanks says the 1944 experiment came to an end on 1944-03-17.
      +# Go with the Arizona State Library instead.
      +
      +Zone America/Phoenix	-7:28:18 -	LMT	1883 Nov 18 11:31:42
      +			-7:00	US	M%sT	1944 Jan  1 00:01
      +			-7:00	-	MST	1944 Apr  1 00:01
      +			-7:00	US	M%sT	1944 Oct  1 00:01
      +			-7:00	-	MST	1967
      +			-7:00	US	M%sT	1968 Mar 21
      +			-7:00	-	MST
      +# From Arthur David Olson (1988-02-13):
      +# A writer from the Inter Tribal Council of Arizona, Inc.,
      +# notes in private correspondence dated 1987-12-28 that "Presently, only the
      +# Navajo Nation participates in the Daylight Saving Time policy, due to its
      +# large size and location in three states."  (The "only" means that other
      +# tribal nations don't use DST.)
      +
      +Link America/Denver America/Shiprock
      +
      +# Southern Idaho (Ada, Adams, Bannock, Bear Lake, Bingham, Blaine,
      +# Boise, Bonneville, Butte, Camas, Canyon, Caribou, Cassia, Clark,
      +# Custer, Elmore, Franklin, Fremont, Gem, Gooding, Jefferson, Jerome,
      +# Lemhi, Lincoln, Madison, Minidoka, Oneida, Owyhee, Payette, Power,
      +# Teton, Twin Falls, Valley, Washington counties, and the southern
      +# quarter of Idaho county) and eastern Oregon (most of Malheur County)
      +# switched four weeks late in 1974.
      +#
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Boise	-7:44:49 -	LMT	1883 Nov 18 12:15:11
      +			-8:00	US	P%sT	1923 May 13 2:00
      +			-7:00	US	M%sT	1974
      +			-7:00	-	MST	1974 Feb  3 2:00
      +			-7:00	US	M%sT
      +
      +# Indiana
      +#
      +# For a map of Indiana's time zone regions, see:
      +# 
      +# What time is it in Indiana?
      +#  (2006-03-01)
      +#
      +# From Paul Eggert (2007-08-17):
      +# Since 1970, most of Indiana has been like America/Indiana/Indianapolis,
      +# with the following exceptions:
      +#
      +# - Gibson, Jasper, Lake, LaPorte, Newton, Porter, Posey, Spencer,
      +#   Vandenburgh, and Warrick counties have been like America/Chicago.
      +#
      +# - Dearborn and Ohio counties have been like America/New_York.
      +#
      +# - Clark, Floyd, and Harrison counties have been like
      +#   America/Kentucky/Louisville.
      +#
      +# - Crawford, Daviess, Dubois, Knox, Martin, Perry, Pike, Pulaski, Starke,
      +#   and Switzerland counties have their own time zone histories as noted below.
      +#
      +# Shanks partitioned Indiana into 345 regions, each with its own time history,
      +# and wrote ``Even newspaper reports present contradictory information.''
      +# Those Hoosiers!  Such a flighty and changeable people!
      +# Fortunately, most of the complexity occurred before our cutoff date of 1970.
      +#
      +# Other than Indianapolis, the Indiana place names are so nondescript
      +# that they would be ambiguous if we left them at the `America' level.
      +# So we reluctantly put them all in a subdirectory `America/Indiana'.
      +
      +# From Paul Eggert (2005-08-16):
      +# http://www.mccsc.edu/time.html says that Indiana will use DST starting 2006.
      +
      +# From Nathan Stratton Treadway (2006-03-30):
      +# http://www.dot.gov/affairs/dot0406.htm [3705 B]
      +# From Deborah Goldsmith (2006-01-18):
      +# http://dmses.dot.gov/docimages/pdf95/382329_web.pdf [2.9 MB]
      +# From Paul Eggert (2006-01-20):
      +# It says "DOT is relocating the time zone boundary in Indiana to move Starke,
      +# Pulaski, Knox, Daviess, Martin, Pike, Dubois, and Perry Counties from the
      +# Eastern Time Zone to the Central Time Zone.... The effective date of
      +# this rule is 2:OO a.m. EST Sunday, April 2, 2006, which is the
      +# changeover date from standard time to Daylight Saving Time."
      +# Strictly speaking, this means the affected counties will change their
      +# clocks twice that night, but this obviously is in error.  The intent
      +# is that 01:59:59 EST be followed by 02:00:00 CDT.
      +
      +# From Gwillim Law (2007-02-10):
      +# The Associated Press has been reporting that Pulaski County, Indiana is
      +# going to switch from Central to Eastern Time on March 11, 2007....
      +# http://www.indystar.com/apps/pbcs.dll/article?AID=/20070207/LOCAL190108/702070524/0/LOCAL
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
      +Rule Indianapolis 1941	only	-	Jun	22	2:00	1:00	D
      +Rule Indianapolis 1941	1954	-	Sep	lastSun	2:00	0	S
      +Rule Indianapolis 1946	1954	-	Apr	lastSun	2:00	1:00	D
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Indiana/Indianapolis -5:44:38 - LMT 1883 Nov 18 12:15:22
      +			-6:00	US	C%sT	1920
      +			-6:00 Indianapolis C%sT	1942
      +			-6:00	US	C%sT	1946
      +			-6:00 Indianapolis C%sT	1955 Apr 24 2:00
      +			-5:00	-	EST	1957 Sep 29 2:00
      +			-6:00	-	CST	1958 Apr 27 2:00
      +			-5:00	-	EST	1969
      +			-5:00	US	E%sT	1971
      +			-5:00	-	EST	2006
      +			-5:00	US	E%sT
      +#
      +# Eastern Crawford County, Indiana, left its clocks alone in 1974,
      +# as well as from 1976 through 2005.
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
      +Rule	Marengo	1951	only	-	Apr	lastSun	2:00	1:00	D
      +Rule	Marengo	1951	only	-	Sep	lastSun	2:00	0	S
      +Rule	Marengo	1954	1960	-	Apr	lastSun	2:00	1:00	D
      +Rule	Marengo	1954	1960	-	Sep	lastSun	2:00	0	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Indiana/Marengo -5:45:23 -	LMT	1883 Nov 18 12:14:37
      +			-6:00	US	C%sT	1951
      +			-6:00	Marengo	C%sT	1961 Apr 30 2:00
      +			-5:00	-	EST	1969
      +			-5:00	US	E%sT	1974 Jan  6 2:00
      +			-6:00	1:00	CDT	1974 Oct 27 2:00
      +			-5:00	US	E%sT	1976
      +			-5:00	-	EST	2006
      +			-5:00	US	E%sT
      +#
      +# Daviess, Dubois, Knox, and Martin Counties, Indiana,
      +# switched from eastern to central time in April 2006, then switched back
      +# in November 2007.
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
      +Rule Vincennes	1946	only	-	Apr	lastSun	2:00	1:00	D
      +Rule Vincennes	1946	only	-	Sep	lastSun	2:00	0	S
      +Rule Vincennes	1953	1954	-	Apr	lastSun	2:00	1:00	D
      +Rule Vincennes	1953	1959	-	Sep	lastSun	2:00	0	S
      +Rule Vincennes	1955	only	-	May	 1	0:00	1:00	D
      +Rule Vincennes	1956	1963	-	Apr	lastSun	2:00	1:00	D
      +Rule Vincennes	1960	only	-	Oct	lastSun	2:00	0	S
      +Rule Vincennes	1961	only	-	Sep	lastSun	2:00	0	S
      +Rule Vincennes	1962	1963	-	Oct	lastSun	2:00	0	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Indiana/Vincennes -5:50:07 - LMT	1883 Nov 18 12:09:53
      +			-6:00	US	C%sT	1946
      +			-6:00 Vincennes	C%sT	1964 Apr 26 2:00
      +			-5:00	-	EST	1969
      +			-5:00	US	E%sT	1971
      +			-5:00	-	EST	2006 Apr  2 2:00
      +			-6:00	US	C%sT	2007 Nov  4 2:00
      +			-5:00	US	E%sT
      +#
      +# Perry County, Indiana, switched from eastern to central time in April 2006.
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
      +Rule Perry	1946	only	-	Apr	lastSun	2:00	1:00	D
      +Rule Perry	1946	only	-	Sep	lastSun	2:00	0	S
      +Rule Perry	1953	1954	-	Apr	lastSun	2:00	1:00	D
      +Rule Perry	1953	1959	-	Sep	lastSun	2:00	0	S
      +Rule Perry	1955	only	-	May	 1	0:00	1:00	D
      +Rule Perry	1956	1963	-	Apr	lastSun	2:00	1:00	D
      +Rule Perry	1960	only	-	Oct	lastSun	2:00	0	S
      +Rule Perry	1961	only	-	Sep	lastSun	2:00	0	S
      +Rule Perry	1962	1963	-	Oct	lastSun	2:00	0	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Indiana/Tell_City -5:47:03 - LMT	1883 Nov 18 12:12:57
      +			-6:00	US	C%sT	1946
      +			-6:00 Perry	C%sT	1964 Apr 26 2:00
      +			-5:00	-	EST	1969
      +			-5:00	US	E%sT	1971
      +			-5:00	-	EST	2006 Apr  2 2:00
      +			-6:00	US	C%sT
      +#
      +# Pike County, Indiana moved from central to eastern time in 1977,
      +# then switched back in 2006, then switched back again in 2007.
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
      +Rule	Pike	1955	only	-	May	 1	0:00	1:00	D
      +Rule	Pike	1955	1960	-	Sep	lastSun	2:00	0	S
      +Rule	Pike	1956	1964	-	Apr	lastSun	2:00	1:00	D
      +Rule	Pike	1961	1964	-	Oct	lastSun	2:00	0	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Indiana/Petersburg -5:49:07 - LMT	1883 Nov 18 12:10:53
      +			-6:00	US	C%sT	1955
      +			-6:00	Pike	C%sT	1965 Apr 25 2:00
      +			-5:00	-	EST	1966 Oct 30 2:00
      +			-6:00	US	C%sT	1977 Oct 30 2:00
      +			-5:00	-	EST	2006 Apr  2 2:00
      +			-6:00	US	C%sT	2007 Nov  4 2:00
      +			-5:00	US	E%sT
      +#
      +# Starke County, Indiana moved from central to eastern time in 1991,
      +# then switched back in 2006.
      +# From Arthur David Olson (1991-10-28):
      +# An article on page A3 of the Sunday, 1991-10-27 Washington Post
      +# notes that Starke County switched from Central time to Eastern time as of
      +# 1991-10-27.
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
      +Rule	Starke	1947	1961	-	Apr	lastSun	2:00	1:00	D
      +Rule	Starke	1947	1954	-	Sep	lastSun	2:00	0	S
      +Rule	Starke	1955	1956	-	Oct	lastSun	2:00	0	S
      +Rule	Starke	1957	1958	-	Sep	lastSun	2:00	0	S
      +Rule	Starke	1959	1961	-	Oct	lastSun	2:00	0	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Indiana/Knox -5:46:30 -	LMT	1883 Nov 18 12:13:30
      +			-6:00	US	C%sT	1947
      +			-6:00	Starke	C%sT	1962 Apr 29 2:00
      +			-5:00	-	EST	1963 Oct 27 2:00
      +			-6:00	US	C%sT	1991 Oct 27 2:00
      +			-5:00	-	EST	2006 Apr  2 2:00
      +			-6:00	US	C%sT
      +#
      +# Pulaski County, Indiana, switched from eastern to central time in
      +# April 2006 and then switched back in March 2007.
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
      +Rule	Pulaski	1946	1960	-	Apr	lastSun	2:00	1:00	D
      +Rule	Pulaski	1946	1954	-	Sep	lastSun	2:00	0	S
      +Rule	Pulaski	1955	1956	-	Oct	lastSun	2:00	0	S
      +Rule	Pulaski	1957	1960	-	Sep	lastSun	2:00	0	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Indiana/Winamac -5:46:25 - LMT	1883 Nov 18 12:13:35
      +			-6:00	US	C%sT	1946
      +			-6:00	Pulaski	C%sT	1961 Apr 30 2:00
      +			-5:00	-	EST	1969
      +			-5:00	US	E%sT	1971
      +			-5:00	-	EST	2006 Apr  2 2:00
      +			-6:00	US	C%sT	2007 Mar 11 2:00
      +			-5:00	US	E%sT
      +#
      +# Switzerland County, Indiana, did not observe DST from 1973 through 2005.
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Indiana/Vevay -5:40:16 -	LMT	1883 Nov 18 12:19:44
      +			-6:00	US	C%sT	1954 Apr 25 2:00
      +			-5:00	-	EST	1969
      +			-5:00	US	E%sT	1973
      +			-5:00	-	EST	2006
      +			-5:00	US	E%sT
      +
      +# Part of Kentucky left its clocks alone in 1974.
      +# This also includes Clark, Floyd, and Harrison counties in Indiana.
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
      +Rule Louisville	1921	only	-	May	1	2:00	1:00	D
      +Rule Louisville	1921	only	-	Sep	1	2:00	0	S
      +Rule Louisville	1941	1961	-	Apr	lastSun	2:00	1:00	D
      +Rule Louisville	1941	only	-	Sep	lastSun	2:00	0	S
      +Rule Louisville	1946	only	-	Jun	2	2:00	0	S
      +Rule Louisville	1950	1955	-	Sep	lastSun	2:00	0	S
      +Rule Louisville	1956	1960	-	Oct	lastSun	2:00	0	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Kentucky/Louisville -5:43:02 -	LMT	1883 Nov 18 12:16:58
      +			-6:00	US	C%sT	1921
      +			-6:00 Louisville C%sT	1942
      +			-6:00	US	C%sT	1946
      +			-6:00 Louisville C%sT	1961 Jul 23 2:00
      +			-5:00	-	EST	1968
      +			-5:00	US	E%sT	1974 Jan  6 2:00
      +			-6:00	1:00	CDT	1974 Oct 27 2:00
      +			-5:00	US	E%sT
      +#
      +# Wayne County, Kentucky
      +#
      +# From
      +# 
      +# Lake Cumberland LIFE
      +#  (1999-01-29) via WKYM-101.7:
      +# Clinton County has joined Wayne County in asking the DoT to change from
      +# the Central to the Eastern time zone....  The Wayne County government made
      +# the same request in December.  And while Russell County officials have not
      +# taken action, the majority of respondents to a poll conducted there in
      +# August indicated they would like to change to "fast time" also.
      +# The three Lake Cumberland counties are the farthest east of any U.S.
      +# location in the Central time zone.
      +#
      +# From Rich Wales (2000-08-29):
      +# After prolonged debate, and despite continuing deep differences of opinion,
      +# Wayne County (central Kentucky) is switching from Central (-0600) to Eastern
      +# (-0500) time.  They won't "fall back" this year.  See Sara Shipley,
      +# The difference an hour makes, Nando Times (2000-08-29 15:33 -0400).
      +#
      +# From Paul Eggert (2001-07-16):
      +# The final rule was published in the
      +# 
      +# Federal Register 65, 160 (2000-08-17), page 50154-50158.
      +# 
      +#
      +Zone America/Kentucky/Monticello -5:39:24 - LMT	1883 Nov 18 12:20:36
      +			-6:00	US	C%sT	1946
      +			-6:00	-	CST	1968
      +			-6:00	US	C%sT	2000 Oct 29  2:00
      +			-5:00	US	E%sT
      +
      +
      +# From Rives McDow (2000-08-30):
      +# Here ... are all the changes in the US since 1985.
      +# Kearny County, KS (put all of county on central;
      +#	previously split between MST and CST) ... 1990-10
      +# Starke County, IN (from CST to EST) ... 1991-10
      +# Oliver County, ND (from MST to CST) ... 1992-10
      +# West Wendover, NV (from PST TO MST) ... 1999-10
      +# Wayne County, KY (from CST to EST) ... 2000-10
      +#
      +# From Paul Eggert (2001-07-17):
      +# We don't know where the line used to be within Kearny County, KS,
      +# so omit that change for now.
      +# See America/Indiana/Knox for the Starke County, IN change.
      +# See America/North_Dakota/Center for the Oliver County, ND change.
      +# West Wendover, NV officially switched from Pacific to mountain time on
      +# 1999-10-31.  See the
      +# 
      +# Federal Register 64, 203 (1999-10-21), page 56705-56707.
      +# 
      +# However, the Federal Register says that West Wendover already operated
      +# on mountain time, and the rule merely made this official;
      +# hence a separate tz entry is not needed.
      +
      +# Michigan
      +#
      +# From Bob Devine (1988-01-28):
      +# Michigan didn't observe DST from 1968 to 1973.
      +#
      +# From Paul Eggert (1999-03-31):
      +# Shanks writes that Michigan started using standard time on 1885-09-18,
      +# but Howse writes (pp 124-125, referring to Popular Astronomy, 1901-01)
      +# that Detroit kept
      +#
      +#	local time until 1900 when the City Council decreed that clocks should
      +#	be put back twenty-eight minutes to Central Standard Time.  Half the
      +#	city obeyed, half refused.  After considerable debate, the decision
      +#	was rescinded and the city reverted to Sun time.  A derisive offer to
      +#	erect a sundial in front of the city hall was referred to the
      +#	Committee on Sewers.  Then, in 1905, Central time was adopted
      +#	by city vote.
      +#
      +# This story is too entertaining to be false, so go with Howse over Shanks.
      +#
      +# From Paul Eggert (2001-03-06):
      +# Garland (1927) writes ``Cleveland and Detroit advanced their clocks
      +# one hour in 1914.''  This change is not in Shanks.  We have no more
      +# info, so omit this for now.
      +#
      +# Most of Michigan observed DST from 1973 on, but was a bit late in 1975.
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
      +Rule	Detroit	1948	only	-	Apr	lastSun	2:00	1:00	D
      +Rule	Detroit	1948	only	-	Sep	lastSun	2:00	0	S
      +Rule	Detroit	1967	only	-	Jun	14	2:00	1:00	D
      +Rule	Detroit	1967	only	-	Oct	lastSun	2:00	0	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Detroit	-5:32:11 -	LMT	1905
      +			-6:00	-	CST	1915 May 15 2:00
      +			-5:00	-	EST	1942
      +			-5:00	US	E%sT	1946
      +			-5:00	Detroit	E%sT	1973
      +			-5:00	US	E%sT	1975
      +			-5:00	-	EST	1975 Apr 27 2:00
      +			-5:00	US	E%sT
      +#
      +# Dickinson, Gogebic, Iron, and Menominee Counties, Michigan,
      +# switched from EST to CST/CDT in 1973.
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
      +Rule Menominee	1946	only	-	Apr	lastSun	2:00	1:00	D
      +Rule Menominee	1946	only	-	Sep	lastSun	2:00	0	S
      +Rule Menominee	1966	only	-	Apr	lastSun	2:00	1:00	D
      +Rule Menominee	1966	only	-	Oct	lastSun	2:00	0	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Menominee	-5:50:27 -	LMT	1885 Sep 18 12:00
      +			-6:00	US	C%sT	1946
      +			-6:00 Menominee	C%sT	1969 Apr 27 2:00
      +			-5:00	-	EST	1973 Apr 29 2:00
      +			-6:00	US	C%sT
      +
      +# Navassa
      +# administered by the US Fish and Wildlife Service
      +# claimed by US under the provisions of the 1856 Guano Islands Act
      +# also claimed by Haiti
      +# occupied 1857/1900 by the Navassa Phosphate Co
      +# US lighthouse 1917/1996-09
      +# currently uninhabited
      +# see Mark Fineman, ``An Isle Rich in Guano and Discord'',
      +# _Los Angeles Times_ (1998-11-10), A1, A10; it cites
      +# Jimmy Skaggs, _The Great Guano Rush_ (1994).
      +
      +################################################################################
      +
      +
      +# From Paul Eggert (2006-03-22):
      +# A good source for time zone historical data outside the U.S. is
      +# Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition),
      +# San Diego: ACS Publications, Inc. (2003).
      +#
      +# Gwillim Law writes that a good source
      +# for recent time zone data is the International Air Transport
      +# Association's Standard Schedules Information Manual (IATA SSIM),
      +# published semiannually.  Law sent in several helpful summaries
      +# of the IATA's data after 1990.
      +#
      +# Except where otherwise noted, Shanks & Pottenger is the source for
      +# entries through 1990, and IATA SSIM is the source for entries afterwards.
      +#
      +# Other sources occasionally used include:
      +#
      +#	Edward W. Whitman, World Time Differences,
      +#	Whitman Publishing Co, 2 Niagara Av, Ealing, London (undated),
      +#	which I found in the UCLA library.
      +#
      +#	
      +#	William Willett, The Waste of Daylight, 19th edition
      +#	 (1914-03)
      +#
      +# See the `europe' file for Greenland.
      +
      +# Canada
      +
      +# From Alain LaBont (1994-11-14):
      +# I post here the time zone abbreviations standardized in Canada
      +# for both English and French in the CAN/CSA-Z234.4-89 standard....
      +#
      +#	UTC	Standard time	Daylight savings time
      +#	offset	French	English	French	English
      +#	-2:30	-	-	HAT	NDT
      +#	-3	-	-	HAA	ADT
      +#	-3:30	HNT	NST	-	-
      +#	-4	HNA	AST	HAE	EDT
      +#	-5	HNE	EST	HAC	CDT
      +#	-6	HNC	CST	HAR	MDT
      +#	-7	HNR	MST	HAP	PDT
      +#	-8	HNP	PST	HAY	YDT
      +#	-9	HNY	YST	-	-
      +#
      +#	HN: Heure Normale	ST: Standard Time
      +#	HA: Heure Avance	DT: Daylight saving Time
      +#
      +#	A: de l'Atlantique	Atlantic
      +#	C: du Centre		Central
      +#	E: de l'Est		Eastern
      +#	M:			Mountain
      +#	N:			Newfoundland
      +#	P: du Pacifique		Pacific
      +#	R: des Rocheuses
      +#	T: de Terre-Neuve
      +#	Y: du Yukon		Yukon
      +#
      +# From Paul Eggert (1994-11-22):
      +# Alas, this sort of thing must be handled by localization software.
      +
      +# Unless otherwise specified, the data for Canada are all from Shanks
      +# & Pottenger.
      +
      +# From Chris Walton (2006-04-01, 2006-04-25, 2006-06-26, 2007-01-31,
      +# 2007-03-01):
      +# The British Columbia government announced yesterday that it will
      +# adjust daylight savings next year to align with changes in the
      +# U.S. and the rest of Canada....
      +# http://www2.news.gov.bc.ca/news_releases_2005-2009/2006AG0014-000330.htm
      +# ...
      +# Nova Scotia
      +# Daylight saving time will be extended by four weeks starting in 2007....
      +# http://www.gov.ns.ca/just/regulations/rg2/2006/ma1206.pdf
      +#
      +# [For New Brunswick] the new legislation dictates that the time change is to
      +# be done at 02:00 instead of 00:01.
      +# http://www.gnb.ca/0062/acts/BBA-2006/Chap-19.pdf
      +# ...
      +# Manitoba has traditionally changed the clock every fall at 03:00.
      +# As of 2006, the transition is to take place one hour earlier at 02:00.
      +# http://web2.gov.mb.ca/laws/statutes/ccsm/o030e.php
      +# ...
      +# [Alberta, Ontario, Quebec] will follow US rules.
      +# http://www.qp.gov.ab.ca/documents/spring/CH03_06.CFM
      +# http://www.e-laws.gov.on.ca/DBLaws/Source/Regs/English/2006/R06111_e.htm
      +# http://www2.publicationsduquebec.gouv.qc.ca/dynamicSearch/telecharge.php?type=5&file=2006C39A.PDF
      +# ...
      +# P.E.I. will follow US rules....
      +# http://www.assembly.pe.ca/bills/pdf_chapter/62/3/chapter-41.pdf
      +# ...
      +# Province of Newfoundland and Labrador....
      +# http://www.hoa.gov.nl.ca/hoa/bills/Bill0634.htm
      +# ...
      +# Yukon
      +# http://www.gov.yk.ca/legislation/regs/oic2006_127.pdf
      +# ...
      +# N.W.T. will follow US rules.  Whoever maintains the government web site
      +# does not seem to believe in bookmarks.  To see the news release, click the
      +# following link and search for "Daylight Savings Time Change".  Press the
      +# "Daylight Savings Time Change" link; it will fire off a popup using
      +# JavaScript.
      +# http://www.exec.gov.nt.ca/currentnews/currentPR.asp?mode=archive
      +# ...
      +# Nunavut
      +# An amendment to the Interpretation Act was registered on February 19/2007....
      +# http://action.attavik.ca/home/justice-gn/attach/2007/gaz02part2.pdf
      +
      +# From Paul Eggert (2006-04-25):
      +# H. David Matthews and Mary Vincent's map
      +# 
      +# "It's about TIME", _Canadian Geographic_ (September-October 1998)
      +#  contains detailed boundaries for regions observing nonstandard
      +# time and daylight saving time arrangements in Canada circa 1998.
      +#
      +# INMS, the Institute for National Measurement Standards in Ottawa, has 
      +# information about standard and daylight saving time zones in Canada.
      +#  (updated periodically).
      +# Its unofficial information is often taken from Matthews and Vincent.
      +
      +# From Paul Eggert (2006-06-27):
      +# For now, assume all of DST-observing Canada will fall into line with the
      +# new US DST rules,
      +
      +# From Chris Walton (2011-12-01)
      +# In the first of Tammy Hardwick's articles
      +# 
      +# http://www.ilovecreston.com/?p=articles&t=spec&ar=260
      +# 
      +# she quotes the Friday November 1/1918 edition of the Creston Review.
      +# The quote includes these two statements:
      +# 'Sunday the CPR went back to the old system of time...'
      +# '... The daylight saving scheme was dropped all over Canada at the same time,'
      +# These statements refer to a transition from daylight time to standard time
      +# that occurred nationally on Sunday October 27/1918.  This transition was
      +# also documented in the Saturday October 26/1918 edition of the Toronto Star.
      +
      +# In light of that evidence, we alter the date from the earlier believed
      +# Oct 31, to Oct 27, 1918 (and Sunday is a more likely transition day
      +# than Thursday) in all Canadian rulesets.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Canada	1918	only	-	Apr	14	2:00	1:00	D
      +Rule	Canada	1918	only	-	Oct	27	2:00	0	S
      +Rule	Canada	1942	only	-	Feb	 9	2:00	1:00	W # War
      +Rule	Canada	1945	only	-	Aug	14	23:00u	1:00	P # Peace
      +Rule	Canada	1945	only	-	Sep	30	2:00	0	S
      +Rule	Canada	1974	1986	-	Apr	lastSun	2:00	1:00	D
      +Rule	Canada	1974	2006	-	Oct	lastSun	2:00	0	S
      +Rule	Canada	1987	2006	-	Apr	Sun>=1	2:00	1:00	D
      +Rule	Canada	2007	max	-	Mar	Sun>=8	2:00	1:00	D
      +Rule	Canada	2007	max	-	Nov	Sun>=1	2:00	0	S
      +
      +
      +# Newfoundland and Labrador
      +
      +# From Paul Eggert (2000-10-02):
      +# Matthews and Vincent (1998) write that Labrador should use NST/NDT,
      +# but the only part of Labrador that follows the rules is the
      +# southeast corner, including Port Hope Simpson and Mary's Harbour,
      +# but excluding, say, Black Tickle.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	StJohns	1917	only	-	Apr	 8	2:00	1:00	D
      +Rule	StJohns	1917	only	-	Sep	17	2:00	0	S
      +# Whitman gives 1919 Apr 5 and 1920 Apr 5; go with Shanks & Pottenger.
      +Rule	StJohns	1919	only	-	May	 5	23:00	1:00	D
      +Rule	StJohns	1919	only	-	Aug	12	23:00	0	S
      +# For 1931-1935 Whitman gives Apr same date; go with Shanks & Pottenger.
      +Rule	StJohns	1920	1935	-	May	Sun>=1	23:00	1:00	D
      +Rule	StJohns	1920	1935	-	Oct	lastSun	23:00	0	S
      +# For 1936-1941 Whitman gives May Sun>=8 and Oct Sun>=1; go with Shanks &
      +# Pottenger.
      +Rule	StJohns	1936	1941	-	May	Mon>=9	0:00	1:00	D
      +Rule	StJohns	1936	1941	-	Oct	Mon>=2	0:00	0	S
      +# Whitman gives the following transitions:
      +# 1942 03-01/12-31, 1943 05-30/09-05, 1944 07-10/09-02, 1945 01-01/10-07
      +# but go with Shanks & Pottenger and assume they used Canadian rules.
      +# For 1946-9 Whitman gives May 5,4,9,1 - Oct 1,5,3,2, and for 1950 he gives
      +# Apr 30 - Sep 24; go with Shanks & Pottenger.
      +Rule	StJohns	1946	1950	-	May	Sun>=8	2:00	1:00	D
      +Rule	StJohns	1946	1950	-	Oct	Sun>=2	2:00	0	S
      +Rule	StJohns	1951	1986	-	Apr	lastSun	2:00	1:00	D
      +Rule	StJohns	1951	1959	-	Sep	lastSun	2:00	0	S
      +Rule	StJohns	1960	1986	-	Oct	lastSun	2:00	0	S
      +# From Paul Eggert (2000-10-02):
      +# INMS (2000-09-12) says that, since 1988 at least, Newfoundland switches
      +# at 00:01 local time.  For now, assume it started in 1987.
      +
      +# From Michael Pelley (2011-09-12):
      +# We received today, Monday, September 12, 2011, notification that the
      +# changes to the Newfoundland Standard Time Act have been proclaimed.
      +# The change in the Act stipulates that the change from Daylight Savings
      +# Time to Standard Time and from Standard Time to Daylight Savings Time
      +# now occurs at 2:00AM.
      +# ...
      +# 
      +# http://www.assembly.nl.ca/legislation/sr/annualstatutes/2011/1106.chp.htm
      +# 
      +# ...
      +# MICHAEL PELLEY  |  Manager of Enterprise Architecture - Solution Delivery
      +# Office of the Chief Information Officer
      +# Executive Council
      +# Government of Newfoundland & Labrador
      +
      +Rule	StJohns	1987	only	-	Apr	Sun>=1	0:01	1:00	D
      +Rule	StJohns	1987	2006	-	Oct	lastSun	0:01	0	S
      +Rule	StJohns	1988	only	-	Apr	Sun>=1	0:01	2:00	DD
      +Rule	StJohns	1989	2006	-	Apr	Sun>=1	0:01	1:00	D
      +Rule	StJohns	2007	2011	-	Mar	Sun>=8	0:01	1:00	D
      +Rule	StJohns	2007	2010	-	Nov	Sun>=1	0:01	0	S
      +#
      +# St John's has an apostrophe, but Posix file names can't have apostrophes.
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/St_Johns	-3:30:52 -	LMT	1884
      +			-3:30:52 StJohns N%sT	1918
      +			-3:30:52 Canada	N%sT	1919
      +			-3:30:52 StJohns N%sT	1935 Mar 30
      +			-3:30	StJohns	N%sT	1942 May 11
      +			-3:30	Canada	N%sT	1946
      +			-3:30	StJohns	N%sT	2011 Nov
      +			-3:30	Canada	N%sT
      +
      +# most of east Labrador
      +
      +# The name `Happy Valley-Goose Bay' is too long; use `Goose Bay'.
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Goose_Bay	-4:01:40 -	LMT	1884 # Happy Valley-Goose Bay
      +			-3:30:52 -	NST	1918
      +			-3:30:52 Canada N%sT	1919
      +			-3:30:52 -	NST	1935 Mar 30
      +			-3:30	-	NST	1936
      +			-3:30	StJohns	N%sT	1942 May 11
      +			-3:30	Canada	N%sT	1946
      +			-3:30	StJohns	N%sT	1966 Mar 15 2:00
      +			-4:00	StJohns	A%sT	2011 Nov
      +			-4:00	Canada	A%sT
      +
      +
      +# west Labrador, Nova Scotia, Prince Edward I
      +
      +# From Paul Eggert (2006-03-22):
      +# Shanks & Pottenger write that since 1970 most of this region has been like
      +# Halifax.  Many locales did not observe peacetime DST until 1972;
      +# Glace Bay, NS is the largest that we know of.
      +# Shanks & Pottenger also write that Liverpool, NS was the only town
      +# in Canada to observe DST in 1971 but not 1970; for now we'll assume
      +# this is a typo.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Halifax	1916	only	-	Apr	 1	0:00	1:00	D
      +Rule	Halifax	1916	only	-	Oct	 1	0:00	0	S
      +Rule	Halifax	1920	only	-	May	 9	0:00	1:00	D
      +Rule	Halifax	1920	only	-	Aug	29	0:00	0	S
      +Rule	Halifax	1921	only	-	May	 6	0:00	1:00	D
      +Rule	Halifax	1921	1922	-	Sep	 5	0:00	0	S
      +Rule	Halifax	1922	only	-	Apr	30	0:00	1:00	D
      +Rule	Halifax	1923	1925	-	May	Sun>=1	0:00	1:00	D
      +Rule	Halifax	1923	only	-	Sep	 4	0:00	0	S
      +Rule	Halifax	1924	only	-	Sep	15	0:00	0	S
      +Rule	Halifax	1925	only	-	Sep	28	0:00	0	S
      +Rule	Halifax	1926	only	-	May	16	0:00	1:00	D
      +Rule	Halifax	1926	only	-	Sep	13	0:00	0	S
      +Rule	Halifax	1927	only	-	May	 1	0:00	1:00	D
      +Rule	Halifax	1927	only	-	Sep	26	0:00	0	S
      +Rule	Halifax	1928	1931	-	May	Sun>=8	0:00	1:00	D
      +Rule	Halifax	1928	only	-	Sep	 9	0:00	0	S
      +Rule	Halifax	1929	only	-	Sep	 3	0:00	0	S
      +Rule	Halifax	1930	only	-	Sep	15	0:00	0	S
      +Rule	Halifax	1931	1932	-	Sep	Mon>=24	0:00	0	S
      +Rule	Halifax	1932	only	-	May	 1	0:00	1:00	D
      +Rule	Halifax	1933	only	-	Apr	30	0:00	1:00	D
      +Rule	Halifax	1933	only	-	Oct	 2	0:00	0	S
      +Rule	Halifax	1934	only	-	May	20	0:00	1:00	D
      +Rule	Halifax	1934	only	-	Sep	16	0:00	0	S
      +Rule	Halifax	1935	only	-	Jun	 2	0:00	1:00	D
      +Rule	Halifax	1935	only	-	Sep	30	0:00	0	S
      +Rule	Halifax	1936	only	-	Jun	 1	0:00	1:00	D
      +Rule	Halifax	1936	only	-	Sep	14	0:00	0	S
      +Rule	Halifax	1937	1938	-	May	Sun>=1	0:00	1:00	D
      +Rule	Halifax	1937	1941	-	Sep	Mon>=24	0:00	0	S
      +Rule	Halifax	1939	only	-	May	28	0:00	1:00	D
      +Rule	Halifax	1940	1941	-	May	Sun>=1	0:00	1:00	D
      +Rule	Halifax	1946	1949	-	Apr	lastSun	2:00	1:00	D
      +Rule	Halifax	1946	1949	-	Sep	lastSun	2:00	0	S
      +Rule	Halifax	1951	1954	-	Apr	lastSun	2:00	1:00	D
      +Rule	Halifax	1951	1954	-	Sep	lastSun	2:00	0	S
      +Rule	Halifax	1956	1959	-	Apr	lastSun	2:00	1:00	D
      +Rule	Halifax	1956	1959	-	Sep	lastSun	2:00	0	S
      +Rule	Halifax	1962	1973	-	Apr	lastSun	2:00	1:00	D
      +Rule	Halifax	1962	1973	-	Oct	lastSun	2:00	0	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Halifax	-4:14:24 -	LMT	1902 Jun 15
      +			-4:00	Halifax	A%sT	1918
      +			-4:00	Canada	A%sT	1919
      +			-4:00	Halifax	A%sT	1942 Feb  9 2:00s
      +			-4:00	Canada	A%sT	1946
      +			-4:00	Halifax	A%sT	1974
      +			-4:00	Canada	A%sT
      +Zone America/Glace_Bay	-3:59:48 -	LMT	1902 Jun 15
      +			-4:00	Canada	A%sT	1953
      +			-4:00	Halifax	A%sT	1954
      +			-4:00	-	AST	1972
      +			-4:00	Halifax	A%sT	1974
      +			-4:00	Canada	A%sT
      +
      +# New Brunswick
      +
      +# From Paul Eggert (2007-01-31):
      +# The Time Definition Act 
      +# says they changed at 00:01 through 2006, and
      +#  makes it
      +# clear that this was the case since at least 1993.
      +# For now, assume it started in 1993.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Moncton	1933	1935	-	Jun	Sun>=8	1:00	1:00	D
      +Rule	Moncton	1933	1935	-	Sep	Sun>=8	1:00	0	S
      +Rule	Moncton	1936	1938	-	Jun	Sun>=1	1:00	1:00	D
      +Rule	Moncton	1936	1938	-	Sep	Sun>=1	1:00	0	S
      +Rule	Moncton	1939	only	-	May	27	1:00	1:00	D
      +Rule	Moncton	1939	1941	-	Sep	Sat>=21	1:00	0	S
      +Rule	Moncton	1940	only	-	May	19	1:00	1:00	D
      +Rule	Moncton	1941	only	-	May	 4	1:00	1:00	D
      +Rule	Moncton	1946	1972	-	Apr	lastSun	2:00	1:00	D
      +Rule	Moncton	1946	1956	-	Sep	lastSun	2:00	0	S
      +Rule	Moncton	1957	1972	-	Oct	lastSun	2:00	0	S
      +Rule	Moncton	1993	2006	-	Apr	Sun>=1	0:01	1:00	D
      +Rule	Moncton	1993	2006	-	Oct	lastSun	0:01	0	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Moncton	-4:19:08 -	LMT	1883 Dec  9
      +			-5:00	-	EST	1902 Jun 15
      +			-4:00	Canada	A%sT	1933
      +			-4:00	Moncton	A%sT	1942
      +			-4:00	Canada	A%sT	1946
      +			-4:00	Moncton	A%sT	1973
      +			-4:00	Canada	A%sT	1993
      +			-4:00	Moncton	A%sT	2007
      +			-4:00	Canada	A%sT
      +
      +# Quebec
      +
      +# From Paul Eggert (2006-07-09):
      +# Shanks & Pottenger write that since 1970 most of Quebec has been
      +# like Montreal.
      +
      +# From Paul Eggert (2006-06-27):
      +# Matthews and Vincent (1998) also write that Quebec east of the -63
      +# meridian is supposed to observe AST, but residents as far east as
      +# Natashquan use EST/EDT, and residents east of Natashquan use AST.
      +# In "Official time in Quebec" the Quebec department of justice writes in
      +# http://www.justice.gouv.qc.ca/english/publications/generale/temps-regl-1-a.htm
      +# that "The residents of the Municipality of the
      +# Cote-Nord-du-Golfe-Saint-Laurent and the municipalities of Saint-Augustin,
      +# Bonne-Esperance and Blanc-Sablon apply the Official Time Act as it is
      +# written and use Atlantic standard time all year round. The same applies to
      +# the residents of the Native facilities along the lower North Shore."
      +# 
      +# says this common practice was codified into law as of 2007.
      +# For lack of better info, guess this practice began around 1970, contra to
      +# Shanks & Pottenger who have this region observing AST/ADT.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Mont	1917	only	-	Mar	25	2:00	1:00	D
      +Rule	Mont	1917	only	-	Apr	24	0:00	0	S
      +Rule	Mont	1919	only	-	Mar	31	2:30	1:00	D
      +Rule	Mont	1919	only	-	Oct	25	2:30	0	S
      +Rule	Mont	1920	only	-	May	 2	2:30	1:00	D
      +Rule	Mont	1920	1922	-	Oct	Sun>=1	2:30	0	S
      +Rule	Mont	1921	only	-	May	 1	2:00	1:00	D
      +Rule	Mont	1922	only	-	Apr	30	2:00	1:00	D
      +Rule	Mont	1924	only	-	May	17	2:00	1:00	D
      +Rule	Mont	1924	1926	-	Sep	lastSun	2:30	0	S
      +Rule	Mont	1925	1926	-	May	Sun>=1	2:00	1:00	D
      +# The 1927-to-1937 rules can be expressed more simply as
      +# Rule	Mont	1927	1937	-	Apr	lastSat	24:00	1:00	D
      +# Rule	Mont	1927	1937	-	Sep	lastSat	24:00	0	S
      +# The rules below avoid use of 24:00
      +# (which pre-1998 versions of zic cannot handle).
      +Rule	Mont	1927	only	-	May	1	0:00	1:00	D
      +Rule	Mont	1927	1932	-	Sep	lastSun	0:00	0	S
      +Rule	Mont	1928	1931	-	Apr	lastSun	0:00	1:00	D
      +Rule	Mont	1932	only	-	May	1	0:00	1:00	D
      +Rule	Mont	1933	1940	-	Apr	lastSun	0:00	1:00	D
      +Rule	Mont	1933	only	-	Oct	1	0:00	0	S
      +Rule	Mont	1934	1939	-	Sep	lastSun	0:00	0	S
      +Rule	Mont	1946	1973	-	Apr	lastSun	2:00	1:00	D
      +Rule	Mont	1945	1948	-	Sep	lastSun	2:00	0	S
      +Rule	Mont	1949	1950	-	Oct	lastSun	2:00	0	S
      +Rule	Mont	1951	1956	-	Sep	lastSun	2:00	0	S
      +Rule	Mont	1957	1973	-	Oct	lastSun	2:00	0	S
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Blanc-Sablon -3:48:28 -	LMT	1884
      +			-4:00	Canada	A%sT	1970
      +			-4:00	-	AST
      +Zone America/Montreal	-4:54:16 -	LMT	1884
      +			-5:00	Mont	E%sT	1918
      +			-5:00	Canada	E%sT	1919
      +			-5:00	Mont	E%sT	1942 Feb  9 2:00s
      +			-5:00	Canada	E%sT	1946
      +			-5:00	Mont	E%sT	1974
      +			-5:00	Canada	E%sT
      +
      +
      +# Ontario
      +
      +# From Paul Eggert (2006-07-09):
      +# Shanks & Pottenger write that since 1970 most of Ontario has been like
      +# Toronto.
      +# Thunder Bay skipped DST in 1973.
      +# Many smaller locales did not observe peacetime DST until 1974;
      +# Nipigon (EST) and Rainy River (CST) are the largest that we know of.
      +# Far west Ontario is like Winnipeg; far east Quebec is like Halifax.
      +
      +# From Mark Brader (2003-07-26):
      +# [According to the Toronto Star] Orillia, Ontario, adopted DST
      +# effective Saturday, 1912-06-22, 22:00; the article mentions that
      +# Port Arthur (now part of Thunder Bay, Ontario) as well as Moose Jaw
      +# have already done so.  In Orillia DST was to run until Saturday,
      +# 1912-08-31 (no time mentioned), but it was met with considerable
      +# hostility from certain segments of the public, and was revoked after
      +# only two weeks -- I copied it as Saturday, 1912-07-07, 22:00, but
      +# presumably that should be -07-06.  (1912-06-19, -07-12; also letters
      +# earlier in June).
      +#
      +# Kenora, Ontario, was to abandon DST on 1914-06-01 (-05-21).
      +
      +# From Paul Eggert (1997-10-17):
      +# Mark Brader writes that an article in the 1997-10-14 Toronto Star
      +# says that Atikokan, Ontario currently does not observe DST,
      +# but will vote on 11-10 whether to use EST/EDT.
      +# He also writes that the
      +# 
      +# Ontario Time Act (1990, Chapter T.9)
      +# 
      +# says that Ontario east of 90W uses EST/EDT, and west of 90W uses CST/CDT.
      +# Officially Atikokan is therefore on CST/CDT, and most likely this report
      +# concerns a non-official time observed as a matter of local practice.
      +#
      +# From Paul Eggert (2000-10-02):
      +# Matthews and Vincent (1998) write that Atikokan, Pickle Lake, and
      +# New Osnaburgh observe CST all year, that Big Trout Lake observes
      +# CST/CDT, and that Upsala and Shebandowan observe EST/EDT, all in
      +# violation of the official Ontario rules.
      +#
      +# From Paul Eggert (2006-07-09):
      +# Chris Walton (2006-07-06) mentioned an article by Stephanie MacLellan in the
      +# 2005-07-21 Chronicle-Journal, which said:
      +#
      +#	The clocks in Atikokan stay set on standard time year-round.
      +#	This means they spend about half the time on central time and
      +#	the other half on eastern time.
      +#
      +#	For the most part, the system works, Mayor Dennis Brown said.
      +#
      +#	"The majority of businesses in Atikokan deal more with Eastern
      +#	Canada, but there are some that deal with Western Canada," he
      +#	said.  "I don't see any changes happening here."
      +#
      +# Walton also writes "Supposedly Pickle Lake and Mishkeegogamang
      +# [New Osnaburgh] follow the same practice."
      +
      +# From Garry McKinnon (2006-07-14) via Chris Walton:
      +# I chatted with a member of my board who has an outstanding memory
      +# and a long history in Atikokan (and in the telecom industry) and he
      +# can say for certain that Atikokan has been practicing the current
      +# time keeping since 1952, at least.
      +
      +# From Paul Eggert (2006-07-17):
      +# Shanks & Pottenger say that Atikokan has agreed with Rainy River
      +# ever since standard time was introduced, but the information from
      +# McKinnon sounds more authoritative.  For now, assume that Atikokan
      +# switched to EST immediately after WWII era daylight saving time
      +# ended.  This matches the old (less-populous) America/Coral_Harbour
      +# entry since our cutoff date of 1970, so we can move
      +# America/Coral_Harbour to the 'backward' file.
      +
      +# From Mark Brader (2010-03-06):
      +#
      +# Currently the database has:
      +#
      +# # Ontario
      +#
      +# # From Paul Eggert (2006-07-09):
      +# # Shanks & Pottenger write that since 1970 most of Ontario has been like
      +# # Toronto.
      +# # Thunder Bay skipped DST in 1973.
      +# # Many smaller locales did not observe peacetime DST until 1974;
      +# # Nipigon (EST) and Rainy River (CST) are the largest that we know of.
      +#
      +# In the (Toronto) Globe and Mail for Saturday, 1955-09-24, in the bottom
      +# right corner of page 1, it says that Toronto will return to standard
      +# time at 2 am Sunday morning (which agrees with the database), and that:
      +#
      +#     The one-hour setback will go into effect throughout most of Ontario,
      +#     except in areas like Windsor which remains on standard time all year.
      +#
      +# Windsor is, of course, a lot larger than Nipigon.
      +#
      +# I only came across this incidentally.  I don't know if Windsor began
      +# observing DST when Detroit did, or in 1974, or on some other date.
      +#
      +# By the way, the article continues by noting that:
      +#
      +#     Some cities in the United States have pushed the deadline back
      +#     three weeks and will change over from daylight saving in October.
      +
      +# From Arthur David Olson (2010-07-17):
      +#
      +# "Standard Time and Time Zones in Canada" appeared in
      +# The Journal of The Royal Astronomical Society of Canada,
      +# volume 26, number 2 (February 1932) and, as of 2010-07-17,
      +# was available at
      +# 
      +# http://adsabs.harvard.edu/full/1932JRASC..26...49S
      +# 
      +#
      +# It includes the text below (starting on page 57):
      +#
      +#   A list of the places in Canada using daylight saving time would
      +# require yearly revision. From information kindly furnished by
      +# the provincial governments and by the postmasters in many cities
      +# and towns, it is found that the following places used daylight sav-
      +# ing in 1930. The information for the province of Quebec is definite,
      +# for the other provinces only approximate:
      +#
      +# 	Province	Daylight saving time used
      +# Prince Edward Island	Not used.
      +# Nova Scotia		In Halifax only.
      +# New Brunswick		In St. John only.
      +# Quebec		In the following places:
      +# 			Montreal	Lachine
      +# 			Quebec		Mont-Royal
      +# 			Levis		Iberville
      +# 			St. Lambert	Cap de la Madeleine
      +# 			Verdun		Loretteville
      +# 			Westmount	Richmond
      +# 			Outremont	St. Jerome
      +# 			Longueuil	Greenfield Park
      +# 			Arvida		Waterloo
      +# 			Chambly-Canton	Beaulieu
      +# 			Melbourne	La Tuque
      +# 			St. Theophile	Buckingham
      +# Ontario		Used generally in the cities and towns along
      +# 			the southerly part of the province. Not
      +# 			used in the northwesterlhy part.
      +# Manitoba		Not used.
      +# Saskatchewan		In Regina only.
      +# Alberta		Not used.
      +# British Columbia	Not used.
      +#
      +#   With some exceptions, the use of daylight saving may be said to be limited
      +# to those cities and towns lying between Quebec city and Windsor, Ont.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Toronto	1919	only	-	Mar	30	23:30	1:00	D
      +Rule	Toronto	1919	only	-	Oct	26	0:00	0	S
      +Rule	Toronto	1920	only	-	May	 2	2:00	1:00	D
      +Rule	Toronto	1920	only	-	Sep	26	0:00	0	S
      +Rule	Toronto	1921	only	-	May	15	2:00	1:00	D
      +Rule	Toronto	1921	only	-	Sep	15	2:00	0	S
      +Rule	Toronto	1922	1923	-	May	Sun>=8	2:00	1:00	D
      +# Shanks & Pottenger say 1923-09-19; assume it's a typo and that "-16"
      +# was meant.
      +Rule	Toronto	1922	1926	-	Sep	Sun>=15	2:00	0	S
      +Rule	Toronto	1924	1927	-	May	Sun>=1	2:00	1:00	D
      +# The 1927-to-1939 rules can be expressed more simply as
      +# Rule	Toronto	1927	1937	-	Sep	Sun>=25	2:00	0	S
      +# Rule	Toronto	1928	1937	-	Apr	Sun>=25	2:00	1:00	D
      +# Rule	Toronto	1938	1940	-	Apr	lastSun	2:00	1:00	D
      +# Rule	Toronto	1938	1939	-	Sep	lastSun	2:00	0	S
      +# The rules below avoid use of Sun>=25
      +# (which pre-2004 versions of zic cannot handle).
      +Rule	Toronto	1927	1932	-	Sep	lastSun	2:00	0	S
      +Rule	Toronto	1928	1931	-	Apr	lastSun	2:00	1:00	D
      +Rule	Toronto	1932	only	-	May	1	2:00	1:00	D
      +Rule	Toronto	1933	1940	-	Apr	lastSun	2:00	1:00	D
      +Rule	Toronto	1933	only	-	Oct	1	2:00	0	S
      +Rule	Toronto	1934	1939	-	Sep	lastSun	2:00	0	S
      +Rule	Toronto	1945	1946	-	Sep	lastSun	2:00	0	S
      +Rule	Toronto	1946	only	-	Apr	lastSun	2:00	1:00	D
      +Rule	Toronto	1947	1949	-	Apr	lastSun	0:00	1:00	D
      +Rule	Toronto	1947	1948	-	Sep	lastSun	0:00	0	S
      +Rule	Toronto	1949	only	-	Nov	lastSun	0:00	0	S
      +Rule	Toronto	1950	1973	-	Apr	lastSun	2:00	1:00	D
      +Rule	Toronto	1950	only	-	Nov	lastSun	2:00	0	S
      +Rule	Toronto	1951	1956	-	Sep	lastSun	2:00	0	S
      +# Shanks & Pottenger say Toronto ended DST a week early in 1971,
      +# namely on 1971-10-24, but Mark Brader wrote (2003-05-31) that this
      +# is wrong, and that he had confirmed it by checking the 1971-10-30
      +# Toronto Star, which said that DST was ending 1971-10-31 as usual.
      +Rule	Toronto	1957	1973	-	Oct	lastSun	2:00	0	S
      +
      +# From Paul Eggert (2003-07-27):
      +# Willett (1914-03) writes (p. 17) "In the Cities of Fort William, and
      +# Port Arthur, Ontario, the principle of the Bill has been in
      +# operation for the past three years, and in the City of Moose Jaw,
      +# Saskatchewan, for one year."
      +
      +# From David Bryan via Tory Tronrud, Director/Curator,
      +# Thunder Bay Museum (2003-11-12):
      +# There is some suggestion, however, that, by-law or not, daylight
      +# savings time was being practiced in Fort William and Port Arthur
      +# before 1909.... [I]n 1910, the line between the Eastern and Central
      +# Time Zones was permanently moved about two hundred miles west to
      +# include the Thunder Bay area....  When Canada adopted daylight
      +# savings time in 1916, Fort William and Port Arthur, having done so
      +# already, did not change their clocks....  During the Second World
      +# War,... [t]he cities agreed to implement DST during the summer
      +# months for the remainder of the war years.
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Toronto	-5:17:32 -	LMT	1895
      +			-5:00	Canada	E%sT	1919
      +			-5:00	Toronto	E%sT	1942 Feb  9 2:00s
      +			-5:00	Canada	E%sT	1946
      +			-5:00	Toronto	E%sT	1974
      +			-5:00	Canada	E%sT
      +Zone America/Thunder_Bay -5:57:00 -	LMT	1895
      +			-6:00	-	CST	1910
      +			-5:00	-	EST	1942
      +			-5:00	Canada	E%sT	1970
      +			-5:00	Mont	E%sT	1973
      +			-5:00	-	EST	1974
      +			-5:00	Canada	E%sT
      +Zone America/Nipigon	-5:53:04 -	LMT	1895
      +			-5:00	Canada	E%sT	1940 Sep 29
      +			-5:00	1:00	EDT	1942 Feb  9 2:00s
      +			-5:00	Canada	E%sT
      +Zone America/Rainy_River -6:18:16 -	LMT	1895
      +			-6:00	Canada	C%sT	1940 Sep 29
      +			-6:00	1:00	CDT	1942 Feb  9 2:00s
      +			-6:00	Canada	C%sT
      +Zone America/Atikokan	-6:06:28 -	LMT	1895
      +			-6:00	Canada	C%sT	1940 Sep 29
      +			-6:00	1:00	CDT	1942 Feb  9 2:00s
      +			-6:00	Canada	C%sT	1945 Sep 30 2:00
      +			-5:00	-	EST
      +
      +
      +# Manitoba
      +
      +# From Rob Douglas (2006-04-06):
      +# the old Manitoba Time Act - as amended by Bill 2, assented to
      +# March 27, 1987 ... said ...
      +# "between two o'clock Central Standard Time in the morning of
      +# the first Sunday of April of each year and two o'clock Central
      +# Standard Time in the morning of the last Sunday of October next
      +# following, one hour in advance of Central Standard Time."...
      +# I believe that the English legislation [of the old time act] had =
      +# been assented to (March 22, 1967)....
      +# Also, as far as I can tell, there was no order-in-council varying
      +# the time of Daylight Saving Time for 2005 and so the provisions of
      +# the 1987 version would apply - the changeover was at 2:00 Central
      +# Standard Time (i.e. not until 3:00 Central Daylight Time).
      +
      +# From Paul Eggert (2006-04-10):
      +# Shanks & Pottenger say Manitoba switched at 02:00 (not 02:00s)
      +# starting 1966.  Since 02:00s is clearly correct for 1967 on, assume
      +# it was also 02:00s in 1966.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Winn	1916	only	-	Apr	23	0:00	1:00	D
      +Rule	Winn	1916	only	-	Sep	17	0:00	0	S
      +Rule	Winn	1918	only	-	Apr	14	2:00	1:00	D
      +Rule	Winn	1918	only	-	Oct	27	2:00	0	S
      +Rule	Winn	1937	only	-	May	16	2:00	1:00	D
      +Rule	Winn	1937	only	-	Sep	26	2:00	0	S
      +Rule	Winn	1942	only	-	Feb	 9	2:00	1:00	W # War
      +Rule	Winn	1945	only	-	Aug	14	23:00u	1:00	P # Peace
      +Rule	Winn	1945	only	-	Sep	lastSun	2:00	0	S
      +Rule	Winn	1946	only	-	May	12	2:00	1:00	D
      +Rule	Winn	1946	only	-	Oct	13	2:00	0	S
      +Rule	Winn	1947	1949	-	Apr	lastSun	2:00	1:00	D
      +Rule	Winn	1947	1949	-	Sep	lastSun	2:00	0	S
      +Rule	Winn	1950	only	-	May	 1	2:00	1:00	D
      +Rule	Winn	1950	only	-	Sep	30	2:00	0	S
      +Rule	Winn	1951	1960	-	Apr	lastSun	2:00	1:00	D
      +Rule	Winn	1951	1958	-	Sep	lastSun	2:00	0	S
      +Rule	Winn	1959	only	-	Oct	lastSun	2:00	0	S
      +Rule	Winn	1960	only	-	Sep	lastSun	2:00	0	S
      +Rule	Winn	1963	only	-	Apr	lastSun	2:00	1:00	D
      +Rule	Winn	1963	only	-	Sep	22	2:00	0	S
      +Rule	Winn	1966	1986	-	Apr	lastSun	2:00s	1:00	D
      +Rule	Winn	1966	2005	-	Oct	lastSun	2:00s	0	S
      +Rule	Winn	1987	2005	-	Apr	Sun>=1	2:00s	1:00	D
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Winnipeg	-6:28:36 -	LMT	1887 Jul 16
      +			-6:00	Winn	C%sT	2006
      +			-6:00	Canada	C%sT
      +
      +
      +# Saskatchewan
      +
      +# From Mark Brader (2003-07-26):
      +# The first actual adoption of DST in Canada was at the municipal
      +# level.  As the [Toronto] Star put it (1912-06-07), "While people
      +# elsewhere have long been talking of legislation to save daylight,
      +# the city of Moose Jaw [Saskatchewan] has acted on its own hook."
      +# DST in Moose Jaw began on Saturday, 1912-06-01 (no time mentioned:
      +# presumably late evening, as below), and would run until "the end of
      +# the summer".  The discrepancy between municipal time and railroad
      +# time was noted.
      +
      +# From Paul Eggert (2003-07-27):
      +# Willett (1914-03) notes that DST "has been in operation ... in the
      +# City of Moose Jaw, Saskatchewan, for one year."
      +
      +# From Paul Eggert (2006-03-22):
      +# Shanks & Pottenger say that since 1970 this region has mostly been as Regina.
      +# Some western towns (e.g. Swift Current) switched from MST/MDT to CST in 1972.
      +# Other western towns (e.g. Lloydminster) are like Edmonton.
      +# Matthews and Vincent (1998) write that Denare Beach and Creighton
      +# are like Winnipeg, in violation of Saskatchewan law.
      +
      +# From W. Jones (1992-11-06):
      +# The. . .below is based on information I got from our law library, the
      +# provincial archives, and the provincial Community Services department.
      +# A precise history would require digging through newspaper archives, and
      +# since you didn't say what you wanted, I didn't bother.
      +#
      +# Saskatchewan is split by a time zone meridian (105W) and over the years
      +# the boundary became pretty ragged as communities near it reevaluated
      +# their affiliations in one direction or the other.  In 1965 a provincial
      +# referendum favoured legislating common time practices.
      +#
      +# On 15 April 1966 the Time Act (c. T-14, Revised Statutes of
      +# Saskatchewan 1978) was proclaimed, and established that the eastern
      +# part of Saskatchewan would use CST year round, that districts in
      +# northwest Saskatchewan would by default follow CST but could opt to
      +# follow Mountain Time rules (thus 1 hour difference in the winter and
      +# zero in the summer), and that districts in southwest Saskatchewan would
      +# by default follow MT but could opt to follow CST.
      +#
      +# It took a few years for the dust to settle (I know one story of a town
      +# on one time zone having its school in another, such that a mom had to
      +# serve her family lunch in two shifts), but presently it seems that only
      +# a few towns on the border with Alberta (e.g. Lloydminster) follow MT
      +# rules any more; all other districts appear to have used CST year round
      +# since sometime in the 1960s.
      +
      +# From Chris Walton (2006-06-26):
      +# The Saskatchewan time act which was last updated in 1996 is about 30 pages
      +# long and rather painful to read.
      +# http://www.qp.gov.sk.ca/documents/English/Statutes/Statutes/T14.pdf
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Regina	1918	only	-	Apr	14	2:00	1:00	D
      +Rule	Regina	1918	only	-	Oct	27	2:00	0	S
      +Rule	Regina	1930	1934	-	May	Sun>=1	0:00	1:00	D
      +Rule	Regina	1930	1934	-	Oct	Sun>=1	0:00	0	S
      +Rule	Regina	1937	1941	-	Apr	Sun>=8	0:00	1:00	D
      +Rule	Regina	1937	only	-	Oct	Sun>=8	0:00	0	S
      +Rule	Regina	1938	only	-	Oct	Sun>=1	0:00	0	S
      +Rule	Regina	1939	1941	-	Oct	Sun>=8	0:00	0	S
      +Rule	Regina	1942	only	-	Feb	 9	2:00	1:00	W # War
      +Rule	Regina	1945	only	-	Aug	14	23:00u	1:00	P # Peace
      +Rule	Regina	1945	only	-	Sep	lastSun	2:00	0	S
      +Rule	Regina	1946	only	-	Apr	Sun>=8	2:00	1:00	D
      +Rule	Regina	1946	only	-	Oct	Sun>=8	2:00	0	S
      +Rule	Regina	1947	1957	-	Apr	lastSun	2:00	1:00	D
      +Rule	Regina	1947	1957	-	Sep	lastSun	2:00	0	S
      +Rule	Regina	1959	only	-	Apr	lastSun	2:00	1:00	D
      +Rule	Regina	1959	only	-	Oct	lastSun	2:00	0	S
      +#
      +Rule	Swift	1957	only	-	Apr	lastSun	2:00	1:00	D
      +Rule	Swift	1957	only	-	Oct	lastSun	2:00	0	S
      +Rule	Swift	1959	1961	-	Apr	lastSun	2:00	1:00	D
      +Rule	Swift	1959	only	-	Oct	lastSun	2:00	0	S
      +Rule	Swift	1960	1961	-	Sep	lastSun	2:00	0	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Regina	-6:58:36 -	LMT	1905 Sep
      +			-7:00	Regina	M%sT	1960 Apr lastSun 2:00
      +			-6:00	-	CST
      +Zone America/Swift_Current -7:11:20 -	LMT	1905 Sep
      +			-7:00	Canada	M%sT	1946 Apr lastSun 2:00
      +			-7:00	Regina	M%sT	1950
      +			-7:00	Swift	M%sT	1972 Apr lastSun 2:00
      +			-6:00	-	CST
      +
      +
      +# Alberta
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Edm	1918	1919	-	Apr	Sun>=8	2:00	1:00	D
      +Rule	Edm	1918	only	-	Oct	27	2:00	0	S
      +Rule	Edm	1919	only	-	May	27	2:00	0	S
      +Rule	Edm	1920	1923	-	Apr	lastSun	2:00	1:00	D
      +Rule	Edm	1920	only	-	Oct	lastSun	2:00	0	S
      +Rule	Edm	1921	1923	-	Sep	lastSun	2:00	0	S
      +Rule	Edm	1942	only	-	Feb	 9	2:00	1:00	W # War
      +Rule	Edm	1945	only	-	Aug	14	23:00u	1:00	P # Peace
      +Rule	Edm	1945	only	-	Sep	lastSun	2:00	0	S
      +Rule	Edm	1947	only	-	Apr	lastSun	2:00	1:00	D
      +Rule	Edm	1947	only	-	Sep	lastSun	2:00	0	S
      +Rule	Edm	1967	only	-	Apr	lastSun	2:00	1:00	D
      +Rule	Edm	1967	only	-	Oct	lastSun	2:00	0	S
      +Rule	Edm	1969	only	-	Apr	lastSun	2:00	1:00	D
      +Rule	Edm	1969	only	-	Oct	lastSun	2:00	0	S
      +Rule	Edm	1972	1986	-	Apr	lastSun	2:00	1:00	D
      +Rule	Edm	1972	2006	-	Oct	lastSun	2:00	0	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Edmonton	-7:33:52 -	LMT	1906 Sep
      +			-7:00	Edm	M%sT	1987
      +			-7:00	Canada	M%sT
      +
      +
      +# British Columbia
      +
      +# From Paul Eggert (2006-03-22):
      +# Shanks & Pottenger write that since 1970 most of this region has
      +# been like Vancouver.
      +# Dawson Creek uses MST.  Much of east BC is like Edmonton.
      +# Matthews and Vincent (1998) write that Creston is like Dawson Creek.
      +
      +# It seems though that (re: Creston) is not entirely correct:
      +
      +# From Chris Walton (2011-12-01):
      +# There are two areas within the Canadian province of British Columbia
      +# that do not currently observe daylight saving:
      +# a) The Creston Valley (includes the town of Creston and surrounding area)
      +# b) The eastern half of the Peace River Regional District
      +# (includes the cities of Dawson Creek and Fort St. John)
      +
      +# Earlier this year I stumbled across a detailed article about the time
      +# keeping history of Creston; it was written by Tammy Hardwick who is the
      +# manager of the Creston & District Museum. The article was written in May 2009.
      +# 
      +# http://www.ilovecreston.com/?p=articles&t=spec&ar=260
      +# 
      +# According to the article, Creston has not changed its clocks since June 1918.
      +# i.e. Creston has been stuck on UTC-7 for 93 years.
      +# Dawson Creek, on the other hand, changed its clocks as recently as April 1972.
      +
      +# Unfortunately the exact date for the time change in June 1918 remains
      +# unknown and will be difficult to ascertain.  I e-mailed Tammy a few months
      +# ago to ask if Sunday June 2 was a reasonable guess.  She said it was just
      +# as plausible as any other date (in June).  She also said that after writing the
      +# article she had discovered another time change in 1916; this is the subject
      +# of another article which she wrote in October 2010.
      +# 
      +# http://www.creston.museum.bc.ca/index.php?module=comments&uop=view_comment&cm+id=56
      +# 
      +
      +# Here is a summary of the three clock change events in Creston's history:
      +# 1. 1884 or 1885: adoption of Mountain Standard Time (GMT-7)
      +# Exact date unknown
      +# 2. Oct 1916: switch to Pacific Standard Time (GMT-8)
      +# Exact date in October unknown;  Sunday October 1 is a reasonable guess.
      +# 3. June 1918: switch to Pacific Daylight Time (GMT-7)
      +# Exact date in June unknown; Sunday June 2 is a reasonable guess.
      +# note#1:
      +# On Oct 27/1918 when daylight saving ended in the rest of Canada,
      +# Creston did not change its clocks.
      +# note#2:
      +# During WWII when the Federal Government legislated a mandatory clock change,
      +# Creston did not oblige.
      +# note#3:
      +# There is no guarantee that Creston will remain on Mountain Standard Time
      +# (UTC-7) forever.
      +# The subject was debated at least once this year by the town Council.
      +# 
      +# http://www.bclocalnews.com/kootenay_rockies/crestonvalleyadvance/news/116760809.html
      +# 
      +
      +# During a period WWII, summer time (Daylight saying) was mandatory in Canada.
      +# In Creston, that was handled by shifting the area to PST (-8:00) then applying
      +# summer time to cause the offset to be -7:00, the same as it had been before
      +# the change.  It can be argued that the timezone abbreviation during this
      +# period should be PDT rather than MST, but that doesn't seem important enough
      +# (to anyone) to further complicate the rules.
      +
      +# The transition dates (and times) are guesses.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Vanc	1918	only	-	Apr	14	2:00	1:00	D
      +Rule	Vanc	1918	only	-	Oct	27	2:00	0	S
      +Rule	Vanc	1942	only	-	Feb	 9	2:00	1:00	W # War
      +Rule	Vanc	1945	only	-	Aug	14	23:00u	1:00	P # Peace
      +Rule	Vanc	1945	only	-	Sep	30	2:00	0	S
      +Rule	Vanc	1946	1986	-	Apr	lastSun	2:00	1:00	D
      +Rule	Vanc	1946	only	-	Oct	13	2:00	0	S
      +Rule	Vanc	1947	1961	-	Sep	lastSun	2:00	0	S
      +Rule	Vanc	1962	2006	-	Oct	lastSun	2:00	0	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Vancouver	-8:12:28 -	LMT	1884
      +			-8:00	Vanc	P%sT	1987
      +			-8:00	Canada	P%sT
      +Zone America/Dawson_Creek -8:00:56 -	LMT	1884
      +			-8:00	Canada	P%sT	1947
      +			-8:00	Vanc	P%sT	1972 Aug 30 2:00
      +			-7:00	-	MST
      +Zone America/Creston	-7:46:04 -	LMT	1884
      +			-7:00	-	MST	1916 Oct 1
      +			-8:00	-	PST	1918 Jun 2
      +			-7:00	-	MST
      +
      +# Northwest Territories, Nunavut, Yukon
      +
      +# From Paul Eggert (2006-03-22):
      +# Dawson switched to PST in 1973.  Inuvik switched to MST in 1979.
      +# Mathew Englander (1996-10-07) gives the following refs:
      +#	* 1967. Paragraph 28(34)(g) of the Interpretation Act, S.C. 1967-68,
      +#	c. 7 defines Yukon standard time as UTC-9.  This is still valid;
      +#	see Interpretation Act, R.S.C. 1985, c. I-21, s. 35(1).
      +#	* C.O. 1973/214 switched Yukon to PST on 1973-10-28 00:00.
      +#	* O.I.C. 1980/02 established DST.
      +#	* O.I.C. 1987/056 changed DST to Apr firstSun 2:00 to Oct lastSun 2:00.
      +# Shanks & Pottenger say Yukon's 1973-10-28 switch was at 2:00; go
      +# with Englander.
      +# From Chris Walton (2006-06-26):
      +# Here is a link to the old daylight saving portion of the interpretation
      +# act which was last updated in 1987:
      +# http://www.gov.yk.ca/legislation/regs/oic1987_056.pdf
      +
      +# From Rives McDow (1999-09-04):
      +# Nunavut ... moved ... to incorporate the whole territory into one time zone.
      +# 
      +# Nunavut moves to single time zone Oct. 31
      +# 
      +#
      +# From Antoine Leca (1999-09-06):
      +# We then need to create a new timezone for the Kitikmeot region of Nunavut
      +# to differentiate it from the Yellowknife region.
      +
      +# From Paul Eggert (1999-09-20):
      +# 
      +# Basic Facts: The New Territory
      +#  (1999) reports that Pangnirtung operates on eastern time,
      +# and that Coral Harbour does not observe DST.  We don't know when
      +# Pangnirtung switched to eastern time; we'll guess 1995.
      +
      +# From Rives McDow (1999-11-08):
      +# On October 31, when the rest of Nunavut went to Central time,
      +# Pangnirtung wobbled.  Here is the result of their wobble:
      +#
      +# The following businesses and organizations in Pangnirtung use Central Time:
      +#
      +#	First Air, Power Corp, Nunavut Construction, Health Center, RCMP,
      +#	Eastern Arctic National Parks, A & D Specialist
      +#
      +# The following businesses and organizations in Pangnirtung use Eastern Time:
      +#
      +#	Hamlet office, All other businesses, Both schools, Airport operator
      +#
      +# This has made for an interesting situation there, which warranted the news.
      +# No one there that I spoke with seems concerned, or has plans to
      +# change the local methods of keeping time, as it evidently does not
      +# really interfere with any activities or make things difficult locally.
      +# They plan to celebrate New Year's turn-over twice, one hour apart,
      +# so it appears that the situation will last at least that long.
      +# The Nunavut Intergovernmental Affairs hopes that they will "come to
      +# their senses", but the locals evidently don't see any problem with
      +# the current state of affairs.
      +
      +# From Michaela Rodrigue, writing in the
      +# 
      +# Nunatsiaq News (1999-11-19):
      +# Clyde River, Pangnirtung and Sanikiluaq now operate with two time zones,
      +# central - or Nunavut time - for government offices, and eastern time
      +# for municipal offices and schools....  Igloolik [was similar but then]
      +# made the switch to central time on Saturday, Nov. 6.
      +
      +# From Paul Eggert (2000-10-02):
      +# Matthews and Vincent (1998) say the following, but we lack histories
      +# for these potential new Zones.
      +#
      +# The Canadian Forces station at Alert uses Eastern Time while the
      +# handful of residents at the Eureka weather station [in the Central
      +# zone] skip daylight savings.  Baffin Island, which is crossed by the
      +# Central, Eastern and Atlantic Time zones only uses Eastern Time.
      +# Gjoa Haven, Taloyoak and Pelly Bay all use Mountain instead of
      +# Central Time and Southampton Island [in the Central zone] is not
      +# required to use daylight savings.
      +
      +# From
      +# 
      +# Nunavut now has two time zones
      +#  (2000-11-10):
      +# The Nunavut government would allow its employees in Kugluktuk and
      +# Cambridge Bay to operate on central time year-round, putting them
      +# one hour behind the rest of Nunavut for six months during the winter.
      +# At the end of October the two communities had rebelled against
      +# Nunavut's unified time zone, refusing to shift to eastern time with
      +# the rest of the territory for the winter.  Cambridge Bay remained on
      +# central time, while Kugluktuk, even farther west, reverted to
      +# mountain time, which they had used before the advent of Nunavut's
      +# unified time zone in 1999.
      +#
      +# From Rives McDow (2001-01-20), quoting the Nunavut government:
      +# The preceding decision came into effect at midnight, Saturday Nov 4, 2000.
      +
      +# From Paul Eggert (2000-12-04):
      +# Let's just keep track of the official times for now.
      +
      +# From Rives McDow (2001-03-07):
      +# The premier of Nunavut has issued a ministerial statement advising
      +# that effective 2001-04-01, the territory of Nunavut will revert
      +# back to three time zones (mountain, central, and eastern).  Of the
      +# cities in Nunavut, Coral Harbor is the only one that I know of that
      +# has said it will not observe dst, staying on EST year round.  I'm
      +# checking for more info, and will get back to you if I come up with
      +# more.
      +# [Also see  (2001-03-09).]
      +
      +# From Gwillim Law (2005-05-21):
      +# According to maps at
      +# http://inms-ienm.nrc-cnrc.gc.ca/images/time_services/TZ01SWE.jpg
      +# http://inms-ienm.nrc-cnrc.gc.ca/images/time_services/TZ01SSE.jpg
      +# (both dated 2003), and
      +# http://www.canadiangeographic.ca/Magazine/SO98/geomap.asp
      +# (from a 1998 Canadian Geographic article), the de facto and de jure time
      +# for Southampton Island (at the north end of Hudson Bay) is UTC-5 all year
      +# round.  Using Google, it's easy to find other websites that confirm this.
      +# I wasn't able to find how far back this time regimen goes, but since it
      +# predates the creation of Nunavut, it probably goes back many years....
      +# The Inuktitut name of Coral Harbour is Sallit, but it's rarely used.
      +#
      +# From Paul Eggert (2005-07-26):
      +# For lack of better information, assume that Southampton Island observed
      +# daylight saving only during wartime.
      +
      +# From Chris Walton (2007-03-01):
      +# ... the community of Resolute (located on Cornwallis Island in
      +# Nunavut) moved from Central Time to Eastern Time last November.
      +# Basically the community did not change its clocks at the end of
      +# daylight saving....
      +# http://www.nnsl.com/frames/newspapers/2006-11/nov13_06none.html
      +
      +# From Chris Walton (2011-03-21):
      +# Back in 2007 I initiated the creation of a new "zone file" for Resolute
      +# Bay. Resolute Bay is a small community located about 900km north of
      +# the Arctic Circle. The zone file was required because Resolute Bay had
      +# decided to use UTC-5 instead of UTC-6 for the winter of 2006-2007.
      +#
      +# According to new information which I received last week, Resolute Bay
      +# went back to using UTC-6 in the winter of 2007-2008...
      +#
      +# On March 11/2007 most of Canada went onto daylight saving. On March
      +# 14/2007 I phoned the Resolute Bay hamlet office to do a "time check." I
      +# talked to somebody that was both knowledgeable and helpful. I was able
      +# to confirm that Resolute Bay was still operating on UTC-5. It was
      +# explained to me that Resolute Bay had been on the Eastern Time zone
      +# (EST) in the winter, and was now back on the Central Time zone (CDT).
      +# i.e. the time zone had changed twice in the last year but the clocks
      +# had not moved. The residents had to know which time zone they were in
      +# so they could follow the correct TV schedule...
      +#
      +# On Nov 02/2008 most of Canada went onto standard time. On Nov 03/2008 I
      +# phoned the Resolute Bay hamlet office...[D]ue to the challenging nature
      +# of the phone call, I decided to seek out an alternate source of
      +# information. I found an e-mail address for somebody by the name of
      +# Stephanie Adams whose job was listed as "Inns North Support Officer for
      +# Arctic Co-operatives." I was under the impression that Stephanie lived
      +# and worked in Resolute Bay...
      +#
      +# On March 14/2011 I phoned the hamlet office again. I was told that
      +# Resolute Bay had been using Central Standard Time over the winter of
      +# 2010-2011 and that the clocks had therefore been moved one hour ahead
      +# on March 13/2011. The person I talked to was aware that Resolute Bay
      +# had previously experimented with Eastern Standard Time but he could not
      +# tell me when the practice had stopped.
      +#
      +# On March 17/2011 I searched the Web to find an e-mail address of
      +# somebody that might be able to tell me exactly when Resolute Bay went
      +# off Eastern Standard Time. I stumbled on the name "Aziz Kheraj." Aziz
      +# used to be the mayor of Resolute Bay and he apparently owns half the
      +# businesses including "South Camp Inn." This website has some info on
      +# Aziz:
      +# 
      +# http://www.uphere.ca/node/493
      +# 
      +#
      +# I sent Aziz an e-mail asking when Resolute Bay had stopped using
      +# Eastern Standard Time.
      +#
      +# Aziz responded quickly with this: "hi, The time was not changed for the
      +# 1 year only, the following year, the community went back to the old way
      +# of "spring ahead-fall behind" currently we are zulu plus 5 hrs and in
      +# the winter Zulu plus 6 hrs"
      +#
      +# This of course conflicted with everything I had ascertained in November 2008.
      +#
      +# I sent Aziz a copy of my 2008 e-mail exchange with Stephanie. Aziz
      +# responded with this: "Hi, Stephanie lives in Winnipeg. I live here, You
      +# may want to check with the weather office in Resolute Bay or do a
      +# search on the weather through Env. Canada. web site"
      +#
      +# If I had realized the Stephanie did not live in Resolute Bay I would
      +# never have contacted her.  I now believe that all the information I
      +# obtained in November 2008 should be ignored...
      +# I apologize for reporting incorrect information in 2008.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	NT_YK	1918	only	-	Apr	14	2:00	1:00	D
      +Rule	NT_YK	1918	only	-	Oct	27	2:00	0	S
      +Rule	NT_YK	1919	only	-	May	25	2:00	1:00	D
      +Rule	NT_YK	1919	only	-	Nov	 1	0:00	0	S
      +Rule	NT_YK	1942	only	-	Feb	 9	2:00	1:00	W # War
      +Rule	NT_YK	1945	only	-	Aug	14	23:00u	1:00	P # Peace
      +Rule	NT_YK	1945	only	-	Sep	30	2:00	0	S
      +Rule	NT_YK	1965	only	-	Apr	lastSun	0:00	2:00	DD
      +Rule	NT_YK	1965	only	-	Oct	lastSun	2:00	0	S
      +Rule	NT_YK	1980	1986	-	Apr	lastSun	2:00	1:00	D
      +Rule	NT_YK	1980	2006	-	Oct	lastSun	2:00	0	S
      +Rule	NT_YK	1987	2006	-	Apr	Sun>=1	2:00	1:00	D
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +# aka Panniqtuuq
      +Zone America/Pangnirtung 0	-	zzz	1921 # trading post est.
      +			-4:00	NT_YK	A%sT	1995 Apr Sun>=1 2:00
      +			-5:00	Canada	E%sT	1999 Oct 31 2:00
      +			-6:00	Canada	C%sT	2000 Oct 29 2:00
      +			-5:00	Canada	E%sT
      +# formerly Frobisher Bay
      +Zone America/Iqaluit	0	-	zzz	1942 Aug # Frobisher Bay est.
      +			-5:00	NT_YK	E%sT	1999 Oct 31 2:00
      +			-6:00	Canada	C%sT	2000 Oct 29 2:00
      +			-5:00	Canada	E%sT
      +# aka Qausuittuq
      +Zone America/Resolute	0	-	zzz	1947 Aug 31 # Resolute founded
      +			-6:00	NT_YK	C%sT	2000 Oct 29 2:00
      +			-5:00	-	EST	2001 Apr  1 3:00
      +			-6:00	Canada	C%sT	2006 Oct 29 2:00
      +			-5:00	-	EST	2007 Mar 11 3:00
      +			-6:00	Canada	C%sT
      +# aka Kangiqiniq
      +Zone America/Rankin_Inlet 0	-	zzz	1957 # Rankin Inlet founded
      +			-6:00	NT_YK	C%sT	2000 Oct 29 2:00
      +			-5:00	-	EST	2001 Apr  1 3:00
      +			-6:00	Canada	C%sT
      +# aka Iqaluktuuttiaq
      +Zone America/Cambridge_Bay 0	-	zzz	1920 # trading post est.?
      +			-7:00	NT_YK	M%sT	1999 Oct 31 2:00
      +			-6:00	Canada	C%sT	2000 Oct 29 2:00
      +			-5:00	-	EST	2000 Nov  5 0:00
      +			-6:00	-	CST	2001 Apr  1 3:00
      +			-7:00	Canada	M%sT
      +Zone America/Yellowknife 0	-	zzz	1935 # Yellowknife founded?
      +			-7:00	NT_YK	M%sT	1980
      +			-7:00	Canada	M%sT
      +Zone America/Inuvik	0	-	zzz	1953 # Inuvik founded
      +			-8:00	NT_YK	P%sT	1979 Apr lastSun 2:00
      +			-7:00	NT_YK	M%sT	1980
      +			-7:00	Canada	M%sT
      +Zone America/Whitehorse	-9:00:12 -	LMT	1900 Aug 20
      +			-9:00	NT_YK	Y%sT	1966 Jul 1 2:00
      +			-8:00	NT_YK	P%sT	1980
      +			-8:00	Canada	P%sT
      +Zone America/Dawson	-9:17:40 -	LMT	1900 Aug 20
      +			-9:00	NT_YK	Y%sT	1973 Oct 28 0:00
      +			-8:00	NT_YK	P%sT	1980
      +			-8:00	Canada	P%sT
      +
      +
      +###############################################################################
      +
      +# Mexico
      +
      +# From Paul Eggert (2001-03-05):
      +# The Investigation and Analysis Service of the
      +# Mexican Library of Congress (MLoC) has published a
      +# 
      +# history of Mexican local time (in Spanish)
      +# .
      +#
      +# Here are the discrepancies between Shanks & Pottenger (S&P) and the MLoC.
      +# (In all cases we go with the MLoC.)
      +# S&P report that Baja was at -8:00 in 1922/1923.
      +# S&P say the 1930 transition in Baja was 1930-11-16.
      +# S&P report no DST during summer 1931.
      +# S&P report a transition at 1932-03-30 23:00, not 1932-04-01.
      +
      +# From Gwillim Law (2001-02-20):
      +# There are some other discrepancies between the Decrees page and the
      +# tz database.  I think they can best be explained by supposing that
      +# the researchers who prepared the Decrees page failed to find some of
      +# the relevant documents.
      +
      +# From Alan Perry (1996-02-15):
      +# A guy from our Mexico subsidiary finally found the Presidential Decree
      +# outlining the timezone changes in Mexico.
      +#
      +# ------------- Begin Forwarded Message -------------
      +#
      +# I finally got my hands on the Official Presidential Decree that sets up the
      +# rules for the DST changes. The rules are:
      +#
      +# 1. The country is divided in 3 timezones:
      +#    - Baja California Norte (the Mexico/BajaNorte TZ)
      +#    - Baja California Sur, Nayarit, Sinaloa and Sonora (the Mexico/BajaSur TZ)
      +#    - The rest of the country (the Mexico/General TZ)
      +#
      +# 2. From the first Sunday in April at 2:00 AM to the last Sunday in October
      +#    at 2:00 AM, the times in each zone are as follows:
      +#    BajaNorte: GMT+7
      +#    BajaSur:   GMT+6
      +#    General:   GMT+5
      +#
      +# 3. The rest of the year, the times are as follows:
      +#    BajaNorte: GMT+8
      +#    BajaSur:   GMT+7
      +#    General:   GMT+6
      +#
      +# The Decree was published in Mexico's Official Newspaper on January 4th.
      +#
      +# -------------- End Forwarded Message --------------
      +# From Paul Eggert (1996-06-12):
      +# For an English translation of the decree, see
      +# 
      +# ``Diario Oficial: Time Zone Changeover'' (1996-01-04).
      +# 
      +
      +# From Rives McDow (1998-10-08):
      +# The State of Quintana Roo has reverted back to central STD and DST times
      +# (i.e. UTC -0600 and -0500 as of 1998-08-02).
      +
      +# From Rives McDow (2000-01-10):
      +# Effective April 4, 1999 at 2:00 AM local time, Sonora changed to the time
      +# zone 5 hours from the International Date Line, and will not observe daylight
      +# savings time so as to stay on the same time zone as the southern part of
      +# Arizona year round.
      +
      +# From Jesper Norgaard, translating
      +#  (2001-01-17):
      +# In Oaxaca, the 55.000 teachers from the Section 22 of the National
      +# Syndicate of Education Workers, refuse to apply daylight saving each
      +# year, so that the more than 10,000 schools work at normal hour the
      +# whole year.
      +
      +# From Gwillim Law (2001-01-19):
      +#  ... says
      +# (translated):...
      +# January 17, 2000 - The Energy Secretary, Ernesto Martens, announced
      +# that Summer Time will be reduced from seven to five months, starting
      +# this year....
      +# 
      +# [translated], says "summer time will ... take effect on the first Sunday
      +# in May, and end on the last Sunday of September.
      +
      +# From Arthur David Olson (2001-01-25):
      +# The 2001-01-24 traditional Washington Post contained the page one
      +# story "Timely Issue Divides Mexicans."...
      +# http://www.washingtonpost.com/wp-dyn/articles/A37383-2001Jan23.html
      +# ... Mexico City Mayor Lopez Obrador "...is threatening to keep
      +# Mexico City and its 20 million residents on a different time than
      +# the rest of the country..." In particular, Lopez Obrador would abolish
      +# observation of Daylight Saving Time.
      +
      +# 
      +# Official statute published by the Energy Department
      +#  (2001-02-01) shows Baja and Chihauhua as still using US DST rules,
      +# and Sonora with no DST.  This was reported by Jesper Norgaard (2001-02-03).
      +
      +# From Paul Eggert (2001-03-03):
      +#
      +# 
      +# James F. Smith writes in today's LA Times
      +# 
      +# * Sonora will continue to observe standard time.
      +# * Last week Mexico City's mayor Andres Manuel Lopez Obrador decreed that
      +#   the Federal District will not adopt DST.
      +# * 4 of 16 district leaders announced they'll ignore the decree.
      +# * The decree does not affect federal-controlled facilities including
      +#   the airport, banks, hospitals, and schools.
      +#
      +# For now we'll assume that the Federal District will bow to federal rules.
      +
      +# From Jesper Norgaard (2001-04-01):
      +# I found some references to the Mexican application of daylight
      +# saving, which modifies what I had already sent you, stating earlier
      +# that a number of northern Mexican states would go on daylight
      +# saving. The modification reverts this to only cover Baja California
      +# (Norte), while all other states (except Sonora, who has no daylight
      +# saving all year) will follow the original decree of president
      +# Vicente Fox, starting daylight saving May 6, 2001 and ending
      +# September 30, 2001.
      +# References: "Diario de Monterrey" 
      +# Palabra  (2001-03-31)
      +
      +# From Reuters (2001-09-04):
      +# Mexico's Supreme Court on Tuesday declared that daylight savings was
      +# unconstitutional in Mexico City, creating the possibility the
      +# capital will be in a different time zone from the rest of the nation
      +# next year....  The Supreme Court's ruling takes effect at 2:00
      +# a.m. (0800 GMT) on Sept. 30, when Mexico is scheduled to revert to
      +# standard time. "This is so residents of the Federal District are not
      +# subject to unexpected time changes," a statement from the court said.
      +
      +# From Jesper Norgaard Welen (2002-03-12):
      +# ... consulting my local grocery store(!) and my coworkers, they all insisted
      +# that a new decision had been made to reinstate US style DST in Mexico....
      +# http://www.conae.gob.mx/ahorro/horaver2001_m1_2002.html (2002-02-20)
      +# confirms this.  Sonora as usual is the only state where DST is not applied.
      +
      +# From Steffen Thorsen (2009-12-28):
      +#
      +# Steffen Thorsen wrote:
      +# > Mexico's House of Representatives has approved a proposal for northern
      +# > Mexico's border cities to share the same daylight saving schedule as
      +# > the United States.
      +# Now this has passed both the Congress and the Senate, so starting from
      +# 2010, some border regions will be the same:
      +# 
      +# http://www.signonsandiego.com/news/2009/dec/28/clocks-will-match-both-sides-border/
      +# 
      +# 
      +# http://www.elmananarey.com/diario/noticia/nacional/noticias/empatan_horario_de_frontera_con_eu/621939
      +# 
      +# (Spanish)
      +#
      +# Could not find the new law text, but the proposed law text changes are here:
      +# 
      +# http://gaceta.diputados.gob.mx/Gaceta/61/2009/dic/20091210-V.pdf
      +# 
      +# (Gaceta Parlamentaria)
      +#
      +# There is also a list of the votes here:
      +# 
      +# http://gaceta.diputados.gob.mx/Gaceta/61/2009/dic/V2-101209.html
      +# 
      +#
      +# Our page:
      +# 
      +# http://www.timeanddate.com/news/time/north-mexico-dst-change.html
      +# 
      +
      +# From Arthur David Olson (2010-01-20):
      +# The page
      +# 
      +# http://dof.gob.mx/nota_detalle.php?codigo=5127480&fecha=06/01/2010
      +# 
      +# includes this text:
      +# En los municipios fronterizos de Tijuana y Mexicali en Baja California;
      +# Juárez y Ojinaga en Chihuahua; Acuña y Piedras Negras en Coahuila;
      +# Anáhuac en Nuevo León; y Nuevo Laredo, Reynosa y Matamoros en
      +# Tamaulipas, la aplicación de este horario estacional surtirá efecto
      +# desde las dos horas del segundo domingo de marzo y concluirá a las dos
      +# horas del primer domingo de noviembre.
      +# En los municipios fronterizos que se encuentren ubicados en la franja
      +# fronteriza norte en el territorio comprendido entre la línea
      +# internacional y la línea paralela ubicada a una distancia de veinte
      +# kilómetros, así como la Ciudad de Ensenada, Baja California, hacia el
      +# interior del país, la aplicación de este horario estacional surtirá
      +# efecto desde las dos horas del segundo domingo de marzo y concluirá a
      +# las dos horas del primer domingo de noviembre.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Mexico	1939	only	-	Feb	5	0:00	1:00	D
      +Rule	Mexico	1939	only	-	Jun	25	0:00	0	S
      +Rule	Mexico	1940	only	-	Dec	9	0:00	1:00	D
      +Rule	Mexico	1941	only	-	Apr	1	0:00	0	S
      +Rule	Mexico	1943	only	-	Dec	16	0:00	1:00	W # War
      +Rule	Mexico	1944	only	-	May	1	0:00	0	S
      +Rule	Mexico	1950	only	-	Feb	12	0:00	1:00	D
      +Rule	Mexico	1950	only	-	Jul	30	0:00	0	S
      +Rule	Mexico	1996	2000	-	Apr	Sun>=1	2:00	1:00	D
      +Rule	Mexico	1996	2000	-	Oct	lastSun	2:00	0	S
      +Rule	Mexico	2001	only	-	May	Sun>=1	2:00	1:00	D
      +Rule	Mexico	2001	only	-	Sep	lastSun	2:00	0	S
      +Rule	Mexico	2002	max	-	Apr	Sun>=1	2:00	1:00	D
      +Rule	Mexico	2002	max	-	Oct	lastSun	2:00	0	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +# Quintana Roo
      +Zone America/Cancun	-5:47:04 -	LMT	1922 Jan  1  0:12:56
      +			-6:00	-	CST	1981 Dec 23
      +			-5:00	Mexico	E%sT	1998 Aug  2  2:00
      +			-6:00	Mexico	C%sT
      +# Campeche, Yucatan
      +Zone America/Merida	-5:58:28 -	LMT	1922 Jan  1  0:01:32
      +			-6:00	-	CST	1981 Dec 23
      +			-5:00	-	EST	1982 Dec  2
      +			-6:00	Mexico	C%sT
      +# Coahuila, Durango, Nuevo Leon, Tamaulipas (near US border)
      +Zone America/Matamoros	-6:40:00 -	LMT	1921 Dec 31 23:20:00
      +			-6:00	-	CST	1988
      +			-6:00	US	C%sT	1989
      +			-6:00	Mexico	C%sT	2010
      +			-6:00	US	C%sT
      +# Coahuila, Durango, Nuevo Leon, Tamaulipas (away from US border)
      +Zone America/Monterrey	-6:41:16 -	LMT	1921 Dec 31 23:18:44
      +			-6:00	-	CST	1988
      +			-6:00	US	C%sT	1989
      +			-6:00	Mexico	C%sT
      +# Central Mexico
      +Zone America/Mexico_City -6:36:36 -	LMT	1922 Jan  1 0:23:24
      +			-7:00	-	MST	1927 Jun 10 23:00
      +			-6:00	-	CST	1930 Nov 15
      +			-7:00	-	MST	1931 May  1 23:00
      +			-6:00	-	CST	1931 Oct
      +			-7:00	-	MST	1932 Apr  1
      +			-6:00	Mexico	C%sT	2001 Sep 30 02:00
      +			-6:00	-	CST	2002 Feb 20
      +			-6:00	Mexico	C%sT
      +# Chihuahua (near US border)
      +Zone America/Ojinaga	-6:57:40 -	LMT	1922 Jan 1 0:02:20
      +			-7:00	-	MST	1927 Jun 10 23:00
      +			-6:00	-	CST	1930 Nov 15
      +			-7:00	-	MST	1931 May  1 23:00
      +			-6:00	-	CST	1931 Oct
      +			-7:00	-	MST	1932 Apr  1
      +			-6:00	-	CST	1996
      +			-6:00	Mexico	C%sT	1998
      +			-6:00	-	CST	1998 Apr Sun>=1 3:00
      +			-7:00	Mexico	M%sT	2010
      +			-7:00	US	M%sT
      +# Chihuahua (away from US border)
      +Zone America/Chihuahua	-7:04:20 -	LMT	1921 Dec 31 23:55:40
      +			-7:00	-	MST	1927 Jun 10 23:00
      +			-6:00	-	CST	1930 Nov 15
      +			-7:00	-	MST	1931 May  1 23:00
      +			-6:00	-	CST	1931 Oct
      +			-7:00	-	MST	1932 Apr  1
      +			-6:00	-	CST	1996
      +			-6:00	Mexico	C%sT	1998
      +			-6:00	-	CST	1998 Apr Sun>=1 3:00
      +			-7:00	Mexico	M%sT
      +# Sonora
      +Zone America/Hermosillo	-7:23:52 -	LMT	1921 Dec 31 23:36:08
      +			-7:00	-	MST	1927 Jun 10 23:00
      +			-6:00	-	CST	1930 Nov 15
      +			-7:00	-	MST	1931 May  1 23:00
      +			-6:00	-	CST	1931 Oct
      +			-7:00	-	MST	1932 Apr  1
      +			-6:00	-	CST	1942 Apr 24
      +			-7:00	-	MST	1949 Jan 14
      +			-8:00	-	PST	1970
      +			-7:00	Mexico	M%sT	1999
      +			-7:00	-	MST
      +
      +# From Alexander Krivenyshev (2010-04-21):
      +# According to news, Bahía de Banderas (Mexican state of Nayarit)
      +# changed time zone UTC-7 to new time zone UTC-6 on April 4, 2010 (to
      +# share the same time zone as nearby city Puerto Vallarta, Jalisco).
      +#
      +# (Spanish)
      +# Bahía de Banderas homologa su horario al del centro del
      +# país, a partir de este domingo
      +# 
      +# http://www.nayarit.gob.mx/notes.asp?id=20748
      +# 
      +#
      +# Bahía de Banderas homologa su horario con el del Centro del
      +# País
      +# 
      +# http://www.bahiadebanderas.gob.mx/principal/index.php?option=com_content&view=article&id=261:bahia-de-banderas-homologa-su-horario-con-el-del-centro-del-pais&catid=42:comunicacion-social&Itemid=50"
      +# 
      +#
      +# (English)
      +# Puerto Vallarta and Bahía de Banderas: One Time Zone
      +# 
      +# http://virtualvallarta.com/puertovallarta/puertovallarta/localnews/2009-12-03-Puerto-Vallarta-and-Bahia-de-Banderas-One-Time-Zone.shtml
      +# 
      +#
      +# or
      +# 
      +# http://www.worldtimezone.com/dst_news/dst_news_mexico08.html
      +# 
      +#
      +# "Mexico's Senate approved the amendments to the Mexican Schedule System that
      +# will allow Bahía de Banderas and Puerto Vallarta to share the same time
      +# zone ..."
      +# Baja California Sur, Nayarit, Sinaloa
      +
      +# From Arthur David Olson (2010-05-01):
      +# Use "Bahia_Banderas" to keep the name to fourteen characters.
      +
      +Zone America/Mazatlan	-7:05:40 -	LMT	1921 Dec 31 23:54:20
      +			-7:00	-	MST	1927 Jun 10 23:00
      +			-6:00	-	CST	1930 Nov 15
      +			-7:00	-	MST	1931 May  1 23:00
      +			-6:00	-	CST	1931 Oct
      +			-7:00	-	MST	1932 Apr  1
      +			-6:00	-	CST	1942 Apr 24
      +			-7:00	-	MST	1949 Jan 14
      +			-8:00	-	PST	1970
      +			-7:00	Mexico	M%sT
      +
      +Zone America/Bahia_Banderas	-7:01:00 -	LMT	1921 Dec 31 23:59:00
      +			-7:00	-	MST	1927 Jun 10 23:00
      +			-6:00	-	CST	1930 Nov 15
      +			-7:00	-	MST	1931 May  1 23:00
      +			-6:00	-	CST	1931 Oct
      +			-7:00	-	MST	1932 Apr  1
      +			-6:00	-	CST	1942 Apr 24
      +			-7:00	-	MST	1949 Jan 14
      +			-8:00	-	PST	1970
      +			-7:00	Mexico	M%sT	2010 Apr 4 2:00
      +			-6:00	Mexico	C%sT
      +
      +# Baja California (near US border)
      +Zone America/Tijuana	-7:48:04 -	LMT	1922 Jan  1  0:11:56
      +			-7:00	-	MST	1924
      +			-8:00	-	PST	1927 Jun 10 23:00
      +			-7:00	-	MST	1930 Nov 15
      +			-8:00	-	PST	1931 Apr  1
      +			-8:00	1:00	PDT	1931 Sep 30
      +			-8:00	-	PST	1942 Apr 24
      +			-8:00	1:00	PWT	1945 Aug 14 23:00u
      +			-8:00	1:00	PPT	1945 Nov 12 # Peace
      +			-8:00	-	PST	1948 Apr  5
      +			-8:00	1:00	PDT	1949 Jan 14
      +			-8:00	-	PST	1954
      +			-8:00	CA	P%sT	1961
      +			-8:00	-	PST	1976
      +			-8:00	US	P%sT	1996
      +			-8:00	Mexico	P%sT	2001
      +			-8:00	US	P%sT	2002 Feb 20
      +			-8:00	Mexico	P%sT	2010
      +			-8:00	US	P%sT
      +# Baja California (away from US border)
      +Zone America/Santa_Isabel	-7:39:28 -	LMT	1922 Jan  1  0:20:32
      +			-7:00	-	MST	1924
      +			-8:00	-	PST	1927 Jun 10 23:00
      +			-7:00	-	MST	1930 Nov 15
      +			-8:00	-	PST	1931 Apr  1
      +			-8:00	1:00	PDT	1931 Sep 30
      +			-8:00	-	PST	1942 Apr 24
      +			-8:00	1:00	PWT	1945 Aug 14 23:00u
      +			-8:00	1:00	PPT	1945 Nov 12 # Peace
      +			-8:00	-	PST	1948 Apr  5
      +			-8:00	1:00	PDT	1949 Jan 14
      +			-8:00	-	PST	1954
      +			-8:00	CA	P%sT	1961
      +			-8:00	-	PST	1976
      +			-8:00	US	P%sT	1996
      +			-8:00	Mexico	P%sT	2001
      +			-8:00	US	P%sT	2002 Feb 20
      +			-8:00	Mexico	P%sT
      +# From Paul Eggert (2006-03-22):
      +# Formerly there was an America/Ensenada zone, which differed from
      +# America/Tijuana only in that it did not observe DST from 1976
      +# through 1995.  This was as per Shanks (1999).  But Shanks & Pottenger say
      +# Ensenada did not observe DST from 1948 through 1975.  Guy Harris reports
      +# that the 1987 OAG says "Only Ensenada, Mexicale, San Felipe and
      +# Tijuana observe DST," which agrees with Shanks & Pottenger but implies that
      +# DST-observance was a town-by-town matter back then.  This concerns
      +# data after 1970 so most likely there should be at least one Zone
      +# other than America/Tijuana for Baja, but it's not clear yet what its
      +# name or contents should be.
      +#
      +# Revillagigedo Is
      +# no information
      +
      +###############################################################################
      +
      +# Anguilla
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Anguilla	-4:12:16 -	LMT	1912 Mar 2
      +			-4:00	-	AST
      +
      +# Antigua and Barbuda
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	America/Antigua	-4:07:12 -	LMT	1912 Mar 2
      +			-5:00	-	EST	1951
      +			-4:00	-	AST
      +
      +# Bahamas
      +#
      +# From Sue Williams (2006-12-07):
      +# The Bahamas announced about a month ago that they plan to change their DST
      +# rules to sync with the U.S. starting in 2007....
      +# http://www.jonesbahamas.com/?c=45&a=10412
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Bahamas	1964	1975	-	Oct	lastSun	2:00	0	S
      +Rule	Bahamas	1964	1975	-	Apr	lastSun	2:00	1:00	D
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	America/Nassau	-5:09:24 -	LMT	1912 Mar 2
      +			-5:00	Bahamas	E%sT	1976
      +			-5:00	US	E%sT
      +
      +# Barbados
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Barb	1977	only	-	Jun	12	2:00	1:00	D
      +Rule	Barb	1977	1978	-	Oct	Sun>=1	2:00	0	S
      +Rule	Barb	1978	1980	-	Apr	Sun>=15	2:00	1:00	D
      +Rule	Barb	1979	only	-	Sep	30	2:00	0	S
      +Rule	Barb	1980	only	-	Sep	25	2:00	0	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Barbados	-3:58:28 -	LMT	1924		# Bridgetown
      +			-3:58:28 -	BMT	1932	  # Bridgetown Mean Time
      +			-4:00	Barb	A%sT
      +
      +# Belize
      +# Whitman entirely disagrees with Shanks; go with Shanks & Pottenger.
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Belize	1918	1942	-	Oct	Sun>=2	0:00	0:30	HD
      +Rule	Belize	1919	1943	-	Feb	Sun>=9	0:00	0	S
      +Rule	Belize	1973	only	-	Dec	 5	0:00	1:00	D
      +Rule	Belize	1974	only	-	Feb	 9	0:00	0	S
      +Rule	Belize	1982	only	-	Dec	18	0:00	1:00	D
      +Rule	Belize	1983	only	-	Feb	12	0:00	0	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	America/Belize	-5:52:48 -	LMT	1912 Apr
      +			-6:00	Belize	C%sT
      +
      +# Bermuda
      +
      +# From Dan Jones, reporting in The Royal Gazette (2006-06-26):
      +
      +# Next year, however, clocks in the US will go forward on the second Sunday
      +# in March, until the first Sunday in November.  And, after the Time Zone
      +# (Seasonal Variation) Bill 2006 was passed in the House of Assembly on
      +# Friday, the same thing will happen in Bermuda.
      +# http://www.theroyalgazette.com/apps/pbcs.dll/article?AID=/20060529/NEWS/105290135
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Atlantic/Bermuda	-4:19:04 -	LMT	1930 Jan  1 2:00    # Hamilton
      +			-4:00	-	AST	1974 Apr 28 2:00
      +			-4:00	Bahamas	A%sT	1976
      +			-4:00	US	A%sT
      +
      +# Cayman Is
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	America/Cayman	-5:25:32 -	LMT	1890		# Georgetown
      +			-5:07:12 -	KMT	1912 Feb    # Kingston Mean Time
      +			-5:00	-	EST
      +
      +# Costa Rica
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	CR	1979	1980	-	Feb	lastSun	0:00	1:00	D
      +Rule	CR	1979	1980	-	Jun	Sun>=1	0:00	0	S
      +Rule	CR	1991	1992	-	Jan	Sat>=15	0:00	1:00	D
      +# IATA SSIM (1991-09) says the following was at 1:00;
      +# go with Shanks & Pottenger.
      +Rule	CR	1991	only	-	Jul	 1	0:00	0	S
      +Rule	CR	1992	only	-	Mar	15	0:00	0	S
      +# There are too many San Joses elsewhere, so we'll use `Costa Rica'.
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Costa_Rica	-5:36:20 -	LMT	1890		# San Jose
      +			-5:36:20 -	SJMT	1921 Jan 15 # San Jose Mean Time
      +			-6:00	CR	C%sT
      +# Coco
      +# no information; probably like America/Costa_Rica
      +
      +# Cuba
      +
      +# From Arthur David Olson (1999-03-29):
      +# The 1999-03-28 exhibition baseball game held in Havana, Cuba, between
      +# the Cuban National Team and the Baltimore Orioles was carried live on
      +# the Orioles Radio Network, including affiliate WTOP in Washington, DC.
      +# During the game, play-by-play announcer Jim Hunter noted that
      +# "We'll be losing two hours of sleep...Cuba switched to Daylight Saving
      +# Time today."  (The "two hour" remark referred to losing one hour of
      +# sleep on 1999-03-28--when the announcers were in Cuba as it switched
      +# to DST--and one more hour on 1999-04-04--when the announcers will have
      +# returned to Baltimore, which switches on that date.)
      +
      +# From Evert van der Veer via Steffen Thorsen (2004-10-28):
      +# Cuba is not going back to standard time this year.
      +# From Paul Eggert (2006-03-22):
      +# http://www.granma.cu/ingles/2004/septiembre/juev30/41medid-i.html
      +# says that it's due to a problem at the Antonio Guiteras
      +# thermoelectric plant, and says "This October there will be no return
      +# to normal hours (after daylight saving time)".
      +# For now, let's assume that it's a temporary measure.
      +
      +# From Carlos A. Carnero Delgado (2005-11-12):
      +# This year (just like in 2004-2005) there's no change in time zone
      +# adjustment in Cuba.  We will stay in daylight saving time:
      +# http://www.granma.cu/espanol/2005/noviembre/mier9/horario.html
      +
      +# From Jesper Norgaard Welen (2006-10-21):
      +# An article in GRANMA INTERNACIONAL claims that Cuba will end
      +# the 3 years of permanent DST next weekend, see
      +# http://www.granma.cu/ingles/2006/octubre/lun16/43horario.html
      +# "On Saturday night, October 28 going into Sunday, October 29, at 01:00,
      +# watches should be set back one hour -- going back to 00:00 hours -- returning
      +# to the normal schedule....
      +
      +# From Paul Eggert (2007-03-02):
      +# http://www.granma.cubaweb.cu/english/news/art89.html, dated yesterday,
      +# says Cuban clocks will advance at midnight on March 10.
      +# For lack of better information, assume Cuba will use US rules,
      +# except that it switches at midnight standard time as usual.
      +#
      +# From Steffen Thorsen (2007-10-25):
      +# Carlos Alberto Fonseca Arauz informed me that Cuba will end DST one week
      +# earlier - on the last Sunday of October, just like in 2006.
      +#
      +# He supplied these references:
      +#
      +# http://www.prensalatina.com.mx/article.asp?ID=%7B4CC32C1B-A9F7-42FB-8A07-8631AFC923AF%7D&language=ES
      +# http://actualidad.terra.es/sociedad/articulo/cuba_llama_ahorrar_energia_cambio_1957044.htm
      +#
      +# From Alex Kryvenishev (2007-10-25):
      +# Here is also article from Granma (Cuba):
      +#
      +# [Regira] el Horario Normal desde el [proximo] domingo 28 de octubre
      +# http://www.granma.cubaweb.cu/2007/10/24/nacional/artic07.html
      +#
      +# http://www.worldtimezone.com/dst_news/dst_news_cuba03.html
      +
      +# From Arthur David Olson (2008-03-09):
      +# I'm in Maryland which is now observing United States Eastern Daylight
      +# Time. At 9:44 local time I used RealPlayer to listen to
      +# 
      +# http://media.enet.cu/radioreloj
      +# , a Cuban information station, and heard
      +# the time announced as "ocho cuarenta y cuatro" ("eight forty-four"),
      +# indicating that Cuba is still on standard time.
      +
      +# From Steffen Thorsen (2008-03-12):
      +# It seems that Cuba will start DST on Sunday, 2007-03-16...
      +# It was announced yesterday, according to this source (in Spanish):
      +# 
      +# http://www.nnc.cubaweb.cu/marzo-2008/cien-1-11-3-08.htm
      +# 
      +#
      +# Some more background information is posted here:
      +# 
      +# http://www.timeanddate.com/news/time/cuba-starts-dst-march-16.html
      +# 
      +#
      +# The article also says that Cuba has been observing DST since 1963,
      +# while Shanks (and tzdata) has 1965 as the first date (except in the
      +# 1940's). Many other web pages in Cuba also claim that it has been
      +# observed since 1963, but with the exception of 1970 - an exception
      +# which is not present in tzdata/Shanks. So there is a chance we need to
      +# change some historic records as well.
      +#
      +# One example:
      +# 
      +# http://www.radiohc.cu/espanol/noticias/mar07/11mar/hor.htm
      +# 
      +
      +# From Jesper Norgaard Welen (2008-03-13):
      +# The Cuban time change has just been confirmed on the most authoritative
      +# web site, the Granma.  Please check out
      +# 
      +# http://www.granma.cubaweb.cu/2008/03/13/nacional/artic10.html
      +# 
      +#
      +# Basically as expected after Steffen Thorsens information, the change
      +# will take place midnight between Saturday and Sunday.
      +
      +# From Arthur David Olson (2008-03-12):
      +# Assume Sun>=15 (third Sunday) going forward.
      +
      +# From Alexander Krivenyshev (2009-03-04)
      +# According to the Radio Reloj - Cuba will start Daylight Saving Time on
      +# midnight between Saturday, March 07, 2009 and Sunday, March 08, 2009-
      +# not on midnight March 14 / March 15 as previously thought.
      +#
      +# 
      +# http://www.worldtimezone.com/dst_news/dst_news_cuba05.html
      +# (in Spanish)
      +# 
      +
      +# From Arthur David Olson (2009-03-09)
      +# I listened over the Internet to
      +# 
      +# http://media.enet.cu/readioreloj
      +# 
      +# this morning; when it was 10:05 a. m. here in Bethesda, Maryland the
      +# the time was announced as "diez cinco"--the same time as here, indicating
      +# that has indeed switched to DST. Assume second Sunday from 2009 forward.
      +
      +# From Steffen Thorsen (2011-03-08):
      +# Granma announced that Cuba is going to start DST on 2011-03-20 00:00:00
      +# this year. Nothing about the end date known so far (if that has
      +# changed at all).
      +#
      +# Source:
      +# 
      +# http://granma.co.cu/2011/03/08/nacional/artic01.html
      +# 
      +#
      +# Our info:
      +# 
      +# http://www.timeanddate.com/news/time/cuba-starts-dst-2011.html
      +# 
      +#
      +# From Steffen Thorsen (2011-10-30)
      +# Cuba will end DST two weeks later this year. Instead of going back
      +# tonight, it has been delayed to 2011-11-13 at 01:00.
      +#
      +# One source (Spanish)
      +# 
      +# http://www.radioangulo.cu/noticias/cuba/17105-cuba-restablecera-el-horario-del-meridiano-de-greenwich.html
      +# 
      +#
      +# Our page:
      +# 
      +# http://www.timeanddate.com/news/time/cuba-time-changes-2011.html
      +# 
      +#
      +# From Steffen Thorsen (2012-03-01)
      +# According to Radio Reloj, Cuba will start DST on Midnight between March
      +# 31 and April 1.
      +#
      +# Radio Reloj has the following info (Spanish):
      +# 
      +# http://www.radioreloj.cu/index.php/noticias-radio-reloj/71-miscelaneas/7529-cuba-aplicara-el-horario-de-verano-desde-el-1-de-abril
      +# 
      +#
      +# Our info on it:
      +# 
      +# http://www.timeanddate.com/news/time/cuba-starts-dst-2012.html
      +# 
      +
      +# From Steffen Thorsen (2012-11-03):
      +# Radio Reloj and many other sources report that Cuba is changing back
      +# to standard time on 2012-11-04:
      +# http://www.radioreloj.cu/index.php/noticias-radio-reloj/36-nacionales/9961-regira-horario-normal-en-cuba-desde-el-domingo-cuatro-de-noviembre
      +# From Paul Eggert (2012-11-03):
      +# For now, assume the future rule is first Sunday in November.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Cuba	1928	only	-	Jun	10	0:00	1:00	D
      +Rule	Cuba	1928	only	-	Oct	10	0:00	0	S
      +Rule	Cuba	1940	1942	-	Jun	Sun>=1	0:00	1:00	D
      +Rule	Cuba	1940	1942	-	Sep	Sun>=1	0:00	0	S
      +Rule	Cuba	1945	1946	-	Jun	Sun>=1	0:00	1:00	D
      +Rule	Cuba	1945	1946	-	Sep	Sun>=1	0:00	0	S
      +Rule	Cuba	1965	only	-	Jun	1	0:00	1:00	D
      +Rule	Cuba	1965	only	-	Sep	30	0:00	0	S
      +Rule	Cuba	1966	only	-	May	29	0:00	1:00	D
      +Rule	Cuba	1966	only	-	Oct	2	0:00	0	S
      +Rule	Cuba	1967	only	-	Apr	8	0:00	1:00	D
      +Rule	Cuba	1967	1968	-	Sep	Sun>=8	0:00	0	S
      +Rule	Cuba	1968	only	-	Apr	14	0:00	1:00	D
      +Rule	Cuba	1969	1977	-	Apr	lastSun	0:00	1:00	D
      +Rule	Cuba	1969	1971	-	Oct	lastSun	0:00	0	S
      +Rule	Cuba	1972	1974	-	Oct	8	0:00	0	S
      +Rule	Cuba	1975	1977	-	Oct	lastSun	0:00	0	S
      +Rule	Cuba	1978	only	-	May	7	0:00	1:00	D
      +Rule	Cuba	1978	1990	-	Oct	Sun>=8	0:00	0	S
      +Rule	Cuba	1979	1980	-	Mar	Sun>=15	0:00	1:00	D
      +Rule	Cuba	1981	1985	-	May	Sun>=5	0:00	1:00	D
      +Rule	Cuba	1986	1989	-	Mar	Sun>=14	0:00	1:00	D
      +Rule	Cuba	1990	1997	-	Apr	Sun>=1	0:00	1:00	D
      +Rule	Cuba	1991	1995	-	Oct	Sun>=8	0:00s	0	S
      +Rule	Cuba	1996	only	-	Oct	 6	0:00s	0	S
      +Rule	Cuba	1997	only	-	Oct	12	0:00s	0	S
      +Rule	Cuba	1998	1999	-	Mar	lastSun	0:00s	1:00	D
      +Rule	Cuba	1998	2003	-	Oct	lastSun	0:00s	0	S
      +Rule	Cuba	2000	2004	-	Apr	Sun>=1	0:00s	1:00	D
      +Rule	Cuba	2006	2010	-	Oct	lastSun	0:00s	0	S
      +Rule	Cuba	2007	only	-	Mar	Sun>=8	0:00s	1:00	D
      +Rule	Cuba	2008	only	-	Mar	Sun>=15	0:00s	1:00	D
      +Rule	Cuba	2009	2010	-	Mar	Sun>=8	0:00s	1:00	D
      +Rule	Cuba	2011	only	-	Mar	Sun>=15	0:00s	1:00	D
      +Rule	Cuba	2011	only	-	Nov	13	0:00s	0	S
      +Rule	Cuba	2012	only	-	Apr	1	0:00s	1:00	D
      +Rule	Cuba	2012	max	-	Nov	Sun>=1	0:00s	0	S
      +Rule	Cuba	2013	max	-	Mar	Sun>=8	0:00s	1:00	D
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	America/Havana	-5:29:28 -	LMT	1890
      +			-5:29:36 -	HMT	1925 Jul 19 12:00 # Havana MT
      +			-5:00	Cuba	C%sT
      +
      +# Dominica
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Dominica	-4:05:36 -	LMT	1911 Jul 1 0:01		# Roseau
      +			-4:00	-	AST
      +
      +# Dominican Republic
      +
      +# From Steffen Thorsen (2000-10-30):
      +# Enrique Morales reported to me that the Dominican Republic has changed the
      +# time zone to Eastern Standard Time as of Sunday 29 at 2 am....
      +# http://www.listin.com.do/antes/261000/republica/princi.html
      +
      +# From Paul Eggert (2000-12-04):
      +# That URL (2000-10-26, in Spanish) says they planned to use US-style DST.
      +
      +# From Rives McDow (2000-12-01):
      +# Dominican Republic changed its mind and presidential decree on Tuesday,
      +# November 28, 2000, with a new decree.  On Sunday, December 3 at 1:00 AM the
      +# Dominican Republic will be reverting to 8 hours from the International Date
      +# Line, and will not be using DST in the foreseeable future.  The reason they
      +# decided to use DST was to be in synch with Puerto Rico, who was also going
      +# to implement DST.  When Puerto Rico didn't implement DST, the president
      +# decided to revert.
      +
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	DR	1966	only	-	Oct	30	0:00	1:00	D
      +Rule	DR	1967	only	-	Feb	28	0:00	0	S
      +Rule	DR	1969	1973	-	Oct	lastSun	0:00	0:30	HD
      +Rule	DR	1970	only	-	Feb	21	0:00	0	S
      +Rule	DR	1971	only	-	Jan	20	0:00	0	S
      +Rule	DR	1972	1974	-	Jan	21	0:00	0	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Santo_Domingo -4:39:36 -	LMT	1890
      +			-4:40	-	SDMT	1933 Apr  1 12:00 # S. Dom. MT
      +			-5:00	DR	E%sT	1974 Oct 27
      +			-4:00	-	AST	2000 Oct 29 02:00
      +			-5:00	US	E%sT	2000 Dec  3 01:00
      +			-4:00	-	AST
      +
      +# El Salvador
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Salv	1987	1988	-	May	Sun>=1	0:00	1:00	D
      +Rule	Salv	1987	1988	-	Sep	lastSun	0:00	0	S
      +# There are too many San Salvadors elsewhere, so use America/El_Salvador
      +# instead of America/San_Salvador.
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/El_Salvador -5:56:48 -	LMT	1921		# San Salvador
      +			-6:00	Salv	C%sT
      +
      +# Grenada
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	America/Grenada	-4:07:00 -	LMT	1911 Jul	# St George's
      +			-4:00	-	AST
      +
      +# Guadeloupe
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Guadeloupe	-4:06:08 -	LMT	1911 Jun 8	# Pointe a Pitre
      +			-4:00	-	AST
      +# St Barthelemy
      +Link America/Guadeloupe	America/St_Barthelemy
      +# St Martin (French part)
      +Link America/Guadeloupe	America/Marigot
      +
      +# Guatemala
      +#
      +# From Gwillim Law (2006-04-22), after a heads-up from Oscar van Vlijmen:
      +# Diario Co Latino, at
      +# http://www.diariocolatino.com/internacionales/detalles.asp?NewsID=8079,
      +# says in an article dated 2006-04-19 that the Guatemalan government had
      +# decided on that date to advance official time by 60 minutes, to lessen the
      +# impact of the elevated cost of oil....  Daylight saving time will last from
      +# 2006-04-29 24:00 (Guatemalan standard time) to 2006-09-30 (time unspecified).
      +# From Paul Eggert (2006-06-22):
      +# The Ministry of Energy and Mines, press release CP-15/2006
      +# (2006-04-19), says DST ends at 24:00.  See
      +# .
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Guat	1973	only	-	Nov	25	0:00	1:00	D
      +Rule	Guat	1974	only	-	Feb	24	0:00	0	S
      +Rule	Guat	1983	only	-	May	21	0:00	1:00	D
      +Rule	Guat	1983	only	-	Sep	22	0:00	0	S
      +Rule	Guat	1991	only	-	Mar	23	0:00	1:00	D
      +Rule	Guat	1991	only	-	Sep	 7	0:00	0	S
      +Rule	Guat	2006	only	-	Apr	30	0:00	1:00	D
      +Rule	Guat	2006	only	-	Oct	 1	0:00	0	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Guatemala	-6:02:04 -	LMT	1918 Oct 5
      +			-6:00	Guat	C%sT
      +
      +# Haiti
      +# From Gwillim Law (2005-04-15):
      +# Risto O. Nykanen wrote me that Haiti is now on DST.
      +# I searched for confirmation, and I found a
      +#  press release
      +# on the Web page of the Haitian Consulate in Chicago (2005-03-31),
      +# .  Translated from French, it says:
      +#
      +#  "The Prime Minister's Communication Office notifies the public in general
      +#   and the press in particular that, following a decision of the Interior
      +#   Ministry and the Territorial Collectivities [I suppose that means the
      +#   provinces], Haiti will move to Eastern Daylight Time in the night from next
      +#   Saturday the 2nd to Sunday the 3rd.
      +#
      +#  "Consequently, the Prime Minister's Communication Office wishes to inform
      +#   the population that the country's clocks will be set forward one hour
      +#   starting at midnight.  This provision will hold until the last Saturday in
      +#   October 2005.
      +#
      +#  "Port-au-Prince, March 31, 2005"
      +#
      +# From Steffen Thorsen (2006-04-04):
      +# I have been informed by users that Haiti observes DST this year like
      +# last year, so the current "only" rule for 2005 might be changed to a
      +# "max" rule or to last until 2006. (Who knows if they will observe DST
      +# next year or if they will extend their DST like US/Canada next year).
      +#
      +# I have found this article about it (in French):
      +# http://www.haitipressnetwork.com/news.cfm?articleID=7612
      +#
      +# The reason seems to be an energy crisis.
      +
      +# From Stephen Colebourne (2007-02-22):
      +# Some IATA info: Haiti won't be having DST in 2007.
      +
      +# From Steffen Thorsen (2012-03-11):
      +# According to several news sources, Haiti will observe DST this year,
      +# apparently using the same start and end date as USA/Canada.
      +# So this means they have already changed their time.
      +#
      +# (Sources in French):
      +# 
      +# http://www.alterpresse.org/spip.php?article12510
      +# 
      +# 
      +# http://radiovision2000haiti.net/home/?p=13253
      +# 
      +#
      +# Our coverage:
      +# 
      +# http://www.timeanddate.com/news/time/haiti-dst-2012.html
      +# 
      +
      +# From Arthur David Olson (2012-03-11):
      +# The alterpresse.org source seems to show a US-style leap from 2:00 a.m. to
      +# 3:00 a.m. rather than the traditional Haitian jump at midnight.
      +# Assume a US-style fall back as well XXX.
      +# Do not yet assume that the change carries forward past 2012 XXX.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Haiti	1983	only	-	May	8	0:00	1:00	D
      +Rule	Haiti	1984	1987	-	Apr	lastSun	0:00	1:00	D
      +Rule	Haiti	1983	1987	-	Oct	lastSun	0:00	0	S
      +# Shanks & Pottenger say AT is 2:00, but IATA SSIM (1991/1997) says 1:00s.
      +# Go with IATA.
      +Rule	Haiti	1988	1997	-	Apr	Sun>=1	1:00s	1:00	D
      +Rule	Haiti	1988	1997	-	Oct	lastSun	1:00s	0	S
      +Rule	Haiti	2005	2006	-	Apr	Sun>=1	0:00	1:00	D
      +Rule	Haiti	2005	2006	-	Oct	lastSun	0:00	0	S
      +Rule	Haiti	2012	only	-	Mar	Sun>=8	2:00	1:00	D
      +Rule	Haiti	2012	only	-	Nov	Sun>=1	2:00	0	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Port-au-Prince -4:49:20 -	LMT	1890
      +			-4:49	-	PPMT	1917 Jan 24 12:00 # P-a-P MT
      +			-5:00	Haiti	E%sT
      +
      +# Honduras
      +# Shanks & Pottenger say 1921 Jan 1; go with Whitman's more precise Apr 1.
      +
      +# From Paul Eggert (2006-05-05):
      +# worldtimezone.com reports a 2006-05-02 Spanish-language AP article
      +# saying Honduras will start using DST midnight Saturday, effective 4
      +# months until September.  La Tribuna reported today
      +#  that Manuel Zelaya, the president
      +# of Honduras, refused to back down on this.
      +
      +# From Jesper Norgaard Welen (2006-08-08):
      +# It seems that Honduras has returned from DST to standard time this Monday at
      +# 00:00 hours (prolonging Sunday to 25 hours duration).
      +# http://www.worldtimezone.com/dst_news/dst_news_honduras04.html
      +
      +# From Paul Eggert (2006-08-08):
      +# Also see Diario El Heraldo, The country returns to standard time (2006-08-08)
      +# .
      +# It mentions executive decree 18-2006.
      +
      +# From Steffen Thorsen (2006-08-17):
      +# Honduras will observe DST from 2007 to 2009, exact dates are not
      +# published, I have located this authoritative source:
      +# http://www.presidencia.gob.hn/noticia.aspx?nId=47
      +
      +# From Steffen Thorsen (2007-03-30):
      +# http://www.laprensahn.com/pais_nota.php?id04962=7386
      +# So it seems that Honduras will not enter DST this year....
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Hond	1987	1988	-	May	Sun>=1	0:00	1:00	D
      +Rule	Hond	1987	1988	-	Sep	lastSun	0:00	0	S
      +Rule	Hond	2006	only	-	May	Sun>=1	0:00	1:00	D
      +Rule	Hond	2006	only	-	Aug	Mon>=1	0:00	0	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Tegucigalpa -5:48:52 -	LMT	1921 Apr
      +			-6:00	Hond	C%sT
      +#
      +# Great Swan I ceded by US to Honduras in 1972
      +
      +# Jamaica
      +
      +# From Bob Devine (1988-01-28):
      +# Follows US rules.
      +
      +# From U. S. Naval Observatory (1989-01-19):
      +# JAMAICA             5 H  BEHIND UTC
      +
      +# From Shanks & Pottenger:
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	America/Jamaica	-5:07:12 -	LMT	1890		# Kingston
      +			-5:07:12 -	KMT	1912 Feb    # Kingston Mean Time
      +			-5:00	-	EST	1974 Apr 28 2:00
      +			-5:00	US	E%sT	1984
      +			-5:00	-	EST
      +
      +# Martinique
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Martinique	-4:04:20 -      LMT	1890		# Fort-de-France
      +			-4:04:20 -	FFMT	1911 May     # Fort-de-France MT
      +			-4:00	-	AST	1980 Apr  6
      +			-4:00	1:00	ADT	1980 Sep 28
      +			-4:00	-	AST
      +
      +# Montserrat
      +# From Paul Eggert (2006-03-22):
      +# In 1995 volcanic eruptions forced evacuation of Plymouth, the capital.
      +# world.gazetteer.com says Cork Hill is the most populous location now.
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Montserrat	-4:08:52 -	LMT	1911 Jul 1 0:01   # Cork Hill
      +			-4:00	-	AST
      +
      +# Nicaragua
      +#
      +# This uses Shanks & Pottenger for times before 2005.
      +#
      +# From Steffen Thorsen (2005-04-12):
      +# I've got reports from 8 different people that Nicaragua just started
      +# DST on Sunday 2005-04-10, in order to save energy because of
      +# expensive petroleum.  The exact end date for DST is not yet
      +# announced, only "September" but some sites also say "mid-September".
      +# Some background information is available on the President's official site:
      +# http://www.presidencia.gob.ni/Presidencia/Files_index/Secretaria/Notas%20de%20Prensa/Presidente/2005/ABRIL/Gobierno-de-nicaragua-adelanta-hora-oficial-06abril.htm
      +# The Decree, no 23-2005 is available here:
      +# http://www.presidencia.gob.ni/buscador_gaceta/BD/DECRETOS/2005/Decreto%2023-2005%20Se%20adelanta%20en%20una%20hora%20en%20todo%20el%20territorio%20nacional%20apartir%20de%20las%2024horas%20del%2009%20de%20Abril.pdf
      +#
      +# From Paul Eggert (2005-05-01):
      +# The decree doesn't say anything about daylight saving, but for now let's
      +# assume that it is daylight saving....
      +#
      +# From Gwillim Law (2005-04-21):
      +# The Associated Press story on the time change, which can be found at
      +# http://www.lapalmainteractivo.com/guias/content/gen/ap/America_Latina/AMC_GEN_NICARAGUA_HORA.html
      +# and elsewhere, says (fifth paragraph, translated from Spanish):  "The last
      +# time that a change of clocks was applied to save energy was in the year 2000
      +# during the Arnoldo Aleman administration."...
      +# The northamerica file says that Nicaragua has been on UTC-6 continuously
      +# since December 1998.  I wasn't able to find any details of Nicaraguan time
      +# changes in 2000.  Perhaps a note could be added to the northamerica file, to
      +# the effect that we have indirect evidence that DST was observed in 2000.
      +#
      +# From Jesper Norgaard Welen (2005-11-02):
      +# Nicaragua left DST the 2005-10-02 at 00:00 (local time).
      +# http://www.presidencia.gob.ni/presidencia/files_index/secretaria/comunicados/2005/septiembre/26septiembre-cambio-hora.htm
      +# (2005-09-26)
      +#
      +# From Jesper Norgaard Welen (2006-05-05):
      +# http://www.elnuevodiario.com.ni/2006/05/01/nacionales/18410
      +# (my informal translation)
      +# By order of the president of the republic, Enrique Bolanos, Nicaragua
      +# advanced by sixty minutes their official time, yesterday at 2 in the
      +# morning, and will stay that way until 30.th. of september.
      +#
      +# From Jesper Norgaard Welen (2006-09-30):
      +# http://www.presidencia.gob.ni/buscador_gaceta/BD/DECRETOS/2006/D-063-2006P-PRN-Cambio-Hora.pdf
      +# My informal translation runs:
      +# The natural sun time is restored in all the national territory, in that the
      +# time is returned one hour at 01:00 am of October 1 of 2006.
      +#
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Nic	1979	1980	-	Mar	Sun>=16	0:00	1:00	D
      +Rule	Nic	1979	1980	-	Jun	Mon>=23	0:00	0	S
      +Rule	Nic	2005	only	-	Apr	10	0:00	1:00	D
      +Rule	Nic	2005	only	-	Oct	Sun>=1	0:00	0	S
      +Rule	Nic	2006	only	-	Apr	30	2:00	1:00	D
      +Rule	Nic	2006	only	-	Oct	Sun>=1	1:00	0	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	America/Managua	-5:45:08 -	LMT	1890
      +			-5:45:12 -	MMT	1934 Jun 23 # Managua Mean Time?
      +			-6:00	-	CST	1973 May
      +			-5:00	-	EST	1975 Feb 16
      +			-6:00	Nic	C%sT	1992 Jan  1 4:00
      +			-5:00	-	EST	1992 Sep 24
      +			-6:00	-	CST	1993
      +			-5:00	-	EST	1997
      +			-6:00	Nic	C%sT
      +
      +# Panama
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	America/Panama	-5:18:08 -	LMT	1890
      +			-5:19:36 -	CMT	1908 Apr 22   # Colon Mean Time
      +			-5:00	-	EST
      +
      +# Puerto Rico
      +# There are too many San Juans elsewhere, so we'll use `Puerto_Rico'.
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Puerto_Rico -4:24:25 -	LMT	1899 Mar 28 12:00    # San Juan
      +			-4:00	-	AST	1942 May  3
      +			-4:00	US	A%sT	1946
      +			-4:00	-	AST
      +
      +# St Kitts-Nevis
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/St_Kitts	-4:10:52 -	LMT	1912 Mar 2	# Basseterre
      +			-4:00	-	AST
      +
      +# St Lucia
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/St_Lucia	-4:04:00 -	LMT	1890		# Castries
      +			-4:04:00 -	CMT	1912	    # Castries Mean Time
      +			-4:00	-	AST
      +
      +# St Pierre and Miquelon
      +# There are too many St Pierres elsewhere, so we'll use `Miquelon'.
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Miquelon	-3:44:40 -	LMT	1911 May 15	# St Pierre
      +			-4:00	-	AST	1980 May
      +			-3:00	-	PMST	1987 # Pierre & Miquelon Time
      +			-3:00	Canada	PM%sT
      +
      +# St Vincent and the Grenadines
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/St_Vincent	-4:04:56 -	LMT	1890		# Kingstown
      +			-4:04:56 -	KMT	1912	   # Kingstown Mean Time
      +			-4:00	-	AST
      +
      +# Turks and Caicos
      +#
      +# From Chris Dunn in
      +# 
      +# (2007-03-15): In the Turks & Caicos Islands (America/Grand_Turk) the
      +# daylight saving dates for time changes have been adjusted to match
      +# the recent U.S. change of dates.
      +#
      +# From Brian Inglis (2007-04-28):
      +# http://www.turksandcaicos.tc/calendar/index.htm [2007-04-26]
      +# there is an entry for Nov 4 "Daylight Savings Time Ends 2007" and three
      +# rows before that there is an out of date entry for Oct:
      +# "Eastern Standard Times Begins 2007
      +# Clocks are set back one hour at 2:00 a.m. local Daylight Saving Time"
      +# indicating that the normal ET rules are followed.
      +#
      +# From Paul Eggert (2006-05-01):
      +# Shanks & Pottenger say they use US DST rules, but IATA SSIM (1991/1998)
      +# says they switch at midnight.  Go with Shanks & Pottenger.
      +#
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	TC	1979	1986	-	Apr	lastSun	2:00	1:00	D
      +Rule	TC	1979	2006	-	Oct	lastSun	2:00	0	S
      +Rule	TC	1987	2006	-	Apr	Sun>=1	2:00	1:00	D
      +Rule	TC	2007	max	-	Mar	Sun>=8	2:00	1:00	D
      +Rule	TC	2007	max	-	Nov	Sun>=1	2:00	0	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Grand_Turk	-4:44:32 -	LMT	1890
      +			-5:07:12 -	KMT	1912 Feb    # Kingston Mean Time
      +			-5:00	TC	E%sT
      +
      +# British Virgin Is
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Tortola	-4:18:28 -	LMT	1911 Jul    # Road Town
      +			-4:00	-	AST
      +
      +# Virgin Is
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/St_Thomas	-4:19:44 -	LMT	1911 Jul    # Charlotte Amalie
      +			-4:00	-	AST
      diff --git a/jdk/test/sun/util/calendar/zi/tzdata/pacificnew b/jdk/test/sun/util/calendar/zi/tzdata/pacificnew
      new file mode 100644
      index 00000000000..7738a48087b
      --- /dev/null
      +++ b/jdk/test/sun/util/calendar/zi/tzdata/pacificnew
      @@ -0,0 +1,51 @@
      +#
      +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      +#  
      +# This code is free software; you can redistribute it and/or modify it
      +# under the terms of the GNU General Public License version 2 only, as
      +# published by the Free Software Foundation.  Oracle designates this
      +# particular file as subject to the "Classpath" exception as provided
      +# by Oracle in the LICENSE file that accompanied this code.
      +#  
      +# This code is distributed in the hope that it will be useful, but WITHOUT
      +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      +# version 2 for more details (a copy is included in the LICENSE file that
      +# accompanied this code).
      +#  
      +# You should have received a copy of the GNU General Public License version
      +# 2 along with this work; if not, write to the Free Software Foundation,
      +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      +#  
      +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      +# or visit www.oracle.com if you need additional information or have any
      +# questions.
      +#
      +# 
      +# This file is in the public domain, so clarified as of
      +# 2009-05-17 by Arthur David Olson.
      +
      +# From Arthur David Olson (1989-04-05):
      +# On 1989-04-05, the U. S. House of Representatives passed (238-154) a bill
      +# establishing "Pacific Presidential Election Time"; it was not acted on
      +# by the Senate or signed into law by the President.
      +# You might want to change the "PE" (Presidential Election) below to
      +# "Q" (Quadrennial) to maintain three-character zone abbreviations.
      +# If you're really conservative, you might want to change it to "D".
      +# Avoid "L" (Leap Year), which won't be true in 2100.
      +
      +# If Presidential Election Time is ever established, replace "XXXX" below
      +# with the year the law takes effect and uncomment the "##" lines.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +## Rule	Twilite	XXXX	max	-	Apr	Sun>=1	2:00	1:00	D
      +## Rule	Twilite	XXXX	max	uspres	Oct	lastSun	2:00	1:00	PE
      +## Rule	Twilite	XXXX	max	uspres	Nov	Sun>=7	2:00	0	S
      +## Rule	Twilite	XXXX	max	nonpres	Oct	lastSun	2:00	0	S
      +
      +# Zone	NAME			GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
      +## Zone	America/Los_Angeles-PET	-8:00	US		P%sT	XXXX
      +##				-8:00	Twilite		P%sT
      +
      +# For now...
      +Link	America/Los_Angeles	US/Pacific-New	##
      diff --git a/jdk/test/sun/util/calendar/zi/tzdata/solar87 b/jdk/test/sun/util/calendar/zi/tzdata/solar87
      new file mode 100644
      index 00000000000..46b1d56025f
      --- /dev/null
      +++ b/jdk/test/sun/util/calendar/zi/tzdata/solar87
      @@ -0,0 +1,413 @@
      +#
      +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      +#  
      +# This code is free software; you can redistribute it and/or modify it
      +# under the terms of the GNU General Public License version 2 only, as
      +# published by the Free Software Foundation.  Oracle designates this
      +# particular file as subject to the "Classpath" exception as provided
      +# by Oracle in the LICENSE file that accompanied this code.
      +#  
      +# This code is distributed in the hope that it will be useful, but WITHOUT
      +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      +# version 2 for more details (a copy is included in the LICENSE file that
      +# accompanied this code).
      +#  
      +# You should have received a copy of the GNU General Public License version
      +# 2 along with this work; if not, write to the Free Software Foundation,
      +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      +#  
      +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      +# or visit www.oracle.com if you need additional information or have any
      +# questions.
      +#
      +# 
      +# This file is in the public domain, so clarified as of
      +# 2009-05-17 by Arthur David Olson.
      +
      +# So much for footnotes about Saudi Arabia.
      +# Apparent noon times below are for Riyadh; your mileage will vary.
      +# Times were computed using formulas in the U.S. Naval Observatory's
      +# Almanac for Computers 1987; the formulas "will give EqT to an accuracy of
      +# [plus or minus two] seconds during the current year."
      +#
      +# Rounding to the nearest five seconds results in fewer than
      +# 256 different "time types"--a limit that's faced because time types are
      +# stored on disk as unsigned chars.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	sol87	1987	only	-	Jan	1	12:03:20s -0:03:20 -
      +Rule	sol87	1987	only	-	Jan	2	12:03:50s -0:03:50 -
      +Rule	sol87	1987	only	-	Jan	3	12:04:15s -0:04:15 -
      +Rule	sol87	1987	only	-	Jan	4	12:04:45s -0:04:45 -
      +Rule	sol87	1987	only	-	Jan	5	12:05:10s -0:05:10 -
      +Rule	sol87	1987	only	-	Jan	6	12:05:40s -0:05:40 -
      +Rule	sol87	1987	only	-	Jan	7	12:06:05s -0:06:05 -
      +Rule	sol87	1987	only	-	Jan	8	12:06:30s -0:06:30 -
      +Rule	sol87	1987	only	-	Jan	9	12:06:55s -0:06:55 -
      +Rule	sol87	1987	only	-	Jan	10	12:07:20s -0:07:20 -
      +Rule	sol87	1987	only	-	Jan	11	12:07:45s -0:07:45 -
      +Rule	sol87	1987	only	-	Jan	12	12:08:10s -0:08:10 -
      +Rule	sol87	1987	only	-	Jan	13	12:08:30s -0:08:30 -
      +Rule	sol87	1987	only	-	Jan	14	12:08:55s -0:08:55 -
      +Rule	sol87	1987	only	-	Jan	15	12:09:15s -0:09:15 -
      +Rule	sol87	1987	only	-	Jan	16	12:09:35s -0:09:35 -
      +Rule	sol87	1987	only	-	Jan	17	12:09:55s -0:09:55 -
      +Rule	sol87	1987	only	-	Jan	18	12:10:15s -0:10:15 -
      +Rule	sol87	1987	only	-	Jan	19	12:10:35s -0:10:35 -
      +Rule	sol87	1987	only	-	Jan	20	12:10:55s -0:10:55 -
      +Rule	sol87	1987	only	-	Jan	21	12:11:10s -0:11:10 -
      +Rule	sol87	1987	only	-	Jan	22	12:11:30s -0:11:30 -
      +Rule	sol87	1987	only	-	Jan	23	12:11:45s -0:11:45 -
      +Rule	sol87	1987	only	-	Jan	24	12:12:00s -0:12:00 -
      +Rule	sol87	1987	only	-	Jan	25	12:12:15s -0:12:15 -
      +Rule	sol87	1987	only	-	Jan	26	12:12:30s -0:12:30 -
      +Rule	sol87	1987	only	-	Jan	27	12:12:40s -0:12:40 -
      +Rule	sol87	1987	only	-	Jan	28	12:12:55s -0:12:55 -
      +Rule	sol87	1987	only	-	Jan	29	12:13:05s -0:13:05 -
      +Rule	sol87	1987	only	-	Jan	30	12:13:15s -0:13:15 -
      +Rule	sol87	1987	only	-	Jan	31	12:13:25s -0:13:25 -
      +Rule	sol87	1987	only	-	Feb	1	12:13:35s -0:13:35 -
      +Rule	sol87	1987	only	-	Feb	2	12:13:40s -0:13:40 -
      +Rule	sol87	1987	only	-	Feb	3	12:13:50s -0:13:50 -
      +Rule	sol87	1987	only	-	Feb	4	12:13:55s -0:13:55 -
      +Rule	sol87	1987	only	-	Feb	5	12:14:00s -0:14:00 -
      +Rule	sol87	1987	only	-	Feb	6	12:14:05s -0:14:05 -
      +Rule	sol87	1987	only	-	Feb	7	12:14:10s -0:14:10 -
      +Rule	sol87	1987	only	-	Feb	8	12:14:10s -0:14:10 -
      +Rule	sol87	1987	only	-	Feb	9	12:14:15s -0:14:15 -
      +Rule	sol87	1987	only	-	Feb	10	12:14:15s -0:14:15 -
      +Rule	sol87	1987	only	-	Feb	11	12:14:15s -0:14:15 -
      +Rule	sol87	1987	only	-	Feb	12	12:14:15s -0:14:15 -
      +Rule	sol87	1987	only	-	Feb	13	12:14:15s -0:14:15 -
      +Rule	sol87	1987	only	-	Feb	14	12:14:15s -0:14:15 -
      +Rule	sol87	1987	only	-	Feb	15	12:14:10s -0:14:10 -
      +Rule	sol87	1987	only	-	Feb	16	12:14:10s -0:14:10 -
      +Rule	sol87	1987	only	-	Feb	17	12:14:05s -0:14:05 -
      +Rule	sol87	1987	only	-	Feb	18	12:14:00s -0:14:00 -
      +Rule	sol87	1987	only	-	Feb	19	12:13:55s -0:13:55 -
      +Rule	sol87	1987	only	-	Feb	20	12:13:50s -0:13:50 -
      +Rule	sol87	1987	only	-	Feb	21	12:13:45s -0:13:45 -
      +Rule	sol87	1987	only	-	Feb	22	12:13:35s -0:13:35 -
      +Rule	sol87	1987	only	-	Feb	23	12:13:30s -0:13:30 -
      +Rule	sol87	1987	only	-	Feb	24	12:13:20s -0:13:20 -
      +Rule	sol87	1987	only	-	Feb	25	12:13:10s -0:13:10 -
      +Rule	sol87	1987	only	-	Feb	26	12:13:00s -0:13:00 -
      +Rule	sol87	1987	only	-	Feb	27	12:12:50s -0:12:50 -
      +Rule	sol87	1987	only	-	Feb	28	12:12:40s -0:12:40 -
      +Rule	sol87	1987	only	-	Mar	1	12:12:30s -0:12:30 -
      +Rule	sol87	1987	only	-	Mar	2	12:12:20s -0:12:20 -
      +Rule	sol87	1987	only	-	Mar	3	12:12:05s -0:12:05 -
      +Rule	sol87	1987	only	-	Mar	4	12:11:55s -0:11:55 -
      +Rule	sol87	1987	only	-	Mar	5	12:11:40s -0:11:40 -
      +Rule	sol87	1987	only	-	Mar	6	12:11:25s -0:11:25 -
      +Rule	sol87	1987	only	-	Mar	7	12:11:15s -0:11:15 -
      +Rule	sol87	1987	only	-	Mar	8	12:11:00s -0:11:00 -
      +Rule	sol87	1987	only	-	Mar	9	12:10:45s -0:10:45 -
      +Rule	sol87	1987	only	-	Mar	10	12:10:30s -0:10:30 -
      +Rule	sol87	1987	only	-	Mar	11	12:10:15s -0:10:15 -
      +Rule	sol87	1987	only	-	Mar	12	12:09:55s -0:09:55 -
      +Rule	sol87	1987	only	-	Mar	13	12:09:40s -0:09:40 -
      +Rule	sol87	1987	only	-	Mar	14	12:09:25s -0:09:25 -
      +Rule	sol87	1987	only	-	Mar	15	12:09:10s -0:09:10 -
      +Rule	sol87	1987	only	-	Mar	16	12:08:50s -0:08:50 -
      +Rule	sol87	1987	only	-	Mar	17	12:08:35s -0:08:35 -
      +Rule	sol87	1987	only	-	Mar	18	12:08:15s -0:08:15 -
      +Rule	sol87	1987	only	-	Mar	19	12:08:00s -0:08:00 -
      +Rule	sol87	1987	only	-	Mar	20	12:07:40s -0:07:40 -
      +Rule	sol87	1987	only	-	Mar	21	12:07:25s -0:07:25 -
      +Rule	sol87	1987	only	-	Mar	22	12:07:05s -0:07:05 -
      +Rule	sol87	1987	only	-	Mar	23	12:06:50s -0:06:50 -
      +Rule	sol87	1987	only	-	Mar	24	12:06:30s -0:06:30 -
      +Rule	sol87	1987	only	-	Mar	25	12:06:10s -0:06:10 -
      +Rule	sol87	1987	only	-	Mar	26	12:05:55s -0:05:55 -
      +Rule	sol87	1987	only	-	Mar	27	12:05:35s -0:05:35 -
      +Rule	sol87	1987	only	-	Mar	28	12:05:15s -0:05:15 -
      +Rule	sol87	1987	only	-	Mar	29	12:05:00s -0:05:00 -
      +Rule	sol87	1987	only	-	Mar	30	12:04:40s -0:04:40 -
      +Rule	sol87	1987	only	-	Mar	31	12:04:25s -0:04:25 -
      +Rule	sol87	1987	only	-	Apr	1	12:04:05s -0:04:05 -
      +Rule	sol87	1987	only	-	Apr	2	12:03:45s -0:03:45 -
      +Rule	sol87	1987	only	-	Apr	3	12:03:30s -0:03:30 -
      +Rule	sol87	1987	only	-	Apr	4	12:03:10s -0:03:10 -
      +Rule	sol87	1987	only	-	Apr	5	12:02:55s -0:02:55 -
      +Rule	sol87	1987	only	-	Apr	6	12:02:35s -0:02:35 -
      +Rule	sol87	1987	only	-	Apr	7	12:02:20s -0:02:20 -
      +Rule	sol87	1987	only	-	Apr	8	12:02:05s -0:02:05 -
      +Rule	sol87	1987	only	-	Apr	9	12:01:45s -0:01:45 -
      +Rule	sol87	1987	only	-	Apr	10	12:01:30s -0:01:30 -
      +Rule	sol87	1987	only	-	Apr	11	12:01:15s -0:01:15 -
      +Rule	sol87	1987	only	-	Apr	12	12:00:55s -0:00:55 -
      +Rule	sol87	1987	only	-	Apr	13	12:00:40s -0:00:40 -
      +Rule	sol87	1987	only	-	Apr	14	12:00:25s -0:00:25 -
      +Rule	sol87	1987	only	-	Apr	15	12:00:10s -0:00:10 -
      +Rule	sol87	1987	only	-	Apr	16	11:59:55s 0:00:05 -
      +Rule	sol87	1987	only	-	Apr	17	11:59:45s 0:00:15 -
      +Rule	sol87	1987	only	-	Apr	18	11:59:30s 0:00:30 -
      +Rule	sol87	1987	only	-	Apr	19	11:59:15s 0:00:45 -
      +Rule	sol87	1987	only	-	Apr	20	11:59:05s 0:00:55 -
      +Rule	sol87	1987	only	-	Apr	21	11:58:50s 0:01:10 -
      +Rule	sol87	1987	only	-	Apr	22	11:58:40s 0:01:20 -
      +Rule	sol87	1987	only	-	Apr	23	11:58:25s 0:01:35 -
      +Rule	sol87	1987	only	-	Apr	24	11:58:15s 0:01:45 -
      +Rule	sol87	1987	only	-	Apr	25	11:58:05s 0:01:55 -
      +Rule	sol87	1987	only	-	Apr	26	11:57:55s 0:02:05 -
      +Rule	sol87	1987	only	-	Apr	27	11:57:45s 0:02:15 -
      +Rule	sol87	1987	only	-	Apr	28	11:57:35s 0:02:25 -
      +Rule	sol87	1987	only	-	Apr	29	11:57:25s 0:02:35 -
      +Rule	sol87	1987	only	-	Apr	30	11:57:15s 0:02:45 -
      +Rule	sol87	1987	only	-	May	1	11:57:10s 0:02:50 -
      +Rule	sol87	1987	only	-	May	2	11:57:00s 0:03:00 -
      +Rule	sol87	1987	only	-	May	3	11:56:55s 0:03:05 -
      +Rule	sol87	1987	only	-	May	4	11:56:50s 0:03:10 -
      +Rule	sol87	1987	only	-	May	5	11:56:45s 0:03:15 -
      +Rule	sol87	1987	only	-	May	6	11:56:40s 0:03:20 -
      +Rule	sol87	1987	only	-	May	7	11:56:35s 0:03:25 -
      +Rule	sol87	1987	only	-	May	8	11:56:30s 0:03:30 -
      +Rule	sol87	1987	only	-	May	9	11:56:25s 0:03:35 -
      +Rule	sol87	1987	only	-	May	10	11:56:25s 0:03:35 -
      +Rule	sol87	1987	only	-	May	11	11:56:20s 0:03:40 -
      +Rule	sol87	1987	only	-	May	12	11:56:20s 0:03:40 -
      +Rule	sol87	1987	only	-	May	13	11:56:20s 0:03:40 -
      +Rule	sol87	1987	only	-	May	14	11:56:20s 0:03:40 -
      +Rule	sol87	1987	only	-	May	15	11:56:20s 0:03:40 -
      +Rule	sol87	1987	only	-	May	16	11:56:20s 0:03:40 -
      +Rule	sol87	1987	only	-	May	17	11:56:20s 0:03:40 -
      +Rule	sol87	1987	only	-	May	18	11:56:20s 0:03:40 -
      +Rule	sol87	1987	only	-	May	19	11:56:25s 0:03:35 -
      +Rule	sol87	1987	only	-	May	20	11:56:25s 0:03:35 -
      +Rule	sol87	1987	only	-	May	21	11:56:30s 0:03:30 -
      +Rule	sol87	1987	only	-	May	22	11:56:35s 0:03:25 -
      +Rule	sol87	1987	only	-	May	23	11:56:40s 0:03:20 -
      +Rule	sol87	1987	only	-	May	24	11:56:45s 0:03:15 -
      +Rule	sol87	1987	only	-	May	25	11:56:50s 0:03:10 -
      +Rule	sol87	1987	only	-	May	26	11:56:55s 0:03:05 -
      +Rule	sol87	1987	only	-	May	27	11:57:00s 0:03:00 -
      +Rule	sol87	1987	only	-	May	28	11:57:10s 0:02:50 -
      +Rule	sol87	1987	only	-	May	29	11:57:15s 0:02:45 -
      +Rule	sol87	1987	only	-	May	30	11:57:25s 0:02:35 -
      +Rule	sol87	1987	only	-	May	31	11:57:30s 0:02:30 -
      +Rule	sol87	1987	only	-	Jun	1	11:57:40s 0:02:20 -
      +Rule	sol87	1987	only	-	Jun	2	11:57:50s 0:02:10 -
      +Rule	sol87	1987	only	-	Jun	3	11:58:00s 0:02:00 -
      +Rule	sol87	1987	only	-	Jun	4	11:58:10s 0:01:50 -
      +Rule	sol87	1987	only	-	Jun	5	11:58:20s 0:01:40 -
      +Rule	sol87	1987	only	-	Jun	6	11:58:30s 0:01:30 -
      +Rule	sol87	1987	only	-	Jun	7	11:58:40s 0:01:20 -
      +Rule	sol87	1987	only	-	Jun	8	11:58:50s 0:01:10 -
      +Rule	sol87	1987	only	-	Jun	9	11:59:05s 0:00:55 -
      +Rule	sol87	1987	only	-	Jun	10	11:59:15s 0:00:45 -
      +Rule	sol87	1987	only	-	Jun	11	11:59:30s 0:00:30 -
      +Rule	sol87	1987	only	-	Jun	12	11:59:40s 0:00:20 -
      +Rule	sol87	1987	only	-	Jun	13	11:59:50s 0:00:10 -
      +Rule	sol87	1987	only	-	Jun	14	12:00:05s -0:00:05 -
      +Rule	sol87	1987	only	-	Jun	15	12:00:15s -0:00:15 -
      +Rule	sol87	1987	only	-	Jun	16	12:00:30s -0:00:30 -
      +Rule	sol87	1987	only	-	Jun	17	12:00:45s -0:00:45 -
      +Rule	sol87	1987	only	-	Jun	18	12:00:55s -0:00:55 -
      +Rule	sol87	1987	only	-	Jun	19	12:01:10s -0:01:10 -
      +Rule	sol87	1987	only	-	Jun	20	12:01:20s -0:01:20 -
      +Rule	sol87	1987	only	-	Jun	21	12:01:35s -0:01:35 -
      +Rule	sol87	1987	only	-	Jun	22	12:01:50s -0:01:50 -
      +Rule	sol87	1987	only	-	Jun	23	12:02:00s -0:02:00 -
      +Rule	sol87	1987	only	-	Jun	24	12:02:15s -0:02:15 -
      +Rule	sol87	1987	only	-	Jun	25	12:02:25s -0:02:25 -
      +Rule	sol87	1987	only	-	Jun	26	12:02:40s -0:02:40 -
      +Rule	sol87	1987	only	-	Jun	27	12:02:50s -0:02:50 -
      +Rule	sol87	1987	only	-	Jun	28	12:03:05s -0:03:05 -
      +Rule	sol87	1987	only	-	Jun	29	12:03:15s -0:03:15 -
      +Rule	sol87	1987	only	-	Jun	30	12:03:30s -0:03:30 -
      +Rule	sol87	1987	only	-	Jul	1	12:03:40s -0:03:40 -
      +Rule	sol87	1987	only	-	Jul	2	12:03:50s -0:03:50 -
      +Rule	sol87	1987	only	-	Jul	3	12:04:05s -0:04:05 -
      +Rule	sol87	1987	only	-	Jul	4	12:04:15s -0:04:15 -
      +Rule	sol87	1987	only	-	Jul	5	12:04:25s -0:04:25 -
      +Rule	sol87	1987	only	-	Jul	6	12:04:35s -0:04:35 -
      +Rule	sol87	1987	only	-	Jul	7	12:04:45s -0:04:45 -
      +Rule	sol87	1987	only	-	Jul	8	12:04:55s -0:04:55 -
      +Rule	sol87	1987	only	-	Jul	9	12:05:05s -0:05:05 -
      +Rule	sol87	1987	only	-	Jul	10	12:05:15s -0:05:15 -
      +Rule	sol87	1987	only	-	Jul	11	12:05:20s -0:05:20 -
      +Rule	sol87	1987	only	-	Jul	12	12:05:30s -0:05:30 -
      +Rule	sol87	1987	only	-	Jul	13	12:05:40s -0:05:40 -
      +Rule	sol87	1987	only	-	Jul	14	12:05:45s -0:05:45 -
      +Rule	sol87	1987	only	-	Jul	15	12:05:50s -0:05:50 -
      +Rule	sol87	1987	only	-	Jul	16	12:06:00s -0:06:00 -
      +Rule	sol87	1987	only	-	Jul	17	12:06:05s -0:06:05 -
      +Rule	sol87	1987	only	-	Jul	18	12:06:10s -0:06:10 -
      +Rule	sol87	1987	only	-	Jul	19	12:06:15s -0:06:15 -
      +Rule	sol87	1987	only	-	Jul	20	12:06:15s -0:06:15 -
      +Rule	sol87	1987	only	-	Jul	21	12:06:20s -0:06:20 -
      +Rule	sol87	1987	only	-	Jul	22	12:06:25s -0:06:25 -
      +Rule	sol87	1987	only	-	Jul	23	12:06:25s -0:06:25 -
      +Rule	sol87	1987	only	-	Jul	24	12:06:25s -0:06:25 -
      +Rule	sol87	1987	only	-	Jul	25	12:06:30s -0:06:30 -
      +Rule	sol87	1987	only	-	Jul	26	12:06:30s -0:06:30 -
      +Rule	sol87	1987	only	-	Jul	27	12:06:30s -0:06:30 -
      +Rule	sol87	1987	only	-	Jul	28	12:06:30s -0:06:30 -
      +Rule	sol87	1987	only	-	Jul	29	12:06:25s -0:06:25 -
      +Rule	sol87	1987	only	-	Jul	30	12:06:25s -0:06:25 -
      +Rule	sol87	1987	only	-	Jul	31	12:06:25s -0:06:25 -
      +Rule	sol87	1987	only	-	Aug	1	12:06:20s -0:06:20 -
      +Rule	sol87	1987	only	-	Aug	2	12:06:15s -0:06:15 -
      +Rule	sol87	1987	only	-	Aug	3	12:06:10s -0:06:10 -
      +Rule	sol87	1987	only	-	Aug	4	12:06:05s -0:06:05 -
      +Rule	sol87	1987	only	-	Aug	5	12:06:00s -0:06:00 -
      +Rule	sol87	1987	only	-	Aug	6	12:05:55s -0:05:55 -
      +Rule	sol87	1987	only	-	Aug	7	12:05:50s -0:05:50 -
      +Rule	sol87	1987	only	-	Aug	8	12:05:40s -0:05:40 -
      +Rule	sol87	1987	only	-	Aug	9	12:05:35s -0:05:35 -
      +Rule	sol87	1987	only	-	Aug	10	12:05:25s -0:05:25 -
      +Rule	sol87	1987	only	-	Aug	11	12:05:15s -0:05:15 -
      +Rule	sol87	1987	only	-	Aug	12	12:05:05s -0:05:05 -
      +Rule	sol87	1987	only	-	Aug	13	12:04:55s -0:04:55 -
      +Rule	sol87	1987	only	-	Aug	14	12:04:45s -0:04:45 -
      +Rule	sol87	1987	only	-	Aug	15	12:04:35s -0:04:35 -
      +Rule	sol87	1987	only	-	Aug	16	12:04:25s -0:04:25 -
      +Rule	sol87	1987	only	-	Aug	17	12:04:10s -0:04:10 -
      +Rule	sol87	1987	only	-	Aug	18	12:04:00s -0:04:00 -
      +Rule	sol87	1987	only	-	Aug	19	12:03:45s -0:03:45 -
      +Rule	sol87	1987	only	-	Aug	20	12:03:30s -0:03:30 -
      +Rule	sol87	1987	only	-	Aug	21	12:03:15s -0:03:15 -
      +Rule	sol87	1987	only	-	Aug	22	12:03:00s -0:03:00 -
      +Rule	sol87	1987	only	-	Aug	23	12:02:45s -0:02:45 -
      +Rule	sol87	1987	only	-	Aug	24	12:02:30s -0:02:30 -
      +Rule	sol87	1987	only	-	Aug	25	12:02:15s -0:02:15 -
      +Rule	sol87	1987	only	-	Aug	26	12:02:00s -0:02:00 -
      +Rule	sol87	1987	only	-	Aug	27	12:01:40s -0:01:40 -
      +Rule	sol87	1987	only	-	Aug	28	12:01:25s -0:01:25 -
      +Rule	sol87	1987	only	-	Aug	29	12:01:05s -0:01:05 -
      +Rule	sol87	1987	only	-	Aug	30	12:00:50s -0:00:50 -
      +Rule	sol87	1987	only	-	Aug	31	12:00:30s -0:00:30 -
      +Rule	sol87	1987	only	-	Sep	1	12:00:10s -0:00:10 -
      +Rule	sol87	1987	only	-	Sep	2	11:59:50s 0:00:10 -
      +Rule	sol87	1987	only	-	Sep	3	11:59:35s 0:00:25 -
      +Rule	sol87	1987	only	-	Sep	4	11:59:15s 0:00:45 -
      +Rule	sol87	1987	only	-	Sep	5	11:58:55s 0:01:05 -
      +Rule	sol87	1987	only	-	Sep	6	11:58:35s 0:01:25 -
      +Rule	sol87	1987	only	-	Sep	7	11:58:15s 0:01:45 -
      +Rule	sol87	1987	only	-	Sep	8	11:57:55s 0:02:05 -
      +Rule	sol87	1987	only	-	Sep	9	11:57:30s 0:02:30 -
      +Rule	sol87	1987	only	-	Sep	10	11:57:10s 0:02:50 -
      +Rule	sol87	1987	only	-	Sep	11	11:56:50s 0:03:10 -
      +Rule	sol87	1987	only	-	Sep	12	11:56:30s 0:03:30 -
      +Rule	sol87	1987	only	-	Sep	13	11:56:10s 0:03:50 -
      +Rule	sol87	1987	only	-	Sep	14	11:55:45s 0:04:15 -
      +Rule	sol87	1987	only	-	Sep	15	11:55:25s 0:04:35 -
      +Rule	sol87	1987	only	-	Sep	16	11:55:05s 0:04:55 -
      +Rule	sol87	1987	only	-	Sep	17	11:54:45s 0:05:15 -
      +Rule	sol87	1987	only	-	Sep	18	11:54:20s 0:05:40 -
      +Rule	sol87	1987	only	-	Sep	19	11:54:00s 0:06:00 -
      +Rule	sol87	1987	only	-	Sep	20	11:53:40s 0:06:20 -
      +Rule	sol87	1987	only	-	Sep	21	11:53:15s 0:06:45 -
      +Rule	sol87	1987	only	-	Sep	22	11:52:55s 0:07:05 -
      +Rule	sol87	1987	only	-	Sep	23	11:52:35s 0:07:25 -
      +Rule	sol87	1987	only	-	Sep	24	11:52:15s 0:07:45 -
      +Rule	sol87	1987	only	-	Sep	25	11:51:55s 0:08:05 -
      +Rule	sol87	1987	only	-	Sep	26	11:51:35s 0:08:25 -
      +Rule	sol87	1987	only	-	Sep	27	11:51:10s 0:08:50 -
      +Rule	sol87	1987	only	-	Sep	28	11:50:50s 0:09:10 -
      +Rule	sol87	1987	only	-	Sep	29	11:50:30s 0:09:30 -
      +Rule	sol87	1987	only	-	Sep	30	11:50:10s 0:09:50 -
      +Rule	sol87	1987	only	-	Oct	1	11:49:50s 0:10:10 -
      +Rule	sol87	1987	only	-	Oct	2	11:49:35s 0:10:25 -
      +Rule	sol87	1987	only	-	Oct	3	11:49:15s 0:10:45 -
      +Rule	sol87	1987	only	-	Oct	4	11:48:55s 0:11:05 -
      +Rule	sol87	1987	only	-	Oct	5	11:48:35s 0:11:25 -
      +Rule	sol87	1987	only	-	Oct	6	11:48:20s 0:11:40 -
      +Rule	sol87	1987	only	-	Oct	7	11:48:00s 0:12:00 -
      +Rule	sol87	1987	only	-	Oct	8	11:47:45s 0:12:15 -
      +Rule	sol87	1987	only	-	Oct	9	11:47:25s 0:12:35 -
      +Rule	sol87	1987	only	-	Oct	10	11:47:10s 0:12:50 -
      +Rule	sol87	1987	only	-	Oct	11	11:46:55s 0:13:05 -
      +Rule	sol87	1987	only	-	Oct	12	11:46:40s 0:13:20 -
      +Rule	sol87	1987	only	-	Oct	13	11:46:25s 0:13:35 -
      +Rule	sol87	1987	only	-	Oct	14	11:46:10s 0:13:50 -
      +Rule	sol87	1987	only	-	Oct	15	11:45:55s 0:14:05 -
      +Rule	sol87	1987	only	-	Oct	16	11:45:45s 0:14:15 -
      +Rule	sol87	1987	only	-	Oct	17	11:45:30s 0:14:30 -
      +Rule	sol87	1987	only	-	Oct	18	11:45:20s 0:14:40 -
      +Rule	sol87	1987	only	-	Oct	19	11:45:05s 0:14:55 -
      +Rule	sol87	1987	only	-	Oct	20	11:44:55s 0:15:05 -
      +Rule	sol87	1987	only	-	Oct	21	11:44:45s 0:15:15 -
      +Rule	sol87	1987	only	-	Oct	22	11:44:35s 0:15:25 -
      +Rule	sol87	1987	only	-	Oct	23	11:44:25s 0:15:35 -
      +Rule	sol87	1987	only	-	Oct	24	11:44:20s 0:15:40 -
      +Rule	sol87	1987	only	-	Oct	25	11:44:10s 0:15:50 -
      +Rule	sol87	1987	only	-	Oct	26	11:44:05s 0:15:55 -
      +Rule	sol87	1987	only	-	Oct	27	11:43:55s 0:16:05 -
      +Rule	sol87	1987	only	-	Oct	28	11:43:50s 0:16:10 -
      +Rule	sol87	1987	only	-	Oct	29	11:43:45s 0:16:15 -
      +Rule	sol87	1987	only	-	Oct	30	11:43:45s 0:16:15 -
      +Rule	sol87	1987	only	-	Oct	31	11:43:40s 0:16:20 -
      +Rule	sol87	1987	only	-	Nov	1	11:43:40s 0:16:20 -
      +Rule	sol87	1987	only	-	Nov	2	11:43:35s 0:16:25 -
      +Rule	sol87	1987	only	-	Nov	3	11:43:35s 0:16:25 -
      +Rule	sol87	1987	only	-	Nov	4	11:43:35s 0:16:25 -
      +Rule	sol87	1987	only	-	Nov	5	11:43:35s 0:16:25 -
      +Rule	sol87	1987	only	-	Nov	6	11:43:40s 0:16:20 -
      +Rule	sol87	1987	only	-	Nov	7	11:43:40s 0:16:20 -
      +Rule	sol87	1987	only	-	Nov	8	11:43:45s 0:16:15 -
      +Rule	sol87	1987	only	-	Nov	9	11:43:50s 0:16:10 -
      +Rule	sol87	1987	only	-	Nov	10	11:43:55s 0:16:05 -
      +Rule	sol87	1987	only	-	Nov	11	11:44:00s 0:16:00 -
      +Rule	sol87	1987	only	-	Nov	12	11:44:05s 0:15:55 -
      +Rule	sol87	1987	only	-	Nov	13	11:44:15s 0:15:45 -
      +Rule	sol87	1987	only	-	Nov	14	11:44:20s 0:15:40 -
      +Rule	sol87	1987	only	-	Nov	15	11:44:30s 0:15:30 -
      +Rule	sol87	1987	only	-	Nov	16	11:44:40s 0:15:20 -
      +Rule	sol87	1987	only	-	Nov	17	11:44:50s 0:15:10 -
      +Rule	sol87	1987	only	-	Nov	18	11:45:05s 0:14:55 -
      +Rule	sol87	1987	only	-	Nov	19	11:45:15s 0:14:45 -
      +Rule	sol87	1987	only	-	Nov	20	11:45:30s 0:14:30 -
      +Rule	sol87	1987	only	-	Nov	21	11:45:45s 0:14:15 -
      +Rule	sol87	1987	only	-	Nov	22	11:46:00s 0:14:00 -
      +Rule	sol87	1987	only	-	Nov	23	11:46:15s 0:13:45 -
      +Rule	sol87	1987	only	-	Nov	24	11:46:30s 0:13:30 -
      +Rule	sol87	1987	only	-	Nov	25	11:46:50s 0:13:10 -
      +Rule	sol87	1987	only	-	Nov	26	11:47:10s 0:12:50 -
      +Rule	sol87	1987	only	-	Nov	27	11:47:25s 0:12:35 -
      +Rule	sol87	1987	only	-	Nov	28	11:47:45s 0:12:15 -
      +Rule	sol87	1987	only	-	Nov	29	11:48:05s 0:11:55 -
      +Rule	sol87	1987	only	-	Nov	30	11:48:30s 0:11:30 -
      +Rule	sol87	1987	only	-	Dec	1	11:48:50s 0:11:10 -
      +Rule	sol87	1987	only	-	Dec	2	11:49:10s 0:10:50 -
      +Rule	sol87	1987	only	-	Dec	3	11:49:35s 0:10:25 -
      +Rule	sol87	1987	only	-	Dec	4	11:50:00s 0:10:00 -
      +Rule	sol87	1987	only	-	Dec	5	11:50:25s 0:09:35 -
      +Rule	sol87	1987	only	-	Dec	6	11:50:50s 0:09:10 -
      +Rule	sol87	1987	only	-	Dec	7	11:51:15s 0:08:45 -
      +Rule	sol87	1987	only	-	Dec	8	11:51:40s 0:08:20 -
      +Rule	sol87	1987	only	-	Dec	9	11:52:05s 0:07:55 -
      +Rule	sol87	1987	only	-	Dec	10	11:52:30s 0:07:30 -
      +Rule	sol87	1987	only	-	Dec	11	11:53:00s 0:07:00 -
      +Rule	sol87	1987	only	-	Dec	12	11:53:25s 0:06:35 -
      +Rule	sol87	1987	only	-	Dec	13	11:53:55s 0:06:05 -
      +Rule	sol87	1987	only	-	Dec	14	11:54:25s 0:05:35 -
      +Rule	sol87	1987	only	-	Dec	15	11:54:50s 0:05:10 -
      +Rule	sol87	1987	only	-	Dec	16	11:55:20s 0:04:40 -
      +Rule	sol87	1987	only	-	Dec	17	11:55:50s 0:04:10 -
      +Rule	sol87	1987	only	-	Dec	18	11:56:20s 0:03:40 -
      +Rule	sol87	1987	only	-	Dec	19	11:56:50s 0:03:10 -
      +Rule	sol87	1987	only	-	Dec	20	11:57:20s 0:02:40 -
      +Rule	sol87	1987	only	-	Dec	21	11:57:50s 0:02:10 -
      +Rule	sol87	1987	only	-	Dec	22	11:58:20s 0:01:40 -
      +Rule	sol87	1987	only	-	Dec	23	11:58:50s 0:01:10 -
      +Rule	sol87	1987	only	-	Dec	24	11:59:20s 0:00:40 -
      +Rule	sol87	1987	only	-	Dec	25	11:59:50s 0:00:10 -
      +Rule	sol87	1987	only	-	Dec	26	12:00:20s -0:00:20 -
      +Rule	sol87	1987	only	-	Dec	27	12:00:45s -0:00:45 -
      +Rule	sol87	1987	only	-	Dec	28	12:01:15s -0:01:15 -
      +Rule	sol87	1987	only	-	Dec	29	12:01:45s -0:01:45 -
      +Rule	sol87	1987	only	-	Dec	30	12:02:15s -0:02:15 -
      +Rule	sol87	1987	only	-	Dec	31	12:02:45s -0:02:45 -
      +
      +# Riyadh is at about 46 degrees 46 minutes East:  3 hrs, 7 mins, 4 secs
      +# Before and after 1987, we'll operate on local mean solar time.
      +
      +# Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
      +Zone	Asia/Riyadh87	3:07:04	-		zzz	1987
      +			3:07:04	sol87		zzz	1988
      +			3:07:04	-		zzz
      +# For backward compatibility...
      +Link	Asia/Riyadh87	Mideast/Riyadh87
      diff --git a/jdk/test/sun/util/calendar/zi/tzdata/solar88 b/jdk/test/sun/util/calendar/zi/tzdata/solar88
      new file mode 100644
      index 00000000000..71b60d5d74a
      --- /dev/null
      +++ b/jdk/test/sun/util/calendar/zi/tzdata/solar88
      @@ -0,0 +1,413 @@
      +#
      +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      +#  
      +# This code is free software; you can redistribute it and/or modify it
      +# under the terms of the GNU General Public License version 2 only, as
      +# published by the Free Software Foundation.  Oracle designates this
      +# particular file as subject to the "Classpath" exception as provided
      +# by Oracle in the LICENSE file that accompanied this code.
      +#  
      +# This code is distributed in the hope that it will be useful, but WITHOUT
      +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      +# version 2 for more details (a copy is included in the LICENSE file that
      +# accompanied this code).
      +#  
      +# You should have received a copy of the GNU General Public License version
      +# 2 along with this work; if not, write to the Free Software Foundation,
      +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      +#  
      +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      +# or visit www.oracle.com if you need additional information or have any
      +# questions.
      +#
      +# 
      +# This file is in the public domain, so clarified as of
      +# 2009-05-17 by Arthur David Olson.
      +
      +# Apparent noon times below are for Riyadh; they're a bit off for other places.
      +# Times were computed using formulas in the U.S. Naval Observatory's
      +# Almanac for Computers 1988; the formulas "will give EqT to an accuracy of
      +# [plus or minus two] seconds during the current year."
      +#
      +# Rounding to the nearest five seconds results in fewer than
      +# 256 different "time types"--a limit that's faced because time types are
      +# stored on disk as unsigned chars.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	sol88	1988	only	-	Jan	1	12:03:15s -0:03:15 -
      +Rule	sol88	1988	only	-	Jan	2	12:03:40s -0:03:40 -
      +Rule	sol88	1988	only	-	Jan	3	12:04:10s -0:04:10 -
      +Rule	sol88	1988	only	-	Jan	4	12:04:40s -0:04:40 -
      +Rule	sol88	1988	only	-	Jan	5	12:05:05s -0:05:05 -
      +Rule	sol88	1988	only	-	Jan	6	12:05:30s -0:05:30 -
      +Rule	sol88	1988	only	-	Jan	7	12:06:00s -0:06:00 -
      +Rule	sol88	1988	only	-	Jan	8	12:06:25s -0:06:25 -
      +Rule	sol88	1988	only	-	Jan	9	12:06:50s -0:06:50 -
      +Rule	sol88	1988	only	-	Jan	10	12:07:15s -0:07:15 -
      +Rule	sol88	1988	only	-	Jan	11	12:07:40s -0:07:40 -
      +Rule	sol88	1988	only	-	Jan	12	12:08:05s -0:08:05 -
      +Rule	sol88	1988	only	-	Jan	13	12:08:25s -0:08:25 -
      +Rule	sol88	1988	only	-	Jan	14	12:08:50s -0:08:50 -
      +Rule	sol88	1988	only	-	Jan	15	12:09:10s -0:09:10 -
      +Rule	sol88	1988	only	-	Jan	16	12:09:30s -0:09:30 -
      +Rule	sol88	1988	only	-	Jan	17	12:09:50s -0:09:50 -
      +Rule	sol88	1988	only	-	Jan	18	12:10:10s -0:10:10 -
      +Rule	sol88	1988	only	-	Jan	19	12:10:30s -0:10:30 -
      +Rule	sol88	1988	only	-	Jan	20	12:10:50s -0:10:50 -
      +Rule	sol88	1988	only	-	Jan	21	12:11:05s -0:11:05 -
      +Rule	sol88	1988	only	-	Jan	22	12:11:25s -0:11:25 -
      +Rule	sol88	1988	only	-	Jan	23	12:11:40s -0:11:40 -
      +Rule	sol88	1988	only	-	Jan	24	12:11:55s -0:11:55 -
      +Rule	sol88	1988	only	-	Jan	25	12:12:10s -0:12:10 -
      +Rule	sol88	1988	only	-	Jan	26	12:12:25s -0:12:25 -
      +Rule	sol88	1988	only	-	Jan	27	12:12:40s -0:12:40 -
      +Rule	sol88	1988	only	-	Jan	28	12:12:50s -0:12:50 -
      +Rule	sol88	1988	only	-	Jan	29	12:13:00s -0:13:00 -
      +Rule	sol88	1988	only	-	Jan	30	12:13:10s -0:13:10 -
      +Rule	sol88	1988	only	-	Jan	31	12:13:20s -0:13:20 -
      +Rule	sol88	1988	only	-	Feb	1	12:13:30s -0:13:30 -
      +Rule	sol88	1988	only	-	Feb	2	12:13:40s -0:13:40 -
      +Rule	sol88	1988	only	-	Feb	3	12:13:45s -0:13:45 -
      +Rule	sol88	1988	only	-	Feb	4	12:13:55s -0:13:55 -
      +Rule	sol88	1988	only	-	Feb	5	12:14:00s -0:14:00 -
      +Rule	sol88	1988	only	-	Feb	6	12:14:05s -0:14:05 -
      +Rule	sol88	1988	only	-	Feb	7	12:14:10s -0:14:10 -
      +Rule	sol88	1988	only	-	Feb	8	12:14:10s -0:14:10 -
      +Rule	sol88	1988	only	-	Feb	9	12:14:15s -0:14:15 -
      +Rule	sol88	1988	only	-	Feb	10	12:14:15s -0:14:15 -
      +Rule	sol88	1988	only	-	Feb	11	12:14:15s -0:14:15 -
      +Rule	sol88	1988	only	-	Feb	12	12:14:15s -0:14:15 -
      +Rule	sol88	1988	only	-	Feb	13	12:14:15s -0:14:15 -
      +Rule	sol88	1988	only	-	Feb	14	12:14:15s -0:14:15 -
      +Rule	sol88	1988	only	-	Feb	15	12:14:10s -0:14:10 -
      +Rule	sol88	1988	only	-	Feb	16	12:14:10s -0:14:10 -
      +Rule	sol88	1988	only	-	Feb	17	12:14:05s -0:14:05 -
      +Rule	sol88	1988	only	-	Feb	18	12:14:00s -0:14:00 -
      +Rule	sol88	1988	only	-	Feb	19	12:13:55s -0:13:55 -
      +Rule	sol88	1988	only	-	Feb	20	12:13:50s -0:13:50 -
      +Rule	sol88	1988	only	-	Feb	21	12:13:45s -0:13:45 -
      +Rule	sol88	1988	only	-	Feb	22	12:13:40s -0:13:40 -
      +Rule	sol88	1988	only	-	Feb	23	12:13:30s -0:13:30 -
      +Rule	sol88	1988	only	-	Feb	24	12:13:20s -0:13:20 -
      +Rule	sol88	1988	only	-	Feb	25	12:13:15s -0:13:15 -
      +Rule	sol88	1988	only	-	Feb	26	12:13:05s -0:13:05 -
      +Rule	sol88	1988	only	-	Feb	27	12:12:55s -0:12:55 -
      +Rule	sol88	1988	only	-	Feb	28	12:12:45s -0:12:45 -
      +Rule	sol88	1988	only	-	Feb	29	12:12:30s -0:12:30 -
      +Rule	sol88	1988	only	-	Mar	1	12:12:20s -0:12:20 -
      +Rule	sol88	1988	only	-	Mar	2	12:12:10s -0:12:10 -
      +Rule	sol88	1988	only	-	Mar	3	12:11:55s -0:11:55 -
      +Rule	sol88	1988	only	-	Mar	4	12:11:45s -0:11:45 -
      +Rule	sol88	1988	only	-	Mar	5	12:11:30s -0:11:30 -
      +Rule	sol88	1988	only	-	Mar	6	12:11:15s -0:11:15 -
      +Rule	sol88	1988	only	-	Mar	7	12:11:00s -0:11:00 -
      +Rule	sol88	1988	only	-	Mar	8	12:10:45s -0:10:45 -
      +Rule	sol88	1988	only	-	Mar	9	12:10:30s -0:10:30 -
      +Rule	sol88	1988	only	-	Mar	10	12:10:15s -0:10:15 -
      +Rule	sol88	1988	only	-	Mar	11	12:10:00s -0:10:00 -
      +Rule	sol88	1988	only	-	Mar	12	12:09:45s -0:09:45 -
      +Rule	sol88	1988	only	-	Mar	13	12:09:30s -0:09:30 -
      +Rule	sol88	1988	only	-	Mar	14	12:09:10s -0:09:10 -
      +Rule	sol88	1988	only	-	Mar	15	12:08:55s -0:08:55 -
      +Rule	sol88	1988	only	-	Mar	16	12:08:40s -0:08:40 -
      +Rule	sol88	1988	only	-	Mar	17	12:08:20s -0:08:20 -
      +Rule	sol88	1988	only	-	Mar	18	12:08:05s -0:08:05 -
      +Rule	sol88	1988	only	-	Mar	19	12:07:45s -0:07:45 -
      +Rule	sol88	1988	only	-	Mar	20	12:07:30s -0:07:30 -
      +Rule	sol88	1988	only	-	Mar	21	12:07:10s -0:07:10 -
      +Rule	sol88	1988	only	-	Mar	22	12:06:50s -0:06:50 -
      +Rule	sol88	1988	only	-	Mar	23	12:06:35s -0:06:35 -
      +Rule	sol88	1988	only	-	Mar	24	12:06:15s -0:06:15 -
      +Rule	sol88	1988	only	-	Mar	25	12:06:00s -0:06:00 -
      +Rule	sol88	1988	only	-	Mar	26	12:05:40s -0:05:40 -
      +Rule	sol88	1988	only	-	Mar	27	12:05:20s -0:05:20 -
      +Rule	sol88	1988	only	-	Mar	28	12:05:05s -0:05:05 -
      +Rule	sol88	1988	only	-	Mar	29	12:04:45s -0:04:45 -
      +Rule	sol88	1988	only	-	Mar	30	12:04:25s -0:04:25 -
      +Rule	sol88	1988	only	-	Mar	31	12:04:10s -0:04:10 -
      +Rule	sol88	1988	only	-	Apr	1	12:03:50s -0:03:50 -
      +Rule	sol88	1988	only	-	Apr	2	12:03:35s -0:03:35 -
      +Rule	sol88	1988	only	-	Apr	3	12:03:15s -0:03:15 -
      +Rule	sol88	1988	only	-	Apr	4	12:03:00s -0:03:00 -
      +Rule	sol88	1988	only	-	Apr	5	12:02:40s -0:02:40 -
      +Rule	sol88	1988	only	-	Apr	6	12:02:25s -0:02:25 -
      +Rule	sol88	1988	only	-	Apr	7	12:02:05s -0:02:05 -
      +Rule	sol88	1988	only	-	Apr	8	12:01:50s -0:01:50 -
      +Rule	sol88	1988	only	-	Apr	9	12:01:35s -0:01:35 -
      +Rule	sol88	1988	only	-	Apr	10	12:01:15s -0:01:15 -
      +Rule	sol88	1988	only	-	Apr	11	12:01:00s -0:01:00 -
      +Rule	sol88	1988	only	-	Apr	12	12:00:45s -0:00:45 -
      +Rule	sol88	1988	only	-	Apr	13	12:00:30s -0:00:30 -
      +Rule	sol88	1988	only	-	Apr	14	12:00:15s -0:00:15 -
      +Rule	sol88	1988	only	-	Apr	15	12:00:00s 0:00:00 -
      +Rule	sol88	1988	only	-	Apr	16	11:59:45s 0:00:15 -
      +Rule	sol88	1988	only	-	Apr	17	11:59:30s 0:00:30 -
      +Rule	sol88	1988	only	-	Apr	18	11:59:20s 0:00:40 -
      +Rule	sol88	1988	only	-	Apr	19	11:59:05s 0:00:55 -
      +Rule	sol88	1988	only	-	Apr	20	11:58:55s 0:01:05 -
      +Rule	sol88	1988	only	-	Apr	21	11:58:40s 0:01:20 -
      +Rule	sol88	1988	only	-	Apr	22	11:58:30s 0:01:30 -
      +Rule	sol88	1988	only	-	Apr	23	11:58:15s 0:01:45 -
      +Rule	sol88	1988	only	-	Apr	24	11:58:05s 0:01:55 -
      +Rule	sol88	1988	only	-	Apr	25	11:57:55s 0:02:05 -
      +Rule	sol88	1988	only	-	Apr	26	11:57:45s 0:02:15 -
      +Rule	sol88	1988	only	-	Apr	27	11:57:35s 0:02:25 -
      +Rule	sol88	1988	only	-	Apr	28	11:57:30s 0:02:30 -
      +Rule	sol88	1988	only	-	Apr	29	11:57:20s 0:02:40 -
      +Rule	sol88	1988	only	-	Apr	30	11:57:10s 0:02:50 -
      +Rule	sol88	1988	only	-	May	1	11:57:05s 0:02:55 -
      +Rule	sol88	1988	only	-	May	2	11:56:55s 0:03:05 -
      +Rule	sol88	1988	only	-	May	3	11:56:50s 0:03:10 -
      +Rule	sol88	1988	only	-	May	4	11:56:45s 0:03:15 -
      +Rule	sol88	1988	only	-	May	5	11:56:40s 0:03:20 -
      +Rule	sol88	1988	only	-	May	6	11:56:35s 0:03:25 -
      +Rule	sol88	1988	only	-	May	7	11:56:30s 0:03:30 -
      +Rule	sol88	1988	only	-	May	8	11:56:25s 0:03:35 -
      +Rule	sol88	1988	only	-	May	9	11:56:25s 0:03:35 -
      +Rule	sol88	1988	only	-	May	10	11:56:20s 0:03:40 -
      +Rule	sol88	1988	only	-	May	11	11:56:20s 0:03:40 -
      +Rule	sol88	1988	only	-	May	12	11:56:20s 0:03:40 -
      +Rule	sol88	1988	only	-	May	13	11:56:20s 0:03:40 -
      +Rule	sol88	1988	only	-	May	14	11:56:20s 0:03:40 -
      +Rule	sol88	1988	only	-	May	15	11:56:20s 0:03:40 -
      +Rule	sol88	1988	only	-	May	16	11:56:20s 0:03:40 -
      +Rule	sol88	1988	only	-	May	17	11:56:20s 0:03:40 -
      +Rule	sol88	1988	only	-	May	18	11:56:25s 0:03:35 -
      +Rule	sol88	1988	only	-	May	19	11:56:25s 0:03:35 -
      +Rule	sol88	1988	only	-	May	20	11:56:30s 0:03:30 -
      +Rule	sol88	1988	only	-	May	21	11:56:35s 0:03:25 -
      +Rule	sol88	1988	only	-	May	22	11:56:40s 0:03:20 -
      +Rule	sol88	1988	only	-	May	23	11:56:45s 0:03:15 -
      +Rule	sol88	1988	only	-	May	24	11:56:50s 0:03:10 -
      +Rule	sol88	1988	only	-	May	25	11:56:55s 0:03:05 -
      +Rule	sol88	1988	only	-	May	26	11:57:00s 0:03:00 -
      +Rule	sol88	1988	only	-	May	27	11:57:05s 0:02:55 -
      +Rule	sol88	1988	only	-	May	28	11:57:15s 0:02:45 -
      +Rule	sol88	1988	only	-	May	29	11:57:20s 0:02:40 -
      +Rule	sol88	1988	only	-	May	30	11:57:30s 0:02:30 -
      +Rule	sol88	1988	only	-	May	31	11:57:40s 0:02:20 -
      +Rule	sol88	1988	only	-	Jun	1	11:57:50s 0:02:10 -
      +Rule	sol88	1988	only	-	Jun	2	11:57:55s 0:02:05 -
      +Rule	sol88	1988	only	-	Jun	3	11:58:05s 0:01:55 -
      +Rule	sol88	1988	only	-	Jun	4	11:58:15s 0:01:45 -
      +Rule	sol88	1988	only	-	Jun	5	11:58:30s 0:01:30 -
      +Rule	sol88	1988	only	-	Jun	6	11:58:40s 0:01:20 -
      +Rule	sol88	1988	only	-	Jun	7	11:58:50s 0:01:10 -
      +Rule	sol88	1988	only	-	Jun	8	11:59:00s 0:01:00 -
      +Rule	sol88	1988	only	-	Jun	9	11:59:15s 0:00:45 -
      +Rule	sol88	1988	only	-	Jun	10	11:59:25s 0:00:35 -
      +Rule	sol88	1988	only	-	Jun	11	11:59:35s 0:00:25 -
      +Rule	sol88	1988	only	-	Jun	12	11:59:50s 0:00:10 -
      +Rule	sol88	1988	only	-	Jun	13	12:00:00s 0:00:00 -
      +Rule	sol88	1988	only	-	Jun	14	12:00:15s -0:00:15 -
      +Rule	sol88	1988	only	-	Jun	15	12:00:25s -0:00:25 -
      +Rule	sol88	1988	only	-	Jun	16	12:00:40s -0:00:40 -
      +Rule	sol88	1988	only	-	Jun	17	12:00:55s -0:00:55 -
      +Rule	sol88	1988	only	-	Jun	18	12:01:05s -0:01:05 -
      +Rule	sol88	1988	only	-	Jun	19	12:01:20s -0:01:20 -
      +Rule	sol88	1988	only	-	Jun	20	12:01:30s -0:01:30 -
      +Rule	sol88	1988	only	-	Jun	21	12:01:45s -0:01:45 -
      +Rule	sol88	1988	only	-	Jun	22	12:02:00s -0:02:00 -
      +Rule	sol88	1988	only	-	Jun	23	12:02:10s -0:02:10 -
      +Rule	sol88	1988	only	-	Jun	24	12:02:25s -0:02:25 -
      +Rule	sol88	1988	only	-	Jun	25	12:02:35s -0:02:35 -
      +Rule	sol88	1988	only	-	Jun	26	12:02:50s -0:02:50 -
      +Rule	sol88	1988	only	-	Jun	27	12:03:00s -0:03:00 -
      +Rule	sol88	1988	only	-	Jun	28	12:03:15s -0:03:15 -
      +Rule	sol88	1988	only	-	Jun	29	12:03:25s -0:03:25 -
      +Rule	sol88	1988	only	-	Jun	30	12:03:40s -0:03:40 -
      +Rule	sol88	1988	only	-	Jul	1	12:03:50s -0:03:50 -
      +Rule	sol88	1988	only	-	Jul	2	12:04:00s -0:04:00 -
      +Rule	sol88	1988	only	-	Jul	3	12:04:10s -0:04:10 -
      +Rule	sol88	1988	only	-	Jul	4	12:04:25s -0:04:25 -
      +Rule	sol88	1988	only	-	Jul	5	12:04:35s -0:04:35 -
      +Rule	sol88	1988	only	-	Jul	6	12:04:45s -0:04:45 -
      +Rule	sol88	1988	only	-	Jul	7	12:04:55s -0:04:55 -
      +Rule	sol88	1988	only	-	Jul	8	12:05:05s -0:05:05 -
      +Rule	sol88	1988	only	-	Jul	9	12:05:10s -0:05:10 -
      +Rule	sol88	1988	only	-	Jul	10	12:05:20s -0:05:20 -
      +Rule	sol88	1988	only	-	Jul	11	12:05:30s -0:05:30 -
      +Rule	sol88	1988	only	-	Jul	12	12:05:35s -0:05:35 -
      +Rule	sol88	1988	only	-	Jul	13	12:05:45s -0:05:45 -
      +Rule	sol88	1988	only	-	Jul	14	12:05:50s -0:05:50 -
      +Rule	sol88	1988	only	-	Jul	15	12:05:55s -0:05:55 -
      +Rule	sol88	1988	only	-	Jul	16	12:06:00s -0:06:00 -
      +Rule	sol88	1988	only	-	Jul	17	12:06:05s -0:06:05 -
      +Rule	sol88	1988	only	-	Jul	18	12:06:10s -0:06:10 -
      +Rule	sol88	1988	only	-	Jul	19	12:06:15s -0:06:15 -
      +Rule	sol88	1988	only	-	Jul	20	12:06:20s -0:06:20 -
      +Rule	sol88	1988	only	-	Jul	21	12:06:25s -0:06:25 -
      +Rule	sol88	1988	only	-	Jul	22	12:06:25s -0:06:25 -
      +Rule	sol88	1988	only	-	Jul	23	12:06:25s -0:06:25 -
      +Rule	sol88	1988	only	-	Jul	24	12:06:30s -0:06:30 -
      +Rule	sol88	1988	only	-	Jul	25	12:06:30s -0:06:30 -
      +Rule	sol88	1988	only	-	Jul	26	12:06:30s -0:06:30 -
      +Rule	sol88	1988	only	-	Jul	27	12:06:30s -0:06:30 -
      +Rule	sol88	1988	only	-	Jul	28	12:06:30s -0:06:30 -
      +Rule	sol88	1988	only	-	Jul	29	12:06:25s -0:06:25 -
      +Rule	sol88	1988	only	-	Jul	30	12:06:25s -0:06:25 -
      +Rule	sol88	1988	only	-	Jul	31	12:06:20s -0:06:20 -
      +Rule	sol88	1988	only	-	Aug	1	12:06:15s -0:06:15 -
      +Rule	sol88	1988	only	-	Aug	2	12:06:15s -0:06:15 -
      +Rule	sol88	1988	only	-	Aug	3	12:06:10s -0:06:10 -
      +Rule	sol88	1988	only	-	Aug	4	12:06:05s -0:06:05 -
      +Rule	sol88	1988	only	-	Aug	5	12:05:55s -0:05:55 -
      +Rule	sol88	1988	only	-	Aug	6	12:05:50s -0:05:50 -
      +Rule	sol88	1988	only	-	Aug	7	12:05:45s -0:05:45 -
      +Rule	sol88	1988	only	-	Aug	8	12:05:35s -0:05:35 -
      +Rule	sol88	1988	only	-	Aug	9	12:05:25s -0:05:25 -
      +Rule	sol88	1988	only	-	Aug	10	12:05:20s -0:05:20 -
      +Rule	sol88	1988	only	-	Aug	11	12:05:10s -0:05:10 -
      +Rule	sol88	1988	only	-	Aug	12	12:05:00s -0:05:00 -
      +Rule	sol88	1988	only	-	Aug	13	12:04:50s -0:04:50 -
      +Rule	sol88	1988	only	-	Aug	14	12:04:35s -0:04:35 -
      +Rule	sol88	1988	only	-	Aug	15	12:04:25s -0:04:25 -
      +Rule	sol88	1988	only	-	Aug	16	12:04:15s -0:04:15 -
      +Rule	sol88	1988	only	-	Aug	17	12:04:00s -0:04:00 -
      +Rule	sol88	1988	only	-	Aug	18	12:03:50s -0:03:50 -
      +Rule	sol88	1988	only	-	Aug	19	12:03:35s -0:03:35 -
      +Rule	sol88	1988	only	-	Aug	20	12:03:20s -0:03:20 -
      +Rule	sol88	1988	only	-	Aug	21	12:03:05s -0:03:05 -
      +Rule	sol88	1988	only	-	Aug	22	12:02:50s -0:02:50 -
      +Rule	sol88	1988	only	-	Aug	23	12:02:35s -0:02:35 -
      +Rule	sol88	1988	only	-	Aug	24	12:02:20s -0:02:20 -
      +Rule	sol88	1988	only	-	Aug	25	12:02:00s -0:02:00 -
      +Rule	sol88	1988	only	-	Aug	26	12:01:45s -0:01:45 -
      +Rule	sol88	1988	only	-	Aug	27	12:01:30s -0:01:30 -
      +Rule	sol88	1988	only	-	Aug	28	12:01:10s -0:01:10 -
      +Rule	sol88	1988	only	-	Aug	29	12:00:50s -0:00:50 -
      +Rule	sol88	1988	only	-	Aug	30	12:00:35s -0:00:35 -
      +Rule	sol88	1988	only	-	Aug	31	12:00:15s -0:00:15 -
      +Rule	sol88	1988	only	-	Sep	1	11:59:55s 0:00:05 -
      +Rule	sol88	1988	only	-	Sep	2	11:59:35s 0:00:25 -
      +Rule	sol88	1988	only	-	Sep	3	11:59:20s 0:00:40 -
      +Rule	sol88	1988	only	-	Sep	4	11:59:00s 0:01:00 -
      +Rule	sol88	1988	only	-	Sep	5	11:58:40s 0:01:20 -
      +Rule	sol88	1988	only	-	Sep	6	11:58:20s 0:01:40 -
      +Rule	sol88	1988	only	-	Sep	7	11:58:00s 0:02:00 -
      +Rule	sol88	1988	only	-	Sep	8	11:57:35s 0:02:25 -
      +Rule	sol88	1988	only	-	Sep	9	11:57:15s 0:02:45 -
      +Rule	sol88	1988	only	-	Sep	10	11:56:55s 0:03:05 -
      +Rule	sol88	1988	only	-	Sep	11	11:56:35s 0:03:25 -
      +Rule	sol88	1988	only	-	Sep	12	11:56:15s 0:03:45 -
      +Rule	sol88	1988	only	-	Sep	13	11:55:50s 0:04:10 -
      +Rule	sol88	1988	only	-	Sep	14	11:55:30s 0:04:30 -
      +Rule	sol88	1988	only	-	Sep	15	11:55:10s 0:04:50 -
      +Rule	sol88	1988	only	-	Sep	16	11:54:50s 0:05:10 -
      +Rule	sol88	1988	only	-	Sep	17	11:54:25s 0:05:35 -
      +Rule	sol88	1988	only	-	Sep	18	11:54:05s 0:05:55 -
      +Rule	sol88	1988	only	-	Sep	19	11:53:45s 0:06:15 -
      +Rule	sol88	1988	only	-	Sep	20	11:53:25s 0:06:35 -
      +Rule	sol88	1988	only	-	Sep	21	11:53:00s 0:07:00 -
      +Rule	sol88	1988	only	-	Sep	22	11:52:40s 0:07:20 -
      +Rule	sol88	1988	only	-	Sep	23	11:52:20s 0:07:40 -
      +Rule	sol88	1988	only	-	Sep	24	11:52:00s 0:08:00 -
      +Rule	sol88	1988	only	-	Sep	25	11:51:40s 0:08:20 -
      +Rule	sol88	1988	only	-	Sep	26	11:51:15s 0:08:45 -
      +Rule	sol88	1988	only	-	Sep	27	11:50:55s 0:09:05 -
      +Rule	sol88	1988	only	-	Sep	28	11:50:35s 0:09:25 -
      +Rule	sol88	1988	only	-	Sep	29	11:50:15s 0:09:45 -
      +Rule	sol88	1988	only	-	Sep	30	11:49:55s 0:10:05 -
      +Rule	sol88	1988	only	-	Oct	1	11:49:35s 0:10:25 -
      +Rule	sol88	1988	only	-	Oct	2	11:49:20s 0:10:40 -
      +Rule	sol88	1988	only	-	Oct	3	11:49:00s 0:11:00 -
      +Rule	sol88	1988	only	-	Oct	4	11:48:40s 0:11:20 -
      +Rule	sol88	1988	only	-	Oct	5	11:48:25s 0:11:35 -
      +Rule	sol88	1988	only	-	Oct	6	11:48:05s 0:11:55 -
      +Rule	sol88	1988	only	-	Oct	7	11:47:50s 0:12:10 -
      +Rule	sol88	1988	only	-	Oct	8	11:47:30s 0:12:30 -
      +Rule	sol88	1988	only	-	Oct	9	11:47:15s 0:12:45 -
      +Rule	sol88	1988	only	-	Oct	10	11:47:00s 0:13:00 -
      +Rule	sol88	1988	only	-	Oct	11	11:46:45s 0:13:15 -
      +Rule	sol88	1988	only	-	Oct	12	11:46:30s 0:13:30 -
      +Rule	sol88	1988	only	-	Oct	13	11:46:15s 0:13:45 -
      +Rule	sol88	1988	only	-	Oct	14	11:46:00s 0:14:00 -
      +Rule	sol88	1988	only	-	Oct	15	11:45:45s 0:14:15 -
      +Rule	sol88	1988	only	-	Oct	16	11:45:35s 0:14:25 -
      +Rule	sol88	1988	only	-	Oct	17	11:45:20s 0:14:40 -
      +Rule	sol88	1988	only	-	Oct	18	11:45:10s 0:14:50 -
      +Rule	sol88	1988	only	-	Oct	19	11:45:00s 0:15:00 -
      +Rule	sol88	1988	only	-	Oct	20	11:44:45s 0:15:15 -
      +Rule	sol88	1988	only	-	Oct	21	11:44:40s 0:15:20 -
      +Rule	sol88	1988	only	-	Oct	22	11:44:30s 0:15:30 -
      +Rule	sol88	1988	only	-	Oct	23	11:44:20s 0:15:40 -
      +Rule	sol88	1988	only	-	Oct	24	11:44:10s 0:15:50 -
      +Rule	sol88	1988	only	-	Oct	25	11:44:05s 0:15:55 -
      +Rule	sol88	1988	only	-	Oct	26	11:44:00s 0:16:00 -
      +Rule	sol88	1988	only	-	Oct	27	11:43:55s 0:16:05 -
      +Rule	sol88	1988	only	-	Oct	28	11:43:50s 0:16:10 -
      +Rule	sol88	1988	only	-	Oct	29	11:43:45s 0:16:15 -
      +Rule	sol88	1988	only	-	Oct	30	11:43:40s 0:16:20 -
      +Rule	sol88	1988	only	-	Oct	31	11:43:40s 0:16:20 -
      +Rule	sol88	1988	only	-	Nov	1	11:43:35s 0:16:25 -
      +Rule	sol88	1988	only	-	Nov	2	11:43:35s 0:16:25 -
      +Rule	sol88	1988	only	-	Nov	3	11:43:35s 0:16:25 -
      +Rule	sol88	1988	only	-	Nov	4	11:43:35s 0:16:25 -
      +Rule	sol88	1988	only	-	Nov	5	11:43:40s 0:16:20 -
      +Rule	sol88	1988	only	-	Nov	6	11:43:40s 0:16:20 -
      +Rule	sol88	1988	only	-	Nov	7	11:43:45s 0:16:15 -
      +Rule	sol88	1988	only	-	Nov	8	11:43:45s 0:16:15 -
      +Rule	sol88	1988	only	-	Nov	9	11:43:50s 0:16:10 -
      +Rule	sol88	1988	only	-	Nov	10	11:44:00s 0:16:00 -
      +Rule	sol88	1988	only	-	Nov	11	11:44:05s 0:15:55 -
      +Rule	sol88	1988	only	-	Nov	12	11:44:10s 0:15:50 -
      +Rule	sol88	1988	only	-	Nov	13	11:44:20s 0:15:40 -
      +Rule	sol88	1988	only	-	Nov	14	11:44:30s 0:15:30 -
      +Rule	sol88	1988	only	-	Nov	15	11:44:40s 0:15:20 -
      +Rule	sol88	1988	only	-	Nov	16	11:44:50s 0:15:10 -
      +Rule	sol88	1988	only	-	Nov	17	11:45:00s 0:15:00 -
      +Rule	sol88	1988	only	-	Nov	18	11:45:15s 0:14:45 -
      +Rule	sol88	1988	only	-	Nov	19	11:45:25s 0:14:35 -
      +Rule	sol88	1988	only	-	Nov	20	11:45:40s 0:14:20 -
      +Rule	sol88	1988	only	-	Nov	21	11:45:55s 0:14:05 -
      +Rule	sol88	1988	only	-	Nov	22	11:46:10s 0:13:50 -
      +Rule	sol88	1988	only	-	Nov	23	11:46:30s 0:13:30 -
      +Rule	sol88	1988	only	-	Nov	24	11:46:45s 0:13:15 -
      +Rule	sol88	1988	only	-	Nov	25	11:47:05s 0:12:55 -
      +Rule	sol88	1988	only	-	Nov	26	11:47:20s 0:12:40 -
      +Rule	sol88	1988	only	-	Nov	27	11:47:40s 0:12:20 -
      +Rule	sol88	1988	only	-	Nov	28	11:48:00s 0:12:00 -
      +Rule	sol88	1988	only	-	Nov	29	11:48:25s 0:11:35 -
      +Rule	sol88	1988	only	-	Nov	30	11:48:45s 0:11:15 -
      +Rule	sol88	1988	only	-	Dec	1	11:49:05s 0:10:55 -
      +Rule	sol88	1988	only	-	Dec	2	11:49:30s 0:10:30 -
      +Rule	sol88	1988	only	-	Dec	3	11:49:55s 0:10:05 -
      +Rule	sol88	1988	only	-	Dec	4	11:50:15s 0:09:45 -
      +Rule	sol88	1988	only	-	Dec	5	11:50:40s 0:09:20 -
      +Rule	sol88	1988	only	-	Dec	6	11:51:05s 0:08:55 -
      +Rule	sol88	1988	only	-	Dec	7	11:51:35s 0:08:25 -
      +Rule	sol88	1988	only	-	Dec	8	11:52:00s 0:08:00 -
      +Rule	sol88	1988	only	-	Dec	9	11:52:25s 0:07:35 -
      +Rule	sol88	1988	only	-	Dec	10	11:52:55s 0:07:05 -
      +Rule	sol88	1988	only	-	Dec	11	11:53:20s 0:06:40 -
      +Rule	sol88	1988	only	-	Dec	12	11:53:50s 0:06:10 -
      +Rule	sol88	1988	only	-	Dec	13	11:54:15s 0:05:45 -
      +Rule	sol88	1988	only	-	Dec	14	11:54:45s 0:05:15 -
      +Rule	sol88	1988	only	-	Dec	15	11:55:15s 0:04:45 -
      +Rule	sol88	1988	only	-	Dec	16	11:55:45s 0:04:15 -
      +Rule	sol88	1988	only	-	Dec	17	11:56:15s 0:03:45 -
      +Rule	sol88	1988	only	-	Dec	18	11:56:40s 0:03:20 -
      +Rule	sol88	1988	only	-	Dec	19	11:57:10s 0:02:50 -
      +Rule	sol88	1988	only	-	Dec	20	11:57:40s 0:02:20 -
      +Rule	sol88	1988	only	-	Dec	21	11:58:10s 0:01:50 -
      +Rule	sol88	1988	only	-	Dec	22	11:58:40s 0:01:20 -
      +Rule	sol88	1988	only	-	Dec	23	11:59:10s 0:00:50 -
      +Rule	sol88	1988	only	-	Dec	24	11:59:40s 0:00:20 -
      +Rule	sol88	1988	only	-	Dec	25	12:00:10s -0:00:10 -
      +Rule	sol88	1988	only	-	Dec	26	12:00:40s -0:00:40 -
      +Rule	sol88	1988	only	-	Dec	27	12:01:10s -0:01:10 -
      +Rule	sol88	1988	only	-	Dec	28	12:01:40s -0:01:40 -
      +Rule	sol88	1988	only	-	Dec	29	12:02:10s -0:02:10 -
      +Rule	sol88	1988	only	-	Dec	30	12:02:35s -0:02:35 -
      +Rule	sol88	1988	only	-	Dec	31	12:03:05s -0:03:05 -
      +
      +# Riyadh is at about 46 degrees 46 minutes East:  3 hrs, 7 mins, 4 secs
      +# Before and after 1988, we'll operate on local mean solar time.
      +
      +# Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
      +Zone	Asia/Riyadh88	3:07:04	-		zzz	1988
      +			3:07:04	sol88		zzz	1989
      +			3:07:04	-		zzz
      +# For backward compatibility...
      +Link	Asia/Riyadh88	Mideast/Riyadh88
      diff --git a/jdk/test/sun/util/calendar/zi/tzdata/solar89 b/jdk/test/sun/util/calendar/zi/tzdata/solar89
      new file mode 100644
      index 00000000000..ae2bea8876a
      --- /dev/null
      +++ b/jdk/test/sun/util/calendar/zi/tzdata/solar89
      @@ -0,0 +1,418 @@
      +#
      +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      +#  
      +# This code is free software; you can redistribute it and/or modify it
      +# under the terms of the GNU General Public License version 2 only, as
      +# published by the Free Software Foundation.  Oracle designates this
      +# particular file as subject to the "Classpath" exception as provided
      +# by Oracle in the LICENSE file that accompanied this code.
      +#  
      +# This code is distributed in the hope that it will be useful, but WITHOUT
      +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      +# version 2 for more details (a copy is included in the LICENSE file that
      +# accompanied this code).
      +#  
      +# You should have received a copy of the GNU General Public License version
      +# 2 along with this work; if not, write to the Free Software Foundation,
      +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      +#  
      +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      +# or visit www.oracle.com if you need additional information or have any
      +# questions.
      +#
      +# 
      +# This file is in the public domain, so clarified as of
      +# 2009-05-17 by Arthur David Olson.
      +
      +# Apparent noon times below are for Riyadh; they're a bit off for other places.
      +# Times were computed using a formula provided by the U. S. Naval Observatory:
      +#	eqt = -105.8 * sin(l) + 596.2 * sin(2 * l) + 4.4 * sin(3 * l)
      +#		-12.7 * sin(4 * l) - 429.0 * cos(l) - 2.1 * cos (2 * l)
      +#		+ 19.3 * cos(3 * l);
      +# where l is the "mean longitude of the Sun" given by
      +#	l = 279.642 degrees + 0.985647 * d
      +# and d is the interval in days from January 0, 0 hours Universal Time
      +# (equaling the day of the year plus the fraction of a day from zero hours).
      +# The accuracy of the formula is plus or minus three seconds.
      +#
      +# Rounding to the nearest five seconds results in fewer than
      +# 256 different "time types"--a limit that's faced because time types are
      +# stored on disk as unsigned chars.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	sol89	1989	only	-	Jan	1	12:03:35s -0:03:35 -
      +Rule	sol89	1989	only	-	Jan	2	12:04:05s -0:04:05 -
      +Rule	sol89	1989	only	-	Jan	3	12:04:30s -0:04:30 -
      +Rule	sol89	1989	only	-	Jan	4	12:05:00s -0:05:00 -
      +Rule	sol89	1989	only	-	Jan	5	12:05:25s -0:05:25 -
      +Rule	sol89	1989	only	-	Jan	6	12:05:50s -0:05:50 -
      +Rule	sol89	1989	only	-	Jan	7	12:06:15s -0:06:15 -
      +Rule	sol89	1989	only	-	Jan	8	12:06:45s -0:06:45 -
      +Rule	sol89	1989	only	-	Jan	9	12:07:10s -0:07:10 -
      +Rule	sol89	1989	only	-	Jan	10	12:07:35s -0:07:35 -
      +Rule	sol89	1989	only	-	Jan	11	12:07:55s -0:07:55 -
      +Rule	sol89	1989	only	-	Jan	12	12:08:20s -0:08:20 -
      +Rule	sol89	1989	only	-	Jan	13	12:08:45s -0:08:45 -
      +Rule	sol89	1989	only	-	Jan	14	12:09:05s -0:09:05 -
      +Rule	sol89	1989	only	-	Jan	15	12:09:25s -0:09:25 -
      +Rule	sol89	1989	only	-	Jan	16	12:09:45s -0:09:45 -
      +Rule	sol89	1989	only	-	Jan	17	12:10:05s -0:10:05 -
      +Rule	sol89	1989	only	-	Jan	18	12:10:25s -0:10:25 -
      +Rule	sol89	1989	only	-	Jan	19	12:10:45s -0:10:45 -
      +Rule	sol89	1989	only	-	Jan	20	12:11:05s -0:11:05 -
      +Rule	sol89	1989	only	-	Jan	21	12:11:20s -0:11:20 -
      +Rule	sol89	1989	only	-	Jan	22	12:11:35s -0:11:35 -
      +Rule	sol89	1989	only	-	Jan	23	12:11:55s -0:11:55 -
      +Rule	sol89	1989	only	-	Jan	24	12:12:10s -0:12:10 -
      +Rule	sol89	1989	only	-	Jan	25	12:12:20s -0:12:20 -
      +Rule	sol89	1989	only	-	Jan	26	12:12:35s -0:12:35 -
      +Rule	sol89	1989	only	-	Jan	27	12:12:50s -0:12:50 -
      +Rule	sol89	1989	only	-	Jan	28	12:13:00s -0:13:00 -
      +Rule	sol89	1989	only	-	Jan	29	12:13:10s -0:13:10 -
      +Rule	sol89	1989	only	-	Jan	30	12:13:20s -0:13:20 -
      +Rule	sol89	1989	only	-	Jan	31	12:13:30s -0:13:30 -
      +Rule	sol89	1989	only	-	Feb	1	12:13:40s -0:13:40 -
      +Rule	sol89	1989	only	-	Feb	2	12:13:45s -0:13:45 -
      +Rule	sol89	1989	only	-	Feb	3	12:13:55s -0:13:55 -
      +Rule	sol89	1989	only	-	Feb	4	12:14:00s -0:14:00 -
      +Rule	sol89	1989	only	-	Feb	5	12:14:05s -0:14:05 -
      +Rule	sol89	1989	only	-	Feb	6	12:14:10s -0:14:10 -
      +Rule	sol89	1989	only	-	Feb	7	12:14:10s -0:14:10 -
      +Rule	sol89	1989	only	-	Feb	8	12:14:15s -0:14:15 -
      +Rule	sol89	1989	only	-	Feb	9	12:14:15s -0:14:15 -
      +Rule	sol89	1989	only	-	Feb	10	12:14:20s -0:14:20 -
      +Rule	sol89	1989	only	-	Feb	11	12:14:20s -0:14:20 -
      +Rule	sol89	1989	only	-	Feb	12	12:14:20s -0:14:20 -
      +Rule	sol89	1989	only	-	Feb	13	12:14:15s -0:14:15 -
      +Rule	sol89	1989	only	-	Feb	14	12:14:15s -0:14:15 -
      +Rule	sol89	1989	only	-	Feb	15	12:14:10s -0:14:10 -
      +Rule	sol89	1989	only	-	Feb	16	12:14:10s -0:14:10 -
      +Rule	sol89	1989	only	-	Feb	17	12:14:05s -0:14:05 -
      +Rule	sol89	1989	only	-	Feb	18	12:14:00s -0:14:00 -
      +Rule	sol89	1989	only	-	Feb	19	12:13:55s -0:13:55 -
      +Rule	sol89	1989	only	-	Feb	20	12:13:50s -0:13:50 -
      +Rule	sol89	1989	only	-	Feb	21	12:13:40s -0:13:40 -
      +Rule	sol89	1989	only	-	Feb	22	12:13:35s -0:13:35 -
      +Rule	sol89	1989	only	-	Feb	23	12:13:25s -0:13:25 -
      +Rule	sol89	1989	only	-	Feb	24	12:13:15s -0:13:15 -
      +Rule	sol89	1989	only	-	Feb	25	12:13:05s -0:13:05 -
      +Rule	sol89	1989	only	-	Feb	26	12:12:55s -0:12:55 -
      +Rule	sol89	1989	only	-	Feb	27	12:12:45s -0:12:45 -
      +Rule	sol89	1989	only	-	Feb	28	12:12:35s -0:12:35 -
      +Rule	sol89	1989	only	-	Mar	1	12:12:25s -0:12:25 -
      +Rule	sol89	1989	only	-	Mar	2	12:12:10s -0:12:10 -
      +Rule	sol89	1989	only	-	Mar	3	12:12:00s -0:12:00 -
      +Rule	sol89	1989	only	-	Mar	4	12:11:45s -0:11:45 -
      +Rule	sol89	1989	only	-	Mar	5	12:11:35s -0:11:35 -
      +Rule	sol89	1989	only	-	Mar	6	12:11:20s -0:11:20 -
      +Rule	sol89	1989	only	-	Mar	7	12:11:05s -0:11:05 -
      +Rule	sol89	1989	only	-	Mar	8	12:10:50s -0:10:50 -
      +Rule	sol89	1989	only	-	Mar	9	12:10:35s -0:10:35 -
      +Rule	sol89	1989	only	-	Mar	10	12:10:20s -0:10:20 -
      +Rule	sol89	1989	only	-	Mar	11	12:10:05s -0:10:05 -
      +Rule	sol89	1989	only	-	Mar	12	12:09:50s -0:09:50 -
      +Rule	sol89	1989	only	-	Mar	13	12:09:30s -0:09:30 -
      +Rule	sol89	1989	only	-	Mar	14	12:09:15s -0:09:15 -
      +Rule	sol89	1989	only	-	Mar	15	12:09:00s -0:09:00 -
      +Rule	sol89	1989	only	-	Mar	16	12:08:40s -0:08:40 -
      +Rule	sol89	1989	only	-	Mar	17	12:08:25s -0:08:25 -
      +Rule	sol89	1989	only	-	Mar	18	12:08:05s -0:08:05 -
      +Rule	sol89	1989	only	-	Mar	19	12:07:50s -0:07:50 -
      +Rule	sol89	1989	only	-	Mar	20	12:07:30s -0:07:30 -
      +Rule	sol89	1989	only	-	Mar	21	12:07:15s -0:07:15 -
      +Rule	sol89	1989	only	-	Mar	22	12:06:55s -0:06:55 -
      +Rule	sol89	1989	only	-	Mar	23	12:06:35s -0:06:35 -
      +Rule	sol89	1989	only	-	Mar	24	12:06:20s -0:06:20 -
      +Rule	sol89	1989	only	-	Mar	25	12:06:00s -0:06:00 -
      +Rule	sol89	1989	only	-	Mar	26	12:05:40s -0:05:40 -
      +Rule	sol89	1989	only	-	Mar	27	12:05:25s -0:05:25 -
      +Rule	sol89	1989	only	-	Mar	28	12:05:05s -0:05:05 -
      +Rule	sol89	1989	only	-	Mar	29	12:04:50s -0:04:50 -
      +Rule	sol89	1989	only	-	Mar	30	12:04:30s -0:04:30 -
      +Rule	sol89	1989	only	-	Mar	31	12:04:10s -0:04:10 -
      +Rule	sol89	1989	only	-	Apr	1	12:03:55s -0:03:55 -
      +Rule	sol89	1989	only	-	Apr	2	12:03:35s -0:03:35 -
      +Rule	sol89	1989	only	-	Apr	3	12:03:20s -0:03:20 -
      +Rule	sol89	1989	only	-	Apr	4	12:03:00s -0:03:00 -
      +Rule	sol89	1989	only	-	Apr	5	12:02:45s -0:02:45 -
      +Rule	sol89	1989	only	-	Apr	6	12:02:25s -0:02:25 -
      +Rule	sol89	1989	only	-	Apr	7	12:02:10s -0:02:10 -
      +Rule	sol89	1989	only	-	Apr	8	12:01:50s -0:01:50 -
      +Rule	sol89	1989	only	-	Apr	9	12:01:35s -0:01:35 -
      +Rule	sol89	1989	only	-	Apr	10	12:01:20s -0:01:20 -
      +Rule	sol89	1989	only	-	Apr	11	12:01:05s -0:01:05 -
      +Rule	sol89	1989	only	-	Apr	12	12:00:50s -0:00:50 -
      +Rule	sol89	1989	only	-	Apr	13	12:00:35s -0:00:35 -
      +Rule	sol89	1989	only	-	Apr	14	12:00:20s -0:00:20 -
      +Rule	sol89	1989	only	-	Apr	15	12:00:05s -0:00:05 -
      +Rule	sol89	1989	only	-	Apr	16	11:59:50s 0:00:10 -
      +Rule	sol89	1989	only	-	Apr	17	11:59:35s 0:00:25 -
      +Rule	sol89	1989	only	-	Apr	18	11:59:20s 0:00:40 -
      +Rule	sol89	1989	only	-	Apr	19	11:59:10s 0:00:50 -
      +Rule	sol89	1989	only	-	Apr	20	11:58:55s 0:01:05 -
      +Rule	sol89	1989	only	-	Apr	21	11:58:45s 0:01:15 -
      +Rule	sol89	1989	only	-	Apr	22	11:58:30s 0:01:30 -
      +Rule	sol89	1989	only	-	Apr	23	11:58:20s 0:01:40 -
      +Rule	sol89	1989	only	-	Apr	24	11:58:10s 0:01:50 -
      +Rule	sol89	1989	only	-	Apr	25	11:58:00s 0:02:00 -
      +Rule	sol89	1989	only	-	Apr	26	11:57:50s 0:02:10 -
      +Rule	sol89	1989	only	-	Apr	27	11:57:40s 0:02:20 -
      +Rule	sol89	1989	only	-	Apr	28	11:57:30s 0:02:30 -
      +Rule	sol89	1989	only	-	Apr	29	11:57:20s 0:02:40 -
      +Rule	sol89	1989	only	-	Apr	30	11:57:15s 0:02:45 -
      +Rule	sol89	1989	only	-	May	1	11:57:05s 0:02:55 -
      +Rule	sol89	1989	only	-	May	2	11:57:00s 0:03:00 -
      +Rule	sol89	1989	only	-	May	3	11:56:50s 0:03:10 -
      +Rule	sol89	1989	only	-	May	4	11:56:45s 0:03:15 -
      +Rule	sol89	1989	only	-	May	5	11:56:40s 0:03:20 -
      +Rule	sol89	1989	only	-	May	6	11:56:35s 0:03:25 -
      +Rule	sol89	1989	only	-	May	7	11:56:30s 0:03:30 -
      +Rule	sol89	1989	only	-	May	8	11:56:30s 0:03:30 -
      +Rule	sol89	1989	only	-	May	9	11:56:25s 0:03:35 -
      +Rule	sol89	1989	only	-	May	10	11:56:25s 0:03:35 -
      +Rule	sol89	1989	only	-	May	11	11:56:20s 0:03:40 -
      +Rule	sol89	1989	only	-	May	12	11:56:20s 0:03:40 -
      +Rule	sol89	1989	only	-	May	13	11:56:20s 0:03:40 -
      +Rule	sol89	1989	only	-	May	14	11:56:20s 0:03:40 -
      +Rule	sol89	1989	only	-	May	15	11:56:20s 0:03:40 -
      +Rule	sol89	1989	only	-	May	16	11:56:20s 0:03:40 -
      +Rule	sol89	1989	only	-	May	17	11:56:20s 0:03:40 -
      +Rule	sol89	1989	only	-	May	18	11:56:25s 0:03:35 -
      +Rule	sol89	1989	only	-	May	19	11:56:25s 0:03:35 -
      +Rule	sol89	1989	only	-	May	20	11:56:30s 0:03:30 -
      +Rule	sol89	1989	only	-	May	21	11:56:35s 0:03:25 -
      +Rule	sol89	1989	only	-	May	22	11:56:35s 0:03:25 -
      +Rule	sol89	1989	only	-	May	23	11:56:40s 0:03:20 -
      +Rule	sol89	1989	only	-	May	24	11:56:45s 0:03:15 -
      +Rule	sol89	1989	only	-	May	25	11:56:55s 0:03:05 -
      +Rule	sol89	1989	only	-	May	26	11:57:00s 0:03:00 -
      +Rule	sol89	1989	only	-	May	27	11:57:05s 0:02:55 -
      +Rule	sol89	1989	only	-	May	28	11:57:15s 0:02:45 -
      +Rule	sol89	1989	only	-	May	29	11:57:20s 0:02:40 -
      +Rule	sol89	1989	only	-	May	30	11:57:30s 0:02:30 -
      +Rule	sol89	1989	only	-	May	31	11:57:35s 0:02:25 -
      +Rule	sol89	1989	only	-	Jun	1	11:57:45s 0:02:15 -
      +Rule	sol89	1989	only	-	Jun	2	11:57:55s 0:02:05 -
      +Rule	sol89	1989	only	-	Jun	3	11:58:05s 0:01:55 -
      +Rule	sol89	1989	only	-	Jun	4	11:58:15s 0:01:45 -
      +Rule	sol89	1989	only	-	Jun	5	11:58:25s 0:01:35 -
      +Rule	sol89	1989	only	-	Jun	6	11:58:35s 0:01:25 -
      +Rule	sol89	1989	only	-	Jun	7	11:58:45s 0:01:15 -
      +Rule	sol89	1989	only	-	Jun	8	11:59:00s 0:01:00 -
      +Rule	sol89	1989	only	-	Jun	9	11:59:10s 0:00:50 -
      +Rule	sol89	1989	only	-	Jun	10	11:59:20s 0:00:40 -
      +Rule	sol89	1989	only	-	Jun	11	11:59:35s 0:00:25 -
      +Rule	sol89	1989	only	-	Jun	12	11:59:45s 0:00:15 -
      +Rule	sol89	1989	only	-	Jun	13	12:00:00s 0:00:00 -
      +Rule	sol89	1989	only	-	Jun	14	12:00:10s -0:00:10 -
      +Rule	sol89	1989	only	-	Jun	15	12:00:25s -0:00:25 -
      +Rule	sol89	1989	only	-	Jun	16	12:00:35s -0:00:35 -
      +Rule	sol89	1989	only	-	Jun	17	12:00:50s -0:00:50 -
      +Rule	sol89	1989	only	-	Jun	18	12:01:05s -0:01:05 -
      +Rule	sol89	1989	only	-	Jun	19	12:01:15s -0:01:15 -
      +Rule	sol89	1989	only	-	Jun	20	12:01:30s -0:01:30 -
      +Rule	sol89	1989	only	-	Jun	21	12:01:40s -0:01:40 -
      +Rule	sol89	1989	only	-	Jun	22	12:01:55s -0:01:55 -
      +Rule	sol89	1989	only	-	Jun	23	12:02:10s -0:02:10 -
      +Rule	sol89	1989	only	-	Jun	24	12:02:20s -0:02:20 -
      +Rule	sol89	1989	only	-	Jun	25	12:02:35s -0:02:35 -
      +Rule	sol89	1989	only	-	Jun	26	12:02:45s -0:02:45 -
      +Rule	sol89	1989	only	-	Jun	27	12:03:00s -0:03:00 -
      +Rule	sol89	1989	only	-	Jun	28	12:03:10s -0:03:10 -
      +Rule	sol89	1989	only	-	Jun	29	12:03:25s -0:03:25 -
      +Rule	sol89	1989	only	-	Jun	30	12:03:35s -0:03:35 -
      +Rule	sol89	1989	only	-	Jul	1	12:03:45s -0:03:45 -
      +Rule	sol89	1989	only	-	Jul	2	12:04:00s -0:04:00 -
      +Rule	sol89	1989	only	-	Jul	3	12:04:10s -0:04:10 -
      +Rule	sol89	1989	only	-	Jul	4	12:04:20s -0:04:20 -
      +Rule	sol89	1989	only	-	Jul	5	12:04:30s -0:04:30 -
      +Rule	sol89	1989	only	-	Jul	6	12:04:40s -0:04:40 -
      +Rule	sol89	1989	only	-	Jul	7	12:04:50s -0:04:50 -
      +Rule	sol89	1989	only	-	Jul	8	12:05:00s -0:05:00 -
      +Rule	sol89	1989	only	-	Jul	9	12:05:10s -0:05:10 -
      +Rule	sol89	1989	only	-	Jul	10	12:05:20s -0:05:20 -
      +Rule	sol89	1989	only	-	Jul	11	12:05:25s -0:05:25 -
      +Rule	sol89	1989	only	-	Jul	12	12:05:35s -0:05:35 -
      +Rule	sol89	1989	only	-	Jul	13	12:05:40s -0:05:40 -
      +Rule	sol89	1989	only	-	Jul	14	12:05:50s -0:05:50 -
      +Rule	sol89	1989	only	-	Jul	15	12:05:55s -0:05:55 -
      +Rule	sol89	1989	only	-	Jul	16	12:06:00s -0:06:00 -
      +Rule	sol89	1989	only	-	Jul	17	12:06:05s -0:06:05 -
      +Rule	sol89	1989	only	-	Jul	18	12:06:10s -0:06:10 -
      +Rule	sol89	1989	only	-	Jul	19	12:06:15s -0:06:15 -
      +Rule	sol89	1989	only	-	Jul	20	12:06:20s -0:06:20 -
      +Rule	sol89	1989	only	-	Jul	21	12:06:20s -0:06:20 -
      +Rule	sol89	1989	only	-	Jul	22	12:06:25s -0:06:25 -
      +Rule	sol89	1989	only	-	Jul	23	12:06:25s -0:06:25 -
      +Rule	sol89	1989	only	-	Jul	24	12:06:30s -0:06:30 -
      +Rule	sol89	1989	only	-	Jul	25	12:06:30s -0:06:30 -
      +Rule	sol89	1989	only	-	Jul	26	12:06:30s -0:06:30 -
      +Rule	sol89	1989	only	-	Jul	27	12:06:30s -0:06:30 -
      +Rule	sol89	1989	only	-	Jul	28	12:06:30s -0:06:30 -
      +Rule	sol89	1989	only	-	Jul	29	12:06:25s -0:06:25 -
      +Rule	sol89	1989	only	-	Jul	30	12:06:25s -0:06:25 -
      +Rule	sol89	1989	only	-	Jul	31	12:06:20s -0:06:20 -
      +Rule	sol89	1989	only	-	Aug	1	12:06:20s -0:06:20 -
      +Rule	sol89	1989	only	-	Aug	2	12:06:15s -0:06:15 -
      +Rule	sol89	1989	only	-	Aug	3	12:06:10s -0:06:10 -
      +Rule	sol89	1989	only	-	Aug	4	12:06:05s -0:06:05 -
      +Rule	sol89	1989	only	-	Aug	5	12:06:00s -0:06:00 -
      +Rule	sol89	1989	only	-	Aug	6	12:05:50s -0:05:50 -
      +Rule	sol89	1989	only	-	Aug	7	12:05:45s -0:05:45 -
      +Rule	sol89	1989	only	-	Aug	8	12:05:35s -0:05:35 -
      +Rule	sol89	1989	only	-	Aug	9	12:05:30s -0:05:30 -
      +Rule	sol89	1989	only	-	Aug	10	12:05:20s -0:05:20 -
      +Rule	sol89	1989	only	-	Aug	11	12:05:10s -0:05:10 -
      +Rule	sol89	1989	only	-	Aug	12	12:05:00s -0:05:00 -
      +Rule	sol89	1989	only	-	Aug	13	12:04:50s -0:04:50 -
      +Rule	sol89	1989	only	-	Aug	14	12:04:40s -0:04:40 -
      +Rule	sol89	1989	only	-	Aug	15	12:04:30s -0:04:30 -
      +Rule	sol89	1989	only	-	Aug	16	12:04:15s -0:04:15 -
      +Rule	sol89	1989	only	-	Aug	17	12:04:05s -0:04:05 -
      +Rule	sol89	1989	only	-	Aug	18	12:03:50s -0:03:50 -
      +Rule	sol89	1989	only	-	Aug	19	12:03:35s -0:03:35 -
      +Rule	sol89	1989	only	-	Aug	20	12:03:25s -0:03:25 -
      +Rule	sol89	1989	only	-	Aug	21	12:03:10s -0:03:10 -
      +Rule	sol89	1989	only	-	Aug	22	12:02:55s -0:02:55 -
      +Rule	sol89	1989	only	-	Aug	23	12:02:40s -0:02:40 -
      +Rule	sol89	1989	only	-	Aug	24	12:02:20s -0:02:20 -
      +Rule	sol89	1989	only	-	Aug	25	12:02:05s -0:02:05 -
      +Rule	sol89	1989	only	-	Aug	26	12:01:50s -0:01:50 -
      +Rule	sol89	1989	only	-	Aug	27	12:01:30s -0:01:30 -
      +Rule	sol89	1989	only	-	Aug	28	12:01:15s -0:01:15 -
      +Rule	sol89	1989	only	-	Aug	29	12:00:55s -0:00:55 -
      +Rule	sol89	1989	only	-	Aug	30	12:00:40s -0:00:40 -
      +Rule	sol89	1989	only	-	Aug	31	12:00:20s -0:00:20 -
      +Rule	sol89	1989	only	-	Sep	1	12:00:00s 0:00:00 -
      +Rule	sol89	1989	only	-	Sep	2	11:59:45s 0:00:15 -
      +Rule	sol89	1989	only	-	Sep	3	11:59:25s 0:00:35 -
      +Rule	sol89	1989	only	-	Sep	4	11:59:05s 0:00:55 -
      +Rule	sol89	1989	only	-	Sep	5	11:58:45s 0:01:15 -
      +Rule	sol89	1989	only	-	Sep	6	11:58:25s 0:01:35 -
      +Rule	sol89	1989	only	-	Sep	7	11:58:05s 0:01:55 -
      +Rule	sol89	1989	only	-	Sep	8	11:57:45s 0:02:15 -
      +Rule	sol89	1989	only	-	Sep	9	11:57:20s 0:02:40 -
      +Rule	sol89	1989	only	-	Sep	10	11:57:00s 0:03:00 -
      +Rule	sol89	1989	only	-	Sep	11	11:56:40s 0:03:20 -
      +Rule	sol89	1989	only	-	Sep	12	11:56:20s 0:03:40 -
      +Rule	sol89	1989	only	-	Sep	13	11:56:00s 0:04:00 -
      +Rule	sol89	1989	only	-	Sep	14	11:55:35s 0:04:25 -
      +Rule	sol89	1989	only	-	Sep	15	11:55:15s 0:04:45 -
      +Rule	sol89	1989	only	-	Sep	16	11:54:55s 0:05:05 -
      +Rule	sol89	1989	only	-	Sep	17	11:54:35s 0:05:25 -
      +Rule	sol89	1989	only	-	Sep	18	11:54:10s 0:05:50 -
      +Rule	sol89	1989	only	-	Sep	19	11:53:50s 0:06:10 -
      +Rule	sol89	1989	only	-	Sep	20	11:53:30s 0:06:30 -
      +Rule	sol89	1989	only	-	Sep	21	11:53:10s 0:06:50 -
      +Rule	sol89	1989	only	-	Sep	22	11:52:45s 0:07:15 -
      +Rule	sol89	1989	only	-	Sep	23	11:52:25s 0:07:35 -
      +Rule	sol89	1989	only	-	Sep	24	11:52:05s 0:07:55 -
      +Rule	sol89	1989	only	-	Sep	25	11:51:45s 0:08:15 -
      +Rule	sol89	1989	only	-	Sep	26	11:51:25s 0:08:35 -
      +Rule	sol89	1989	only	-	Sep	27	11:51:05s 0:08:55 -
      +Rule	sol89	1989	only	-	Sep	28	11:50:40s 0:09:20 -
      +Rule	sol89	1989	only	-	Sep	29	11:50:20s 0:09:40 -
      +Rule	sol89	1989	only	-	Sep	30	11:50:00s 0:10:00 -
      +Rule	sol89	1989	only	-	Oct	1	11:49:45s 0:10:15 -
      +Rule	sol89	1989	only	-	Oct	2	11:49:25s 0:10:35 -
      +Rule	sol89	1989	only	-	Oct	3	11:49:05s 0:10:55 -
      +Rule	sol89	1989	only	-	Oct	4	11:48:45s 0:11:15 -
      +Rule	sol89	1989	only	-	Oct	5	11:48:30s 0:11:30 -
      +Rule	sol89	1989	only	-	Oct	6	11:48:10s 0:11:50 -
      +Rule	sol89	1989	only	-	Oct	7	11:47:50s 0:12:10 -
      +Rule	sol89	1989	only	-	Oct	8	11:47:35s 0:12:25 -
      +Rule	sol89	1989	only	-	Oct	9	11:47:20s 0:12:40 -
      +Rule	sol89	1989	only	-	Oct	10	11:47:00s 0:13:00 -
      +Rule	sol89	1989	only	-	Oct	11	11:46:45s 0:13:15 -
      +Rule	sol89	1989	only	-	Oct	12	11:46:30s 0:13:30 -
      +Rule	sol89	1989	only	-	Oct	13	11:46:15s 0:13:45 -
      +Rule	sol89	1989	only	-	Oct	14	11:46:00s 0:14:00 -
      +Rule	sol89	1989	only	-	Oct	15	11:45:50s 0:14:10 -
      +Rule	sol89	1989	only	-	Oct	16	11:45:35s 0:14:25 -
      +Rule	sol89	1989	only	-	Oct	17	11:45:20s 0:14:40 -
      +Rule	sol89	1989	only	-	Oct	18	11:45:10s 0:14:50 -
      +Rule	sol89	1989	only	-	Oct	19	11:45:00s 0:15:00 -
      +Rule	sol89	1989	only	-	Oct	20	11:44:50s 0:15:10 -
      +Rule	sol89	1989	only	-	Oct	21	11:44:40s 0:15:20 -
      +Rule	sol89	1989	only	-	Oct	22	11:44:30s 0:15:30 -
      +Rule	sol89	1989	only	-	Oct	23	11:44:20s 0:15:40 -
      +Rule	sol89	1989	only	-	Oct	24	11:44:10s 0:15:50 -
      +Rule	sol89	1989	only	-	Oct	25	11:44:05s 0:15:55 -
      +Rule	sol89	1989	only	-	Oct	26	11:44:00s 0:16:00 -
      +Rule	sol89	1989	only	-	Oct	27	11:43:50s 0:16:10 -
      +Rule	sol89	1989	only	-	Oct	28	11:43:45s 0:16:15 -
      +Rule	sol89	1989	only	-	Oct	29	11:43:40s 0:16:20 -
      +Rule	sol89	1989	only	-	Oct	30	11:43:40s 0:16:20 -
      +Rule	sol89	1989	only	-	Oct	31	11:43:35s 0:16:25 -
      +Rule	sol89	1989	only	-	Nov	1	11:43:35s 0:16:25 -
      +Rule	sol89	1989	only	-	Nov	2	11:43:35s 0:16:25 -
      +Rule	sol89	1989	only	-	Nov	3	11:43:30s 0:16:30 -
      +Rule	sol89	1989	only	-	Nov	4	11:43:35s 0:16:25 -
      +Rule	sol89	1989	only	-	Nov	5	11:43:35s 0:16:25 -
      +Rule	sol89	1989	only	-	Nov	6	11:43:35s 0:16:25 -
      +Rule	sol89	1989	only	-	Nov	7	11:43:40s 0:16:20 -
      +Rule	sol89	1989	only	-	Nov	8	11:43:45s 0:16:15 -
      +Rule	sol89	1989	only	-	Nov	9	11:43:50s 0:16:10 -
      +Rule	sol89	1989	only	-	Nov	10	11:43:55s 0:16:05 -
      +Rule	sol89	1989	only	-	Nov	11	11:44:00s 0:16:00 -
      +Rule	sol89	1989	only	-	Nov	12	11:44:05s 0:15:55 -
      +Rule	sol89	1989	only	-	Nov	13	11:44:15s 0:15:45 -
      +Rule	sol89	1989	only	-	Nov	14	11:44:25s 0:15:35 -
      +Rule	sol89	1989	only	-	Nov	15	11:44:35s 0:15:25 -
      +Rule	sol89	1989	only	-	Nov	16	11:44:45s 0:15:15 -
      +Rule	sol89	1989	only	-	Nov	17	11:44:55s 0:15:05 -
      +Rule	sol89	1989	only	-	Nov	18	11:45:10s 0:14:50 -
      +Rule	sol89	1989	only	-	Nov	19	11:45:20s 0:14:40 -
      +Rule	sol89	1989	only	-	Nov	20	11:45:35s 0:14:25 -
      +Rule	sol89	1989	only	-	Nov	21	11:45:50s 0:14:10 -
      +Rule	sol89	1989	only	-	Nov	22	11:46:05s 0:13:55 -
      +Rule	sol89	1989	only	-	Nov	23	11:46:25s 0:13:35 -
      +Rule	sol89	1989	only	-	Nov	24	11:46:40s 0:13:20 -
      +Rule	sol89	1989	only	-	Nov	25	11:47:00s 0:13:00 -
      +Rule	sol89	1989	only	-	Nov	26	11:47:20s 0:12:40 -
      +Rule	sol89	1989	only	-	Nov	27	11:47:35s 0:12:25 -
      +Rule	sol89	1989	only	-	Nov	28	11:47:55s 0:12:05 -
      +Rule	sol89	1989	only	-	Nov	29	11:48:20s 0:11:40 -
      +Rule	sol89	1989	only	-	Nov	30	11:48:40s 0:11:20 -
      +Rule	sol89	1989	only	-	Dec	1	11:49:00s 0:11:00 -
      +Rule	sol89	1989	only	-	Dec	2	11:49:25s 0:10:35 -
      +Rule	sol89	1989	only	-	Dec	3	11:49:50s 0:10:10 -
      +Rule	sol89	1989	only	-	Dec	4	11:50:15s 0:09:45 -
      +Rule	sol89	1989	only	-	Dec	5	11:50:35s 0:09:25 -
      +Rule	sol89	1989	only	-	Dec	6	11:51:00s 0:09:00 -
      +Rule	sol89	1989	only	-	Dec	7	11:51:30s 0:08:30 -
      +Rule	sol89	1989	only	-	Dec	8	11:51:55s 0:08:05 -
      +Rule	sol89	1989	only	-	Dec	9	11:52:20s 0:07:40 -
      +Rule	sol89	1989	only	-	Dec	10	11:52:50s 0:07:10 -
      +Rule	sol89	1989	only	-	Dec	11	11:53:15s 0:06:45 -
      +Rule	sol89	1989	only	-	Dec	12	11:53:45s 0:06:15 -
      +Rule	sol89	1989	only	-	Dec	13	11:54:10s 0:05:50 -
      +Rule	sol89	1989	only	-	Dec	14	11:54:40s 0:05:20 -
      +Rule	sol89	1989	only	-	Dec	15	11:55:10s 0:04:50 -
      +Rule	sol89	1989	only	-	Dec	16	11:55:40s 0:04:20 -
      +Rule	sol89	1989	only	-	Dec	17	11:56:05s 0:03:55 -
      +Rule	sol89	1989	only	-	Dec	18	11:56:35s 0:03:25 -
      +Rule	sol89	1989	only	-	Dec	19	11:57:05s 0:02:55 -
      +Rule	sol89	1989	only	-	Dec	20	11:57:35s 0:02:25 -
      +Rule	sol89	1989	only	-	Dec	21	11:58:05s 0:01:55 -
      +Rule	sol89	1989	only	-	Dec	22	11:58:35s 0:01:25 -
      +Rule	sol89	1989	only	-	Dec	23	11:59:05s 0:00:55 -
      +Rule	sol89	1989	only	-	Dec	24	11:59:35s 0:00:25 -
      +Rule	sol89	1989	only	-	Dec	25	12:00:05s -0:00:05 -
      +Rule	sol89	1989	only	-	Dec	26	12:00:35s -0:00:35 -
      +Rule	sol89	1989	only	-	Dec	27	12:01:05s -0:01:05 -
      +Rule	sol89	1989	only	-	Dec	28	12:01:35s -0:01:35 -
      +Rule	sol89	1989	only	-	Dec	29	12:02:00s -0:02:00 -
      +Rule	sol89	1989	only	-	Dec	30	12:02:30s -0:02:30 -
      +Rule	sol89	1989	only	-	Dec	31	12:03:00s -0:03:00 -
      +
      +# Riyadh is at about 46 degrees 46 minutes East:  3 hrs, 7 mins, 4 secs
      +# Before and after 1989, we'll operate on local mean solar time.
      +
      +# Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
      +Zone	Asia/Riyadh89	3:07:04	-		zzz	1989
      +			3:07:04	sol89		zzz	1990
      +			3:07:04	-		zzz
      +# For backward compatibility...
      +Link	Asia/Riyadh89	Mideast/Riyadh89
      diff --git a/jdk/test/sun/util/calendar/zi/tzdata/southamerica b/jdk/test/sun/util/calendar/zi/tzdata/southamerica
      new file mode 100644
      index 00000000000..0d6797eab6b
      --- /dev/null
      +++ b/jdk/test/sun/util/calendar/zi/tzdata/southamerica
      @@ -0,0 +1,1734 @@
      +#
      +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      +#  
      +# This code is free software; you can redistribute it and/or modify it
      +# under the terms of the GNU General Public License version 2 only, as
      +# published by the Free Software Foundation.  Oracle designates this
      +# particular file as subject to the "Classpath" exception as provided
      +# by Oracle in the LICENSE file that accompanied this code.
      +#  
      +# This code is distributed in the hope that it will be useful, but WITHOUT
      +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      +# version 2 for more details (a copy is included in the LICENSE file that
      +# accompanied this code).
      +#  
      +# You should have received a copy of the GNU General Public License version
      +# 2 along with this work; if not, write to the Free Software Foundation,
      +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      +#  
      +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      +# or visit www.oracle.com if you need additional information or have any
      +# questions.
      +#
      +# 
      +# This file is in the public domain, so clarified as of
      +# 2009-05-17 by Arthur David Olson.
      +
      +# This data is by no means authoritative; if you think you know better,
      +# go ahead and edit the file (and please send any changes to
      +# tz@elsie.nci.nih.gov for general use in the future).
      +
      +# From Paul Eggert (2006-03-22):
      +# A good source for time zone historical data outside the U.S. is
      +# Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition),
      +# San Diego: ACS Publications, Inc. (2003).
      +#
      +# Gwillim Law writes that a good source
      +# for recent time zone data is the International Air Transport
      +# Association's Standard Schedules Information Manual (IATA SSIM),
      +# published semiannually.  Law sent in several helpful summaries
      +# of the IATA's data after 1990.
      +#
      +# Except where otherwise noted, Shanks & Pottenger is the source for
      +# entries through 1990, and IATA SSIM is the source for entries afterwards.
      +#
      +# Earlier editions of these tables used the North American style (e.g. ARST and
      +# ARDT for Argentine Standard and Daylight Time), but the following quote
      +# suggests that it's better to use European style (e.g. ART and ARST).
      +#	I suggest the use of _Summer time_ instead of the more cumbersome
      +#	_daylight-saving time_.  _Summer time_ seems to be in general use
      +#	in Europe and South America.
      +#	-- E O Cutler, _New York Times_ (1937-02-14), quoted in
      +#	H L Mencken, _The American Language: Supplement I_ (1960), p 466
      +#
      +# Earlier editions of these tables also used the North American style
      +# for time zones in Brazil, but this was incorrect, as Brazilians say
      +# "summer time".  Reinaldo Goulart, a Sao Paulo businessman active in
      +# the railroad sector, writes (1999-07-06):
      +#	The subject of time zones is currently a matter of discussion/debate in
      +#	Brazil.  Let's say that "the Brasilia time" is considered the
      +#	"official time" because Brasilia is the capital city.
      +#	The other three time zones are called "Brasilia time "minus one" or
      +#	"plus one" or "plus two".  As far as I know there is no such
      +#	name/designation as "Eastern Time" or "Central Time".
      +# So I invented the following (English-language) abbreviations for now.
      +# Corrections are welcome!
      +#		std	dst
      +#	-2:00	FNT	FNST	Fernando de Noronha
      +#	-3:00	BRT	BRST	Brasilia
      +#	-4:00	AMT	AMST	Amazon
      +#	-5:00	ACT	ACST	Acre
      +
      +###############################################################################
      +
      +###############################################################################
      +
      +# Argentina
      +
      +# From Bob Devine (1988-01-28):
      +# Argentina: first Sunday in October to first Sunday in April since 1976.
      +# Double Summer time from 1969 to 1974.  Switches at midnight.
      +
      +# From U. S. Naval Observatory (1988-01-199):
      +# ARGENTINA           3 H BEHIND   UTC
      +
      +# From Hernan G. Otero (1995-06-26):
      +# I am sending modifications to the Argentine time zone table...
      +# AR was chosen because they are the ISO letters that represent Argentina.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Arg	1930	only	-	Dec	 1	0:00	1:00	S
      +Rule	Arg	1931	only	-	Apr	 1	0:00	0	-
      +Rule	Arg	1931	only	-	Oct	15	0:00	1:00	S
      +Rule	Arg	1932	1940	-	Mar	 1	0:00	0	-
      +Rule	Arg	1932	1939	-	Nov	 1	0:00	1:00	S
      +Rule	Arg	1940	only	-	Jul	 1	0:00	1:00	S
      +Rule	Arg	1941	only	-	Jun	15	0:00	0	-
      +Rule	Arg	1941	only	-	Oct	15	0:00	1:00	S
      +Rule	Arg	1943	only	-	Aug	 1	0:00	0	-
      +Rule	Arg	1943	only	-	Oct	15	0:00	1:00	S
      +Rule	Arg	1946	only	-	Mar	 1	0:00	0	-
      +Rule	Arg	1946	only	-	Oct	 1	0:00	1:00	S
      +Rule	Arg	1963	only	-	Oct	 1	0:00	0	-
      +Rule	Arg	1963	only	-	Dec	15	0:00	1:00	S
      +Rule	Arg	1964	1966	-	Mar	 1	0:00	0	-
      +Rule	Arg	1964	1966	-	Oct	15	0:00	1:00	S
      +Rule	Arg	1967	only	-	Apr	 2	0:00	0	-
      +Rule	Arg	1967	1968	-	Oct	Sun>=1	0:00	1:00	S
      +Rule	Arg	1968	1969	-	Apr	Sun>=1	0:00	0	-
      +Rule	Arg	1974	only	-	Jan	23	0:00	1:00	S
      +Rule	Arg	1974	only	-	May	 1	0:00	0	-
      +Rule	Arg	1988	only	-	Dec	 1	0:00	1:00	S
      +#
      +# From Hernan G. Otero (1995-06-26):
      +# These corrections were contributed by InterSoft Argentina S.A.,
      +# obtaining the data from the:
      +# Talleres de Hidrografia Naval Argentina
      +# (Argentine Naval Hydrography Institute)
      +Rule	Arg	1989	1993	-	Mar	Sun>=1	0:00	0	-
      +Rule	Arg	1989	1992	-	Oct	Sun>=15	0:00	1:00	S
      +#
      +# From Hernan G. Otero (1995-06-26):
      +# From this moment on, the law that mandated the daylight saving
      +# time corrections was derogated and no more modifications
      +# to the time zones (for daylight saving) are now made.
      +#
      +# From Rives McDow (2000-01-10):
      +# On October 3, 1999, 0:00 local, Argentina implemented daylight savings time,
      +# which did not result in the switch of a time zone, as they stayed 9 hours
      +# from the International Date Line.
      +Rule	Arg	1999	only	-	Oct	Sun>=1	0:00	1:00	S
      +# From Paul Eggert (2007-12-28):
      +# DST was set to expire on March 5, not March 3, but since it was converted
      +# to standard time on March 3 it's more convenient for us to pretend that
      +# it ended on March 3.
      +Rule	Arg	2000	only	-	Mar	3	0:00	0	-
      +#
      +# From Peter Gradelski via Steffen Thorsen (2000-03-01):
      +# We just checked with our Sao Paulo office and they say the government of
      +# Argentina decided not to become one of the countries that go on or off DST.
      +# So Buenos Aires should be -3 hours from GMT at all times.
      +#
      +# From Fabian L. Arce Jofre (2000-04-04):
      +# The law that claimed DST for Argentina was derogated by President Fernando
      +# de la Rua on March 2, 2000, because it would make people spend more energy
      +# in the winter time, rather than less.  The change took effect on March 3.
      +#
      +# From Mariano Absatz (2001-06-06):
      +# one of the major newspapers here in Argentina said that the 1999
      +# Timezone Law (which never was effectively applied) will (would?) be
      +# in effect.... The article is at
      +# http://ar.clarin.com/diario/2001-06-06/e-01701.htm
      +# ... The Law itself is "Ley No 25155", sanctioned on 1999-08-25, enacted
      +# 1999-09-17, and published 1999-09-21.  The official publication is at:
      +# http://www.boletin.jus.gov.ar/BON/Primera/1999/09-Septiembre/21/PDF/BO21-09-99LEG.PDF
      +# Regretfully, you have to subscribe (and pay) for the on-line version....
      +#
      +# (2001-06-12):
      +# the timezone for Argentina will not change next Sunday.
      +# Apparently it will do so on Sunday 24th....
      +# http://ar.clarin.com/diario/2001-06-12/s-03501.htm
      +#
      +# (2001-06-25):
      +# Last Friday (yes, the last working day before the date of the change), the
      +# Senate annulled the 1999 law that introduced the changes later postponed.
      +# http://www.clarin.com.ar/diario/2001-06-22/s-03601.htm
      +# It remains the vote of the Deputies..., but it will be the same....
      +# This kind of things had always been done this way in Argentina.
      +# We are still -03:00 all year round in all of the country.
      +#
      +# From Steffen Thorsen (2007-12-21):
      +# A user (Leonardo Chaim) reported that Argentina will adopt DST....
      +# all of the country (all Zone-entries) are affected.  News reports like
      +# http://www.lanacion.com.ar/opinion/nota.asp?nota_id=973037 indicate
      +# that Argentina will use DST next year as well, from October to
      +# March, although exact rules are not given.
      +#
      +# From Jesper Norgaard Welen (2007-12-26)
      +# The last hurdle of Argentina DST is over, the proposal was approved in
      +# the lower chamber too (Deputados) with a vote 192 for and 2 against.
      +# By the way thanks to Mariano Absatz and Daniel Mario Vega for the link to
      +# the original scanned proposal, where the dates and the zero hours are
      +# clear and unambiguous...This is the article about final approval:
      +# 
      +# http://www.lanacion.com.ar/politica/nota.asp?nota_id=973996
      +# 
      +#
      +# From Paul Eggert (2007-12-22):
      +# For dates after mid-2008, the following rules are my guesses and
      +# are quite possibly wrong, but are more likely than no DST at all.
      +
      +# From Alexander Krivenyshev (2008-09-05):
      +# As per message from Carlos Alberto Fonseca Arauz (Nicaragua),
      +# Argentina will start DST on Sunday October 19, 2008.
      +#
      +# 
      +# http://www.worldtimezone.com/dst_news/dst_news_argentina03.html
      +# 
      +# OR
      +# 
      +# http://www.impulsobaires.com.ar/nota.php?id=57832 (in spanish)
      +# 
      +
      +# From Rodrigo Severo (2008-10-06):
      +# Here is some info available at a Gentoo bug related to TZ on Argentina's DST:
      +# ...
      +# ------- Comment #1 from [jmdocile]  2008-10-06 16:28 0000 -------
      +# Hi, there is a problem with timezone-data-2008e and maybe with
      +# timezone-data-2008f
      +# Argentinian law [Number] 25.155 is no longer valid.
      +# 
      +# http://www.infoleg.gov.ar/infolegInternet/anexos/60000-64999/60036/norma.htm
      +# 
      +# The new one is law [Number] 26.350
      +# 
      +# http://www.infoleg.gov.ar/infolegInternet/anexos/135000-139999/136191/norma.htm
      +# 
      +# So there is no summer time in Argentina for now.
      +
      +# From Mariano Absatz (2008-10-20):
      +# Decree 1693/2008 applies Law 26.350 for the summer 2008/2009 establishing DST in Argentina
      +# From 2008-10-19 until 2009-03-15
      +# 
      +# http://www.boletinoficial.gov.ar/Bora.Portal/CustomControls/PdfContent.aspx?fp=16102008&pi=3&pf=4&s=0&sec=01
      +# 
      +#
      +# Decree 1705/2008 excepting 12 Provinces from applying DST in the summer 2008/2009:
      +# Catamarca, La Rioja, Mendoza, Salta, San Juan, San Luis, La Pampa, Neuquen, Rio Negro, Chubut, Santa Cruz
      +# and Tierra del Fuego
      +# 
      +# http://www.boletinoficial.gov.ar/Bora.Portal/CustomControls/PdfContent.aspx?fp=17102008&pi=1&pf=1&s=0&sec=01
      +# 
      +#
      +# Press release 235 dated Saturday October 18th, from the Government of the Province of Jujuy saying
      +# it will not apply DST either (even when it was not included in Decree 1705/2008)
      +# 
      +# http://www.jujuy.gov.ar/index2/partes_prensa/18_10_08/235-181008.doc
      +# 
      +
      +# From fullinet (2009-10-18):
      +# As announced in
      +# 
      +# http://www.argentina.gob.ar/argentina/portal/paginas.dhtml?pagina=356
      +# 
      +# (an official .gob.ar) under title: "Sin Cambio de Hora" (english: "No hour change")
      +#
      +# "Por el momento, el Gobierno Nacional resolvio no modificar la hora
      +# oficial, decision que estaba en estudio para su implementacion el
      +# domingo 18 de octubre. Desde el Ministerio de Planificacion se anuncio
      +# que la Argentina hoy, en estas condiciones meteorologicas, no necesita
      +# la modificacion del huso horario, ya que 2009 nos encuentra con
      +# crecimiento en la produccion y distribucion energetica."
      +
      +Rule	Arg	2007	only	-	Dec	30	0:00	1:00	S
      +Rule	Arg	2008	2009	-	Mar	Sun>=15	0:00	0	-
      +Rule	Arg	2008	only	-	Oct	Sun>=15	0:00	1:00	S
      +
      +# From Mariano Absatz (2004-05-21):
      +# Today it was officially published that the Province of Mendoza is changing
      +# its timezone this winter... starting tomorrow night....
      +# http://www.gobernac.mendoza.gov.ar/boletin/pdf/20040521-27158-normas.pdf
      +# From Paul Eggert (2004-05-24):
      +# It's Law No. 7,210.  This change is due to a public power emergency, so for
      +# now we'll assume it's for this year only.
      +#
      +# From Paul Eggert (2006-03-22):
      +# 
      +# Hora de verano para la Republica Argentina (2003-06-08)
      +#  says that standard time in Argentina from 1894-10-31
      +# to 1920-05-01 was -4:16:48.25.  Go with this more-precise value
      +# over Shanks & Pottenger.
      +#
      +# From Mariano Absatz (2004-06-05):
      +# These media articles from a major newspaper mostly cover the current state:
      +# http://www.lanacion.com.ar/04/05/27/de_604825.asp
      +# http://www.lanacion.com.ar/04/05/28/de_605203.asp
      +#
      +# The following eight (8) provinces pulled clocks back to UTC-04:00 at
      +# midnight Monday May 31st. (that is, the night between 05/31 and 06/01).
      +# Apparently, all nine provinces would go back to UTC-03:00 at the same
      +# time in October 17th.
      +#
      +# Catamarca, Chubut, La Rioja, San Juan, San Luis, Santa Cruz,
      +# Tierra del Fuego, Tucuman.
      +#
      +# From Mariano Absatz (2004-06-14):
      +# ... this weekend, the Province of Tucuman decided it'd go back to UTC-03:00
      +# yesterday midnight (that is, at 24:00 Saturday 12th), since the people's
      +# annoyance with the change is much higher than the power savings obtained....
      +#
      +# From Gwillim Law (2004-06-14):
      +# http://www.lanacion.com.ar/04/06/10/de_609078.asp ...
      +#     "The time change in Tierra del Fuego was a conflicted decision from
      +#   the start.  The government had decreed that the measure would take
      +#   effect on June 1, but a normative error forced the new time to begin
      +#   three days earlier, from a Saturday to a Sunday....
      +# Our understanding was that the change was originally scheduled to take place
      +# on June 1 at 00:00 in Chubut, Santa Cruz, Tierra del Fuego (and some other
      +# provinces).  Sunday was May 30, only two days earlier.  So the article
      +# contains a contradiction.  I would give more credence to the Saturday/Sunday
      +# date than the "three days earlier" phrase, and conclude that Tierra del
      +# Fuego set its clocks back at 2004-05-30 00:00.
      +#
      +# From Steffen Thorsen (2004-10-05):
      +# The previous law 7210 which changed the province of Mendoza's time zone
      +# back in May have been modified slightly in a new law 7277, which set the
      +# new end date to 2004-09-26 (original date was 2004-10-17).
      +# http://www.gobernac.mendoza.gov.ar/boletin/pdf/20040924-27244-normas.pdf
      +#
      +# From Mariano Absatz (2004-10-05):
      +# San Juan changed from UTC-03:00 to UTC-04:00 at midnight between
      +# Sunday, May 30th and Monday, May 31st.  It changed back to UTC-03:00
      +# at midnight between Saturday, July 24th and Sunday, July 25th....
      +# http://www.sanjuan.gov.ar/prensa/archivo/000329.html
      +# http://www.sanjuan.gov.ar/prensa/archivo/000426.html
      +# http://www.sanjuan.gov.ar/prensa/archivo/000441.html
      +
      +# From Alex Krivenyshev (2008-01-17):
      +# Here are articles that Argentina Province San Luis is planning to end DST
      +# as earlier as upcoming Monday January 21, 2008 or February 2008:
      +#
      +# Provincia argentina retrasa reloj y marca diferencia con resto del pais
      +# (Argentine Province delayed clock and mark difference with the rest of the
      +# country)
      +# 
      +# http://cl.invertia.com/noticias/noticia.aspx?idNoticia=200801171849_EFE_ET4373&idtel
      +# 
      +#
      +# Es inminente que en San Luis atrasen una hora los relojes
      +# (It is imminent in San Luis clocks one hour delay)
      +# 
      +# http://www.lagaceta.com.ar/vernotae.asp?id_nota=253414
      +# 
      +#
      +# 
      +# http://www.worldtimezone.net/dst_news/dst_news_argentina02.html
      +# 
      +
      +# From Jesper Norgaard Welen (2008-01-18):
      +# The page of the San Luis provincial government
      +# 
      +# http://www.sanluis.gov.ar/notas.asp?idCanal=0&id=22812
      +# 
      +# confirms what Alex Krivenyshev has earlier sent to the tz
      +# emailing list about that San Luis plans to return to standard
      +# time much earlier than the rest of the country. It also
      +# confirms that upon request the provinces San Juan and Mendoza
      +# refused to follow San Luis in this change.
      +#
      +# The change is supposed to take place Monday the 21.st at 0:00
      +# hours. As far as I understand it if this goes ahead, we need
      +# a new timezone for San Luis (although there are also documented
      +# independent changes in the southamerica file of San Luis in
      +# 1990 and 1991 which has not been confirmed).
      +
      +# From Jesper Norgaard Welen (2008-01-25):
      +# Unfortunately the below page has become defunct, about the San Luis
      +# time change. Perhaps because it now is part of a group of pages "Most
      +# important pages of 2008."
      +#
      +# You can use
      +# 
      +# http://www.sanluis.gov.ar/notas.asp?idCanal=8141&id=22834
      +# 
      +# instead it seems. Or use "Buscador" from the main page of the San Luis
      +# government, and fill in "huso" and click OK, and you will get 3 pages
      +# from which the first one is identical to the above.
      +
      +# From Mariano Absatz (2008-01-28):
      +# I can confirm that the Province of San Luis (and so far only that
      +# province) decided to go back to UTC-3 effective midnight Jan 20th 2008
      +# (that is, Monday 21st at 0:00 is the time the clocks were delayed back
      +# 1 hour), and they intend to keep UTC-3 as their timezone all year round
      +# (that is, unless they change their mind any minute now).
      +#
      +# So we'll have to add yet another city to 'southamerica' (I think San
      +# Luis city is the mos populated city in the Province, so it'd be
      +# America/Argentina/San_Luis... of course I can't remember if San Luis's
      +# history of particular changes goes along with Mendoza or San Juan :-(
      +# (I only remember not being able to collect hard facts about San Luis
      +# back in 2004, when these provinces changed to UTC-4 for a few days, I
      +# mailed them personally and never got an answer).
      +
      +# From Paul Eggert (2008-06-30):
      +# Unless otherwise specified, data are from Shanks & Pottenger through 1992,
      +# from the IATA otherwise.  As noted below, Shanks & Pottenger say that
      +# America/Cordoba split into 6 subregions during 1991/1992, one of which
      +# was America/San_Luis, but we haven't verified this yet so for now we'll
      +# keep America/Cordoba a single region rather than splitting it into the
      +# other 5 subregions.
      +
      +# From Mariano Absatz (2009-03-13):
      +# Yesterday (with our usual 2-day notice) the Province of San Luis
      +# decided that next Sunday instead of "staying" @utc-03:00 they will go
      +# to utc-04:00 until the second Saturday in October...
      +#
      +# The press release is at
      +# 
      +# http://www.sanluis.gov.ar/SL/Paginas/NoticiaDetalle.asp?TemaId=1&InfoPrensaId=3102
      +# 
      +# (I couldn't find the decree, but
      +# 
      +# www.sanluis.gov.ar
      +# 
      +# is the official page for the Province Government).
      +#
      +# There's also a note in only one of the major national papers (La Nación) at
      +# 
      +# http://www.lanacion.com.ar/nota.asp?nota_id=1107912
      +# 
      +#
      +# The press release says:
      +#  (...) anunció que el próximo domingo a las 00:00 los puntanos deberán
      +# atrasar una hora sus relojes.
      +#
      +# A partir de entonces, San Luis establecerá el huso horario propio de
      +# la Provincia. De esta manera, durante el periodo del calendario anual
      +# 2009, el cambio horario quedará comprendido entre las 00:00 del tercer
      +# domingo de marzo y las 24:00 del segundo sábado de octubre.
      +# Quick&dirty translation
      +# (...) announced that next Sunday, at 00:00, Puntanos (the San Luis
      +# inhabitants) will have to turn back one hour their clocks
      +#
      +# Since then, San Luis will establish its own Province timezone. Thus,
      +# during 2009, this timezone change will run from 00:00 the third Sunday
      +# in March until 24:00 of the second Saturday in October.
      +
      +# From Mariano Absatz (2009-10-16):
      +# ...the Province of San Luis is a case in itself.
      +#
      +# The Law at
      +# 
      +# is ambiguous because establishes a calendar from the 2nd Sunday in
      +# October at 0:00 thru the 2nd Saturday in March at 24:00 and the
      +# complement of that starting on the 2nd Sunday of March at 0:00 and
      +# ending on the 2nd Saturday of March at 24:00.
      +#
      +# This clearly breaks every time the 1st of March or October is a Sunday.
      +#
      +# IMHO, the "spirit of the Law" is to make the changes at 0:00 on the 2nd
      +# Sunday of October and March.
      +#
      +# The problem is that the changes in the rest of the Provinces that did
      +# change in 2007/2008, were made according to the Federal Law and Decrees
      +# that did so on the 3rd Sunday of October and March.
      +#
      +# In fact, San Luis actually switched from UTC-4 to UTC-3 last Sunday
      +# (October 11th) at 0:00.
      +#
      +# So I guess a new set of rules, besides "Arg", must be made and the last
      +# America/Argentina/San_Luis entries should change to use these...
      +#
      +# I'm enclosing a patch that does what I say... regretfully, the San Luis
      +# timezone must be called "WART/WARST" even when most of the time (like,
      +# right now) WARST == ART... that is, since last Sunday, all the country
      +# is using UTC-3, but in my patch, San Luis calls it "WARST" and the rest
      +# of the country calls it "ART".
      +# ...
      +
      +# From Alexander Krivenyshev (2010-04-09):
      +# According to news reports from El Diario de la Republica Province San
      +# Luis, Argentina (standard time UTC-04) will keep Daylight Saving Time
      +# after April 11, 2010--will continue to have same time as rest of
      +# Argentina (UTC-3) (no DST).
      +#
      +# Confirmaron la prórroga del huso horario de verano (Spanish)
      +# 
      +# http://www.eldiariodelarepublica.com/index.php?option=com_content&task=view&id=29383&Itemid=9
      +# 
      +# or (some English translation):
      +# 
      +# http://www.worldtimezone.com/dst_news/dst_news_argentina08.html
      +# 
      +
      +# From Mariano Absatz (2010-04-12):
      +# yes...I can confirm this...and given that San Luis keeps calling
      +# UTC-03:00 "summer time", we should't just let San Luis go back to "Arg"
      +# rules...San Luis is still using "Western ARgentina Time" and it got
      +# stuck on Summer daylight savings time even though the summer is over.
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +#
      +# Buenos Aires (BA), Capital Federal (CF),
      +Zone America/Argentina/Buenos_Aires -3:53:48 - LMT 1894 Oct 31
      +			-4:16:48 -	CMT	1920 May # Cordoba Mean Time
      +			-4:00	-	ART	1930 Dec
      +			-4:00	Arg	AR%sT	1969 Oct  5
      +			-3:00	Arg	AR%sT	1999 Oct  3
      +			-4:00	Arg	AR%sT	2000 Mar  3
      +			-3:00	Arg	AR%sT
      +#
      +# Cordoba (CB), Santa Fe (SF), Entre Rios (ER), Corrientes (CN), Misiones (MN),
      +# Chaco (CC), Formosa (FM), Santiago del Estero (SE)
      +#
      +# Shanks & Pottenger also make the following claims, which we haven't verified:
      +# - Formosa switched to -3:00 on 1991-01-07.
      +# - Misiones switched to -3:00 on 1990-12-29.
      +# - Chaco switched to -3:00 on 1991-01-04.
      +# - Santiago del Estero switched to -4:00 on 1991-04-01,
      +#   then to -3:00 on 1991-04-26.
      +#
      +Zone America/Argentina/Cordoba -4:16:48 - LMT	1894 Oct 31
      +			-4:16:48 -	CMT	1920 May
      +			-4:00	-	ART	1930 Dec
      +			-4:00	Arg	AR%sT	1969 Oct  5
      +			-3:00	Arg	AR%sT	1991 Mar  3
      +			-4:00	-	WART	1991 Oct 20
      +			-3:00	Arg	AR%sT	1999 Oct  3
      +			-4:00	Arg	AR%sT	2000 Mar  3
      +			-3:00	Arg	AR%sT
      +#
      +# Salta (SA), La Pampa (LP), Neuquen (NQ), Rio Negro (RN)
      +Zone America/Argentina/Salta -4:21:40 - LMT	1894 Oct 31
      +			-4:16:48 -	CMT	1920 May
      +			-4:00	-	ART	1930 Dec
      +			-4:00	Arg	AR%sT	1969 Oct  5
      +			-3:00	Arg	AR%sT	1991 Mar  3
      +			-4:00	-	WART	1991 Oct 20
      +			-3:00	Arg	AR%sT	1999 Oct  3
      +			-4:00	Arg	AR%sT	2000 Mar  3
      +			-3:00	Arg	AR%sT	2008 Oct 18
      +			-3:00	-	ART
      +#
      +# Tucuman (TM)
      +Zone America/Argentina/Tucuman -4:20:52 - LMT	1894 Oct 31
      +			-4:16:48 -	CMT	1920 May
      +			-4:00	-	ART	1930 Dec
      +			-4:00	Arg	AR%sT	1969 Oct  5
      +			-3:00	Arg	AR%sT	1991 Mar  3
      +			-4:00	-	WART	1991 Oct 20
      +			-3:00	Arg	AR%sT	1999 Oct  3
      +			-4:00	Arg	AR%sT	2000 Mar  3
      +			-3:00	-	ART	2004 Jun  1
      +			-4:00	-	WART	2004 Jun 13
      +			-3:00	Arg	AR%sT
      +#
      +# La Rioja (LR)
      +Zone America/Argentina/La_Rioja -4:27:24 - LMT	1894 Oct 31
      +			-4:16:48 -	CMT	1920 May
      +			-4:00	-	ART	1930 Dec
      +			-4:00	Arg	AR%sT	1969 Oct  5
      +			-3:00	Arg	AR%sT	1991 Mar  1
      +			-4:00	-	WART	1991 May  7
      +			-3:00	Arg	AR%sT	1999 Oct  3
      +			-4:00	Arg	AR%sT	2000 Mar  3
      +			-3:00	-	ART	2004 Jun  1
      +			-4:00	-	WART	2004 Jun 20
      +			-3:00	Arg	AR%sT	2008 Oct 18
      +			-3:00	-	ART
      +#
      +# San Juan (SJ)
      +Zone America/Argentina/San_Juan -4:34:04 - LMT	1894 Oct 31
      +			-4:16:48 -	CMT	1920 May
      +			-4:00	-	ART	1930 Dec
      +			-4:00	Arg	AR%sT	1969 Oct  5
      +			-3:00	Arg	AR%sT	1991 Mar  1
      +			-4:00	-	WART	1991 May  7
      +			-3:00	Arg	AR%sT	1999 Oct  3
      +			-4:00	Arg	AR%sT	2000 Mar  3
      +			-3:00	-	ART	2004 May 31
      +			-4:00	-	WART	2004 Jul 25
      +			-3:00	Arg	AR%sT	2008 Oct 18
      +			-3:00	-	ART
      +#
      +# Jujuy (JY)
      +Zone America/Argentina/Jujuy -4:21:12 -	LMT	1894 Oct 31
      +			-4:16:48 -	CMT	1920 May
      +			-4:00	-	ART	1930 Dec
      +			-4:00	Arg	AR%sT	1969 Oct  5
      +			-3:00	Arg	AR%sT	1990 Mar  4
      +			-4:00	-	WART	1990 Oct 28
      +			-4:00	1:00	WARST	1991 Mar 17
      +			-4:00	-	WART	1991 Oct  6
      +			-3:00	1:00	ARST	1992
      +			-3:00	Arg	AR%sT	1999 Oct  3
      +			-4:00	Arg	AR%sT	2000 Mar  3
      +			-3:00	Arg	AR%sT	2008 Oct 18
      +			-3:00	-	ART
      +#
      +# Catamarca (CT), Chubut (CH)
      +Zone America/Argentina/Catamarca -4:23:08 - LMT	1894 Oct 31
      +			-4:16:48 -	CMT	1920 May
      +			-4:00	-	ART	1930 Dec
      +			-4:00	Arg	AR%sT	1969 Oct  5
      +			-3:00	Arg	AR%sT	1991 Mar  3
      +			-4:00	-	WART	1991 Oct 20
      +			-3:00	Arg	AR%sT	1999 Oct  3
      +			-4:00	Arg	AR%sT	2000 Mar  3
      +			-3:00	-	ART	2004 Jun  1
      +			-4:00	-	WART	2004 Jun 20
      +			-3:00	Arg	AR%sT	2008 Oct 18
      +			-3:00	-	ART
      +#
      +# Mendoza (MZ)
      +Zone America/Argentina/Mendoza -4:35:16 - LMT	1894 Oct 31
      +			-4:16:48 -	CMT	1920 May
      +			-4:00	-	ART	1930 Dec
      +			-4:00	Arg	AR%sT	1969 Oct  5
      +			-3:00	Arg	AR%sT	1990 Mar  4
      +			-4:00	-	WART	1990 Oct 15
      +			-4:00	1:00	WARST	1991 Mar  1
      +			-4:00	-	WART	1991 Oct 15
      +			-4:00	1:00	WARST	1992 Mar  1
      +			-4:00	-	WART	1992 Oct 18
      +			-3:00	Arg	AR%sT	1999 Oct  3
      +			-4:00	Arg	AR%sT	2000 Mar  3
      +			-3:00	-	ART	2004 May 23
      +			-4:00	-	WART	2004 Sep 26
      +			-3:00	Arg	AR%sT	2008 Oct 18
      +			-3:00	-	ART
      +#
      +# San Luis (SL)
      +
      +Rule	SanLuis	2008	2009	-	Mar	Sun>=8	0:00	0	-
      +Rule	SanLuis	2007	2009	-	Oct	Sun>=8	0:00	1:00	S
      +
      +Zone America/Argentina/San_Luis -4:25:24 - LMT	1894 Oct 31
      +			-4:16:48 -	CMT	1920 May
      +			-4:00	-	ART	1930 Dec
      +			-4:00	Arg	AR%sT	1969 Oct  5
      +			-3:00	Arg	AR%sT	1990
      +			-3:00	1:00	ARST	1990 Mar 14
      +			-4:00	-	WART	1990 Oct 15
      +			-4:00	1:00	WARST	1991 Mar  1
      +			-4:00	-	WART	1991 Jun  1
      +			-3:00	-	ART	1999 Oct  3
      +			-4:00	1:00	WARST	2000 Mar  3
      +			-3:00	-	ART	2004 May 31
      +			-4:00	-	WART	2004 Jul 25
      +			-3:00	Arg	AR%sT	2008 Jan 21
      +			-4:00	SanLuis	WAR%sT
      +#
      +# Santa Cruz (SC)
      +Zone America/Argentina/Rio_Gallegos -4:36:52 - LMT 1894 Oct 31
      +			-4:16:48 -	CMT	1920 May # Cordoba Mean Time
      +			-4:00	-	ART	1930 Dec
      +			-4:00	Arg	AR%sT	1969 Oct  5
      +			-3:00	Arg	AR%sT	1999 Oct  3
      +			-4:00	Arg	AR%sT	2000 Mar  3
      +			-3:00	-	ART	2004 Jun  1
      +			-4:00	-	WART	2004 Jun 20
      +			-3:00	Arg	AR%sT	2008 Oct 18
      +			-3:00	-	ART
      +#
      +# Tierra del Fuego, Antartida e Islas del Atlantico Sur (TF)
      +Zone America/Argentina/Ushuaia -4:33:12 - LMT 1894 Oct 31
      +			-4:16:48 -	CMT	1920 May # Cordoba Mean Time
      +			-4:00	-	ART	1930 Dec
      +			-4:00	Arg	AR%sT	1969 Oct  5
      +			-3:00	Arg	AR%sT	1999 Oct  3
      +			-4:00	Arg	AR%sT	2000 Mar  3
      +			-3:00	-	ART	2004 May 30
      +			-4:00	-	WART	2004 Jun 20
      +			-3:00	Arg	AR%sT	2008 Oct 18
      +			-3:00	-	ART
      +
      +# Aruba
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	America/Aruba	-4:40:24 -	LMT	1912 Feb 12	# Oranjestad
      +			-4:30	-	ANT	1965 # Netherlands Antilles Time
      +			-4:00	-	AST
      +
      +# Bolivia
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	America/La_Paz	-4:32:36 -	LMT	1890
      +			-4:32:36 -	CMT	1931 Oct 15 # Calamarca MT
      +			-4:32:36 1:00	BOST	1932 Mar 21 # Bolivia ST
      +			-4:00	-	BOT	# Bolivia Time
      +
      +# Brazil
      +
      +# From Paul Eggert (1993-11-18):
      +# The mayor of Rio recently attempted to change the time zone rules
      +# just in his city, in order to leave more summer time for the tourist trade.
      +# The rule change lasted only part of the day;
      +# the federal government refused to follow the city's rules, and business
      +# was in a chaos, so the mayor backed down that afternoon.
      +
      +# From IATA SSIM (1996-02):
      +# _Only_ the following states in BR1 observe DST: Rio Grande do Sul (RS),
      +# Santa Catarina (SC), Parana (PR), Sao Paulo (SP), Rio de Janeiro (RJ),
      +# Espirito Santo (ES), Minas Gerais (MG), Bahia (BA), Goias (GO),
      +# Distrito Federal (DF), Tocantins (TO), Sergipe [SE] and Alagoas [AL].
      +# [The last three states are new to this issue of the IATA SSIM.]
      +
      +# From Gwillim Law (1996-10-07):
      +# Geography, history (Tocantins was part of Goias until 1989), and other
      +# sources of time zone information lead me to believe that AL, SE, and TO were
      +# always in BR1, and so the only change was whether or not they observed DST....
      +# The earliest issue of the SSIM I have is 2/91.  Each issue from then until
      +# 9/95 says that DST is observed only in the ten states I quoted from 9/95,
      +# along with Mato Grosso (MT) and Mato Grosso do Sul (MS), which are in BR2
      +# (UTC-4)....  The other two time zones given for Brazil are BR3, which is
      +# UTC-5, no DST, and applies only in the state of Acre (AC); and BR4, which is
      +# UTC-2, and applies to Fernando de Noronha (formerly FN, but I believe it's
      +# become part of the state of Pernambuco).  The boundary between BR1 and BR2
      +# has never been clearly stated.  They've simply been called East and West.
      +# However, some conclusions can be drawn from another IATA manual: the Airline
      +# Coding Directory, which lists close to 400 airports in Brazil.  For each
      +# airport it gives a time zone which is coded to the SSIM.  From that
      +# information, I'm led to conclude that the states of Amapa (AP), Ceara (CE),
      +# Maranhao (MA), Paraiba (PR), Pernambuco (PE), Piaui (PI), and Rio Grande do
      +# Norte (RN), and the eastern part of Para (PA) are all in BR1 without DST.
      +
      +# From Marcos Tadeu (1998-09-27):
      +# 
      +# Brazilian official page
      +# 
      +
      +# From Jesper Norgaard (2000-11-03):
      +# [For an official list of which regions in Brazil use which time zones, see:]
      +# http://pcdsh01.on.br/Fusbr.htm
      +# http://pcdsh01.on.br/Fusbrhv.htm
      +
      +# From Celso Doria via David Madeo (2002-10-09):
      +# The reason for the delay this year has to do with elections in Brazil.
      +#
      +# Unlike in the United States, elections in Brazil are 100% computerized and
      +# the results are known almost immediately.  Yesterday, it was the first
      +# round of the elections when 115 million Brazilians voted for President,
      +# Governor, Senators, Federal Deputies, and State Deputies.  Nobody is
      +# counting (or re-counting) votes anymore and we know there will be a second
      +# round for the Presidency and also for some Governors.  The 2nd round will
      +# take place on October 27th.
      +#
      +# The reason why the DST will only begin November 3rd is that the thousands
      +# of electoral machines used cannot have their time changed, and since the
      +# Constitution says the elections must begin at 8:00 AM and end at 5:00 PM,
      +# the Government decided to postpone DST, instead of changing the Constitution
      +# (maybe, for the next elections, it will be possible to change the clock)...
      +
      +# From Rodrigo Severo (2004-10-04):
      +# It's just the biannual change made necessary by the much hyped, supposedly
      +# modern Brazilian eletronic voting machines which, apparently, can't deal
      +# with a time change between the first and the second rounds of the elections.
      +
      +# From Steffen Thorsen (2007-09-20):
      +# Brazil will start DST on 2007-10-14 00:00 and end on 2008-02-17 00:00:
      +# http://www.mme.gov.br/site/news/detail.do;jsessionid=BBA06811AFCAAC28F0285210913513DA?newsId=13975
      +
      +# From Paul Schulze (2008-06-24):
      +# ...by law number 11.662 of April 24, 2008 (published in the "Diario
      +# Oficial da Uniao"...) in Brazil there are changes in the timezones,
      +# effective today (00:00am at June 24, 2008) as follows:
      +#
      +# a) The timezone UTC+5 is e[x]tinguished, with all the Acre state and the
      +# part of the Amazonas state that had this timezone now being put to the
      +# timezone UTC+4
      +# b) The whole Para state now is put at timezone UTC+3, instead of just
      +# part of it, as was before.
      +#
      +# This change follows a proposal of senator Tiao Viana of Acre state, that
      +# proposed it due to concerns about open television channels displaying
      +# programs inappropriate to youths in the states that had the timezone
      +# UTC+5 too early in the night. In the occasion, some more corrections
      +# were proposed, trying to unify the timezones of any given state. This
      +# change modifies timezone rules defined in decree 2.784 of 18 June,
      +# 1913.
      +
      +# From Rodrigo Severo (2008-06-24):
      +# Just correcting the URL:
      +# 
      +# https://www.in.gov.br/imprensa/visualiza/index.jsp?jornal=do&secao=1&pagina=1&data=25/04/2008
      +# 
      +#
      +# As a result of the above Decree I believe the America/Rio_Branco
      +# timezone shall be modified from UTC-5 to UTC-4 and a new timezone shall
      +# be created to represent the...west side of the Para State. I
      +# suggest this new timezone be called Santarem as the most
      +# important/populated city in the affected area.
      +#
      +# This new timezone would be the same as the Rio_Branco timezone up to
      +# the 2008/06/24 change which would be to UTC-3 instead of UTC-4.
      +
      +# From Alex Krivenyshev (2008-06-24):
      +# This is a quick reference page for New and Old Brazil Time Zones map.
      +# 
      +# http://www.worldtimezone.com/brazil-time-new-old.php
      +# 
      +#
      +# - 4 time zones replaced by 3 time zones-eliminating time zone UTC- 05
      +# (state Acre and the part of the Amazonas will be UTC/GMT- 04) - western
      +# part of Par state is moving to one timezone UTC- 03 (from UTC -04).
      +
      +# From Paul Eggert (2002-10-10):
      +# The official decrees referenced below are mostly taken from
      +# 
      +# Decretos sobre o Horario de Verao no Brasil
      +# .
      +
      +# From Steffen Thorsen (2008-08-29):
      +# As announced by the government and many newspapers in Brazil late
      +# yesterday, Brazil will start DST on 2008-10-19 (need to change rule) and
      +# it will end on 2009-02-15 (current rule for Brazil is fine). Based on
      +# past years experience with the elections, there was a good chance that
      +# the start was postponed to November, but it did not happen this year.
      +#
      +# It has not yet been posted to http://pcdsh01.on.br/DecHV.html
      +#
      +# An official page about it:
      +# 
      +# http://www.mme.gov.br/site/news/detail.do?newsId=16722
      +# 
      +# Note that this link does not always work directly, but must be accessed
      +# by going to
      +# 
      +# http://www.mme.gov.br/first
      +# 
      +#
      +# One example link that works directly:
      +# 
      +# http://jornale.com.br/index.php?option=com_content&task=view&id=13530&Itemid=54
      +# (Portuguese)
      +# 
      +#
      +# We have a written a short article about it as well:
      +# 
      +# http://www.timeanddate.com/news/time/brazil-dst-2008-2009.html
      +# 
      +#
      +# From Alexander Krivenyshev (2011-10-04):
      +# State Bahia will return to Daylight savings time this year after 8 years off.
      +# The announcement was made by Governor Jaques Wagner in an interview to a
      +# television station in Salvador.
      +
      +# In Portuguese:
      +# 
      +# http://g1.globo.com/bahia/noticia/2011/10/governador-jaques-wagner-confirma-horario-de-verao-na-bahia.html
      +#  and
      +# 
      +# http://noticias.terra.com.br/brasil/noticias/0,,OI5390887-EI8139,00-Bahia+volta+a+ter+horario+de+verao+apos+oito+anos.html
      +# 
      +
      +# From Guilherme Bernardes Rodrigues (2011-10-07):
      +# There is news in the media, however there is still no decree about it.
      +# I just send a e-mail to Zulmira Brandão at
      +# http://pcdsh01.on.br/ the
      +# oficial agency about time in Brazil, and she confirmed that the old rule is
      +# still in force.
      +
      +# From Guilherme Bernardes Rodrigues (2011-10-14)
      +# It's official, the President signed a decree that includes Bahia in summer
      +# time.
      +#	 [ and in a second message (same day): ]
      +# I found the decree.
      +#
      +# DECRETO No- 7.584, DE 13 DE OUTUBRO DE 2011
      +# Link :
      +# 
      +# http://www.in.gov.br/visualiza/index.jsp?data=13/10/2011&jornal=1000&pagina=6&totalArquivos=6
      +# 
      +
      +# From Kelley Cook (2012-10-16):
      +# The governor of state of Bahia in Brazil announced on Thursday that
      +# due to public pressure, he is reversing the DST policy they implemented
      +# last year and will not be going to Summer Time on October 21st....
      +# http://www.correio24horas.com.br/r/artigo/apos-pressoes-wagner-suspende-horario-de-verao-na-bahia
      +
      +# From Rodrigo Severo (2012-10-16):
      +# Tocantins state will have DST.
      +# http://noticias.terra.com.br/brasil/noticias/0,,OI6232536-EI306.html
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +# Decree 20,466 (1931-10-01)
      +# Decree 21,896 (1932-01-10)
      +Rule	Brazil	1931	only	-	Oct	 3	11:00	1:00	S
      +Rule	Brazil	1932	1933	-	Apr	 1	 0:00	0	-
      +Rule	Brazil	1932	only	-	Oct	 3	 0:00	1:00	S
      +# Decree 23,195 (1933-10-10)
      +# revoked DST.
      +# Decree 27,496 (1949-11-24)
      +# Decree 27,998 (1950-04-13)
      +Rule	Brazil	1949	1952	-	Dec	 1	 0:00	1:00	S
      +Rule	Brazil	1950	only	-	Apr	16	 1:00	0	-
      +Rule	Brazil	1951	1952	-	Apr	 1	 0:00	0	-
      +# Decree 32,308 (1953-02-24)
      +Rule	Brazil	1953	only	-	Mar	 1	 0:00	0	-
      +# Decree 34,724 (1953-11-30)
      +# revoked DST.
      +# Decree 52,700 (1963-10-18)
      +# established DST from 1963-10-23 00:00 to 1964-02-29 00:00
      +# in SP, RJ, GB, MG, ES, due to the prolongation of the drought.
      +# Decree 53,071 (1963-12-03)
      +# extended the above decree to all of the national territory on 12-09.
      +Rule	Brazil	1963	only	-	Dec	 9	 0:00	1:00	S
      +# Decree 53,604 (1964-02-25)
      +# extended summer time by one day to 1964-03-01 00:00 (start of school).
      +Rule	Brazil	1964	only	-	Mar	 1	 0:00	0	-
      +# Decree 55,639 (1965-01-27)
      +Rule	Brazil	1965	only	-	Jan	31	 0:00	1:00	S
      +Rule	Brazil	1965	only	-	Mar	31	 0:00	0	-
      +# Decree 57,303 (1965-11-22)
      +Rule	Brazil	1965	only	-	Dec	 1	 0:00	1:00	S
      +# Decree 57,843 (1966-02-18)
      +Rule	Brazil	1966	1968	-	Mar	 1	 0:00	0	-
      +Rule	Brazil	1966	1967	-	Nov	 1	 0:00	1:00	S
      +# Decree 63,429 (1968-10-15)
      +# revoked DST.
      +# Decree 91,698 (1985-09-27)
      +Rule	Brazil	1985	only	-	Nov	 2	 0:00	1:00	S
      +# Decree 92,310 (1986-01-21)
      +# Decree 92,463 (1986-03-13)
      +Rule	Brazil	1986	only	-	Mar	15	 0:00	0	-
      +# Decree 93,316 (1986-10-01)
      +Rule	Brazil	1986	only	-	Oct	25	 0:00	1:00	S
      +Rule	Brazil	1987	only	-	Feb	14	 0:00	0	-
      +# Decree 94,922 (1987-09-22)
      +Rule	Brazil	1987	only	-	Oct	25	 0:00	1:00	S
      +Rule	Brazil	1988	only	-	Feb	 7	 0:00	0	-
      +# Decree 96,676 (1988-09-12)
      +# except for the states of AC, AM, PA, RR, RO, and AP (then a territory)
      +Rule	Brazil	1988	only	-	Oct	16	 0:00	1:00	S
      +Rule	Brazil	1989	only	-	Jan	29	 0:00	0	-
      +# Decree 98,077 (1989-08-21)
      +# with the same exceptions
      +Rule	Brazil	1989	only	-	Oct	15	 0:00	1:00	S
      +Rule	Brazil	1990	only	-	Feb	11	 0:00	0	-
      +# Decree 99,530 (1990-09-17)
      +# adopted by RS, SC, PR, SP, RJ, ES, MG, GO, MS, DF.
      +# Decree 99,629 (1990-10-19) adds BA, MT.
      +Rule	Brazil	1990	only	-	Oct	21	 0:00	1:00	S
      +Rule	Brazil	1991	only	-	Feb	17	 0:00	0	-
      +# Unnumbered decree (1991-09-25)
      +# adopted by RS, SC, PR, SP, RJ, ES, MG, BA, GO, MT, MS, DF.
      +Rule	Brazil	1991	only	-	Oct	20	 0:00	1:00	S
      +Rule	Brazil	1992	only	-	Feb	 9	 0:00	0	-
      +# Unnumbered decree (1992-10-16)
      +# adopted by same states.
      +Rule	Brazil	1992	only	-	Oct	25	 0:00	1:00	S
      +Rule	Brazil	1993	only	-	Jan	31	 0:00	0	-
      +# Decree 942 (1993-09-28)
      +# adopted by same states, plus AM.
      +# Decree 1,252 (1994-09-22;
      +# web page corrected 2004-01-07) adopted by same states, minus AM.
      +# Decree 1,636 (1995-09-14)
      +# adopted by same states, plus MT and TO.
      +# Decree 1,674 (1995-10-13)
      +# adds AL, SE.
      +Rule	Brazil	1993	1995	-	Oct	Sun>=11	 0:00	1:00	S
      +Rule	Brazil	1994	1995	-	Feb	Sun>=15	 0:00	0	-
      +Rule	Brazil	1996	only	-	Feb	11	 0:00	0	-
      +# Decree 2,000 (1996-09-04)
      +# adopted by same states, minus AL, SE.
      +Rule	Brazil	1996	only	-	Oct	 6	 0:00	1:00	S
      +Rule	Brazil	1997	only	-	Feb	16	 0:00	0	-
      +# From Daniel C. Sobral (1998-02-12):
      +# In 1997, the DS began on October 6. The stated reason was that
      +# because international television networks ignored Brazil's policy on DS,
      +# they bought the wrong times on satellite for coverage of Pope's visit.
      +# This year, the ending date of DS was postponed to March 1
      +# to help dealing with the shortages of electric power.
      +#
      +# Decree 2,317 (1997-09-04), adopted by same states.
      +Rule	Brazil	1997	only	-	Oct	 6	 0:00	1:00	S
      +# Decree 2,495
      +# (1998-02-10)
      +Rule	Brazil	1998	only	-	Mar	 1	 0:00	0	-
      +# Decree 2,780 (1998-09-11)
      +# adopted by the same states as before.
      +Rule	Brazil	1998	only	-	Oct	11	 0:00	1:00	S
      +Rule	Brazil	1999	only	-	Feb	21	 0:00	0	-
      +# Decree 3,150
      +# (1999-08-23) adopted by same states.
      +# Decree 3,188 (1999-09-30)
      +# adds SE, AL, PB, PE, RN, CE, PI, MA and RR.
      +Rule	Brazil	1999	only	-	Oct	 3	 0:00	1:00	S
      +Rule	Brazil	2000	only	-	Feb	27	 0:00	0	-
      +# Decree 3,592 (2000-09-06)
      +# adopted by the same states as before.
      +# Decree 3,630 (2000-10-13)
      +# repeals DST in PE and RR, effective 2000-10-15 00:00.
      +# Decree 3,632 (2000-10-17)
      +# repeals DST in SE, AL, PB, RN, CE, PI and MA, effective 2000-10-22 00:00.
      +# Decree 3,916
      +# (2001-09-13) reestablishes DST in AL, CE, MA, PB, PE, PI, RN, SE.
      +Rule	Brazil	2000	2001	-	Oct	Sun>=8	 0:00	1:00	S
      +Rule	Brazil	2001	2006	-	Feb	Sun>=15	 0:00	0	-
      +# Decree 4,399 (2002-10-01) repeals DST in AL, CE, MA, PB, PE, PI, RN, SE.
      +# 4,399
      +Rule	Brazil	2002	only	-	Nov	 3	 0:00	1:00	S
      +# Decree 4,844 (2003-09-24; corrected 2003-09-26) repeals DST in BA, MT, TO.
      +# 4,844
      +Rule	Brazil	2003	only	-	Oct	19	 0:00	1:00	S
      +# Decree 5,223 (2004-10-01) reestablishes DST in MT.
      +# 5,223
      +Rule	Brazil	2004	only	-	Nov	 2	 0:00	1:00	S
      +# Decree 5,539 (2005-09-19),
      +# adopted by the same states as before.
      +Rule	Brazil	2005	only	-	Oct	16	 0:00	1:00	S
      +# Decree 5,920 (2006-10-03),
      +# adopted by the same states as before.
      +Rule	Brazil	2006	only	-	Nov	 5	 0:00	1:00	S
      +Rule	Brazil	2007	only	-	Feb	25	 0:00	0	-
      +# Decree 6,212 (2007-09-26),
      +# adopted by the same states as before.
      +Rule	Brazil	2007	only	-	Oct	Sun>=8	 0:00	1:00	S
      +# From Frederico A. C. Neves (2008-09-10):
      +# Acording to this decree
      +# 
      +# http://www.planalto.gov.br/ccivil_03/_Ato2007-2010/2008/Decreto/D6558.htm
      +# 
      +# [t]he DST period in Brazil now on will be from the 3rd Oct Sunday to the
      +# 3rd Feb Sunday. There is an exception on the return date when this is
      +# the Carnival Sunday then the return date will be the next Sunday...
      +Rule	Brazil	2008	max	-	Oct	Sun>=15	0:00	1:00	S
      +Rule	Brazil	2008	2011	-	Feb	Sun>=15	0:00	0	-
      +Rule	Brazil	2012	only	-	Feb	Sun>=22	0:00	0	-
      +Rule	Brazil	2013	2014	-	Feb	Sun>=15	0:00	0	-
      +Rule	Brazil	2015	only	-	Feb	Sun>=22	0:00	0	-
      +Rule	Brazil	2016	2022	-	Feb	Sun>=15	0:00	0	-
      +Rule	Brazil	2023	only	-	Feb	Sun>=22	0:00	0	-
      +Rule	Brazil	2024	2025	-	Feb	Sun>=15	0:00	0	-
      +Rule	Brazil	2026	only	-	Feb	Sun>=22	0:00	0	-
      +Rule	Brazil	2027	2033	-	Feb	Sun>=15	0:00	0	-
      +Rule	Brazil	2034	only	-	Feb	Sun>=22	0:00	0	-
      +Rule	Brazil	2035	2036	-	Feb	Sun>=15	0:00	0	-
      +Rule	Brazil	2037	only	-	Feb	Sun>=22	0:00	0	-
      +# From Arthur David Olson (2008-09-29):
      +# The next is wrong in some years but is better than nothing.
      +Rule	Brazil	2038	max	-	Feb	Sun>=15	0:00	0	-
      +
      +# The latest ruleset listed above says that the following states observe DST:
      +# DF, ES, GO, MG, MS, MT, PR, RJ, RS, SC, SP.
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +#
      +# Fernando de Noronha (administratively part of PE)
      +Zone America/Noronha	-2:09:40 -	LMT	1914
      +			-2:00	Brazil	FN%sT	1990 Sep 17
      +			-2:00	-	FNT	1999 Sep 30
      +			-2:00	Brazil	FN%sT	2000 Oct 15
      +			-2:00	-	FNT	2001 Sep 13
      +			-2:00	Brazil	FN%sT	2002 Oct  1
      +			-2:00	-	FNT
      +# Other Atlantic islands have no permanent settlement.
      +# These include Trindade and Martin Vaz (administratively part of ES),
      +# Atol das Rocas (RN), and Penedos de Sao Pedro e Sao Paulo (PE).
      +# Fernando de Noronha was a separate territory from 1942-09-02 to 1989-01-01;
      +# it also included the Penedos.
      +#
      +# Amapa (AP), east Para (PA)
      +# East Para includes Belem, Maraba, Serra Norte, and Sao Felix do Xingu.
      +# The division between east and west Para is the river Xingu.
      +# In the north a very small part from the river Javary (now Jari I guess,
      +# the border with Amapa) to the Amazon, then to the Xingu.
      +Zone America/Belem	-3:13:56 -	LMT	1914
      +			-3:00	Brazil	BR%sT	1988 Sep 12
      +			-3:00	-	BRT
      +#
      +# west Para (PA)
      +# West Para includes Altamira, Oribidos, Prainha, Oriximina, and Santarem.
      +Zone America/Santarem	-3:38:48 -	LMT	1914
      +			-4:00	Brazil	AM%sT	1988 Sep 12
      +			-4:00	-	AMT	2008 Jun 24 00:00
      +			-3:00	-	BRT
      +#
      +# Maranhao (MA), Piaui (PI), Ceara (CE), Rio Grande do Norte (RN),
      +# Paraiba (PB)
      +Zone America/Fortaleza	-2:34:00 -	LMT	1914
      +			-3:00	Brazil	BR%sT	1990 Sep 17
      +			-3:00	-	BRT	1999 Sep 30
      +			-3:00	Brazil	BR%sT	2000 Oct 22
      +			-3:00	-	BRT	2001 Sep 13
      +			-3:00	Brazil	BR%sT	2002 Oct  1
      +			-3:00	-	BRT
      +#
      +# Pernambuco (PE) (except Atlantic islands)
      +Zone America/Recife	-2:19:36 -	LMT	1914
      +			-3:00	Brazil	BR%sT	1990 Sep 17
      +			-3:00	-	BRT	1999 Sep 30
      +			-3:00	Brazil	BR%sT	2000 Oct 15
      +			-3:00	-	BRT	2001 Sep 13
      +			-3:00	Brazil	BR%sT	2002 Oct  1
      +			-3:00	-	BRT
      +#
      +# Tocantins (TO)
      +Zone America/Araguaina	-3:12:48 -	LMT	1914
      +			-3:00	Brazil	BR%sT	1990 Sep 17
      +			-3:00	-	BRT	1995 Sep 14
      +			-3:00	Brazil	BR%sT	2003 Sep 24
      +			-3:00	-	BRT	2012 Oct 21
      +			-3:00	Brazil	BR%sT
      +#
      +# Alagoas (AL), Sergipe (SE)
      +Zone America/Maceio	-2:22:52 -	LMT	1914
      +			-3:00	Brazil	BR%sT	1990 Sep 17
      +			-3:00	-	BRT	1995 Oct 13
      +			-3:00	Brazil	BR%sT	1996 Sep  4
      +			-3:00	-	BRT	1999 Sep 30
      +			-3:00	Brazil	BR%sT	2000 Oct 22
      +			-3:00	-	BRT	2001 Sep 13
      +			-3:00	Brazil	BR%sT	2002 Oct  1
      +			-3:00	-	BRT
      +#
      +# Bahia (BA)
      +# There are too many Salvadors elsewhere, so use America/Bahia instead
      +# of America/Salvador.
      +Zone America/Bahia	-2:34:04 -	LMT	1914
      +			-3:00	Brazil	BR%sT	2003 Sep 24
      +			-3:00	-	BRT	2011 Oct 16
      +			-3:00	Brazil	BR%sT	2012 Oct 21
      +			-3:00	-	BRT
      +#
      +# Goias (GO), Distrito Federal (DF), Minas Gerais (MG),
      +# Espirito Santo (ES), Rio de Janeiro (RJ), Sao Paulo (SP), Parana (PR),
      +# Santa Catarina (SC), Rio Grande do Sul (RS)
      +Zone America/Sao_Paulo	-3:06:28 -	LMT	1914
      +			-3:00	Brazil	BR%sT	1963 Oct 23 00:00
      +			-3:00	1:00	BRST	1964
      +			-3:00	Brazil	BR%sT
      +#
      +# Mato Grosso do Sul (MS)
      +Zone America/Campo_Grande -3:38:28 -	LMT	1914
      +			-4:00	Brazil	AM%sT
      +#
      +# Mato Grosso (MT)
      +Zone America/Cuiaba	-3:44:20 -	LMT	1914
      +			-4:00	Brazil	AM%sT	2003 Sep 24
      +			-4:00	-	AMT	2004 Oct  1
      +			-4:00	Brazil	AM%sT
      +#
      +# Rondonia (RO)
      +Zone America/Porto_Velho -4:15:36 -	LMT	1914
      +			-4:00	Brazil	AM%sT	1988 Sep 12
      +			-4:00	-	AMT
      +#
      +# Roraima (RR)
      +Zone America/Boa_Vista	-4:02:40 -	LMT	1914
      +			-4:00	Brazil	AM%sT	1988 Sep 12
      +			-4:00	-	AMT	1999 Sep 30
      +			-4:00	Brazil	AM%sT	2000 Oct 15
      +			-4:00	-	AMT
      +#
      +# east Amazonas (AM): Boca do Acre, Jutai, Manaus, Floriano Peixoto
      +# The great circle line from Tabatinga to Porto Acre divides
      +# east from west Amazonas.
      +Zone America/Manaus	-4:00:04 -	LMT	1914
      +			-4:00	Brazil	AM%sT	1988 Sep 12
      +			-4:00	-	AMT	1993 Sep 28
      +			-4:00	Brazil	AM%sT	1994 Sep 22
      +			-4:00	-	AMT
      +#
      +# west Amazonas (AM): Atalaia do Norte, Boca do Maoco, Benjamin Constant,
      +#	Eirunepe, Envira, Ipixuna
      +Zone America/Eirunepe	-4:39:28 -	LMT	1914
      +			-5:00	Brazil	AC%sT	1988 Sep 12
      +			-5:00	-	ACT	1993 Sep 28
      +			-5:00	Brazil	AC%sT	1994 Sep 22
      +			-5:00	-	ACT	2008 Jun 24 00:00
      +			-4:00	-	AMT
      +#
      +# Acre (AC)
      +Zone America/Rio_Branco	-4:31:12 -	LMT	1914
      +			-5:00	Brazil	AC%sT	1988 Sep 12
      +			-5:00	-	ACT	2008 Jun 24 00:00
      +			-4:00	-	AMT
      +
      +# Chile
      +
      +# From Eduardo Krell (1995-10-19):
      +# The law says to switch to DST at midnight [24:00] on the second SATURDAY
      +# of October....  The law is the same for March and October.
      +# (1998-09-29):
      +# Because of the drought this year, the government decided to go into
      +# DST earlier (saturday 9/26 at 24:00). This is a one-time change only ...
      +# (unless there's another dry season next year, I guess).
      +
      +# From Julio I. Pacheco Troncoso (1999-03-18):
      +# Because of the same drought, the government decided to end DST later,
      +# on April 3, (one-time change).
      +
      +# From Oscar van Vlijmen (2006-10-08):
      +# http://www.horaoficial.cl/cambio.htm
      +
      +# From Jesper Norgaard Welen (2006-10-08):
      +# I think that there are some obvious mistakes in the suggested link
      +# from Oscar van Vlijmen,... for instance entry 66 says that GMT-4
      +# ended 1990-09-12 while entry 67 only begins GMT-3 at 1990-09-15
      +# (they should have been 1990-09-15 and 1990-09-16 respectively), but
      +# anyhow it clears up some doubts too.
      +
      +# From Paul Eggert (2006-12-27):
      +# The following data for Chile and America/Santiago are from
      +#  (2006-09-20), transcribed by
      +# Jesper Norgaard Welen.  The data for Pacific/Easter are from Shanks
      +# & Pottenger, except with DST transitions after 1932 cloned from
      +# America/Santiago.  The pre-1980 Pacific/Easter data are dubious,
      +# but we have no other source.
      +
      +# From German Poo-Caaman~o (2008-03-03):
      +# Due to drought, Chile extends Daylight Time in three weeks.  This
      +# is one-time change (Saturday 3/29 at 24:00 for America/Santiago
      +# and Saturday 3/29 at 22:00 for Pacific/Easter)
      +# The Supreme Decree is located at
      +# 
      +# http://www.shoa.cl/servicios/supremo316.pdf
      +# 
      +# and the instructions for 2008 are located in:
      +# 
      +# http://www.horaoficial.cl/cambio.htm
      +# .
      +
      +# From Jose Miguel Garrido (2008-03-05):
      +# ...
      +# You could see the announces of the change on
      +# 
      +# http://www.shoa.cl/noticias/2008/04hora/hora.htm
      +# .
      +
      +# From Angel Chiang (2010-03-04):
      +# Subject: DST in Chile exceptionally extended to 3 April due to earthquake
      +# 
      +# http://www.gobiernodechile.cl/viewNoticia.aspx?idArticulo=30098
      +# 
      +# (in Spanish, last paragraph).
      +#
      +# This is breaking news. There should be more information available later.
      +
      +# From Arthur Daivd Olson (2010-03-06):
      +# Angel Chiang's message confirmed by Julio Pacheco; Julio provided a patch.
      +
      +# From Glenn Eychaner (2011-03-02): [geychaner@mac.com]
      +# It appears that the Chilean government has decided to postpone the
      +# change from summer time to winter time again, by three weeks to April
      +# 2nd:
      +# 
      +# http://www.emol.com/noticias/nacional/detalle/detallenoticias.asp?idnoticia=467651
      +# 
      +#
      +# This is not yet reflected in the offical "cambio de hora" site, but
      +# probably will be soon:
      +# 
      +# http://www.horaoficial.cl/cambio.htm
      +# 
      +
      +# From Arthur David Olson (2011-03-02):
      +# The emol.com article mentions a water shortage as the cause of the
      +# postponement, which may mean that it's not a permanent change.
      +
      +# From Glenn Eychaner (2011-03-28):
      +# The article:
      +# 
      +# http://diario.elmercurio.com/2011/03/28/_portada/_portada/noticias/7565897A-CA86-49E6-9E03-660B21A4883E.htm?id=3D{7565897A-CA86-49E6-9E03-660B21A4883E}
      +# 
      +#
      +# In English:
      +# Chile's clocks will go back an hour this year on the 7th of May instead
      +# of this Saturday. They will go forward again the 3rd Saturday in
      +# August, not in October as they have since 1968. This is a pilot plan
      +# which will be reevaluated in 2012.
      +
      +# From Mauricio Parada (2012-02-22), translated by Glenn Eychaner (2012-02-23):
      +# As stated in the website of the Chilean Energy Ministry
      +# http://www.minenergia.cl/ministerio/noticias/generales/gobierno-anuncia-fechas-de-cambio-de.html
      +# The Chilean Government has decided to postpone the entrance into winter time
      +# (to leave DST) from March 11 2012 to April 28th 2012. The decision has not
      +# been yet formalized but it will within the next days.
      +# Quote from the website communication:
      +#
      +# 6. For the year 2012, the dates of entry into winter time will be as follows:
      +# a. Saturday April 28, 2012, clocks should go back 60 minutes; that is, at
      +# 23:59:59, instead of passing to 0:00, the time should be adjusted to be 23:00
      +# of the same day.
      +# b. Saturday, September 1, 2012, clocks should go forward 60 minutes; that is,
      +# at 23:59:59, instead of passing to 0:00, the time should be adjusted to be
      +# 01:00 on September 2.
      +#
      +# Note that...this is yet another "temporary" change that will be reevaluated
      +# AGAIN in 2013.
      +
      +# NOTE: ChileAQ rules for Antarctic bases are stored separately in the
      +# 'antarctica' file.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Chile	1927	1932	-	Sep	 1	0:00	1:00	S
      +Rule	Chile	1928	1932	-	Apr	 1	0:00	0	-
      +Rule	Chile	1942	only	-	Jun	 1	4:00u	0	-
      +Rule	Chile	1942	only	-	Aug	 1	5:00u	1:00	S
      +Rule	Chile	1946	only	-	Jul	15	4:00u	1:00	S
      +Rule	Chile	1946	only	-	Sep	 1	3:00u	0:00	-
      +Rule	Chile	1947	only	-	Apr	 1	4:00u	0	-
      +Rule	Chile	1968	only	-	Nov	 3	4:00u	1:00	S
      +Rule	Chile	1969	only	-	Mar	30	3:00u	0	-
      +Rule	Chile	1969	only	-	Nov	23	4:00u	1:00	S
      +Rule	Chile	1970	only	-	Mar	29	3:00u	0	-
      +Rule	Chile	1971	only	-	Mar	14	3:00u	0	-
      +Rule	Chile	1970	1972	-	Oct	Sun>=9	4:00u	1:00	S
      +Rule	Chile	1972	1986	-	Mar	Sun>=9	3:00u	0	-
      +Rule	Chile	1973	only	-	Sep	30	4:00u	1:00	S
      +Rule	Chile	1974	1987	-	Oct	Sun>=9	4:00u	1:00	S
      +Rule	Chile	1987	only	-	Apr	12	3:00u	0	-
      +Rule	Chile	1988	1989	-	Mar	Sun>=9	3:00u	0	-
      +Rule	Chile	1988	only	-	Oct	Sun>=1	4:00u	1:00	S
      +Rule	Chile	1989	only	-	Oct	Sun>=9	4:00u	1:00	S
      +Rule	Chile	1990	only	-	Mar	18	3:00u	0	-
      +Rule	Chile	1990	only	-	Sep	16	4:00u	1:00	S
      +Rule	Chile	1991	1996	-	Mar	Sun>=9	3:00u	0	-
      +Rule	Chile	1991	1997	-	Oct	Sun>=9	4:00u	1:00	S
      +Rule	Chile	1997	only	-	Mar	30	3:00u	0	-
      +Rule	Chile	1998	only	-	Mar	Sun>=9	3:00u	0	-
      +Rule	Chile	1998	only	-	Sep	27	4:00u	1:00	S
      +Rule	Chile	1999	only	-	Apr	 4	3:00u	0	-
      +Rule	Chile	1999	2010	-	Oct	Sun>=9	4:00u	1:00	S
      +Rule	Chile	2000	2007	-	Mar	Sun>=9	3:00u	0	-
      +# N.B.: the end of March 29 in Chile is March 30 in Universal time,
      +# which is used below in specifying the transition.
      +Rule	Chile	2008	only	-	Mar	30	3:00u	0	-
      +Rule	Chile	2009	only	-	Mar	Sun>=9	3:00u	0	-
      +Rule	Chile	2010	only	-	Apr	Sun>=1	3:00u	0	-
      +Rule	Chile	2011	only	-	May	Sun>=2	3:00u	0	-
      +Rule	Chile	2011	only	-	Aug	Sun>=16	4:00u	1:00	S
      +Rule	Chile	2012	only	-	Apr	Sun>=23	3:00u	0	-
      +Rule	Chile	2012	only	-	Sep	Sun>=2	4:00u	1:00	S
      +Rule	Chile	2013	max	-	Mar	Sun>=9	3:00u	0	-
      +Rule	Chile	2013	max	-	Oct	Sun>=9	4:00u	1:00	S
      +# IATA SSIM anomalies: (1992-02) says 1992-03-14;
      +# (1996-09) says 1998-03-08.  Ignore these.
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Santiago	-4:42:46 -	LMT	1890
      +			-4:42:46 -	SMT	1910 	    # Santiago Mean Time
      +			-5:00	-	CLT	1916 Jul  1 # Chile Time
      +			-4:42:46 -	SMT	1918 Sep  1 # Santiago Mean Time
      +			-4:00	-	CLT	1919 Jul  1 # Chile Time
      +			-4:42:46 -	SMT	1927 Sep  1 # Santiago Mean Time
      +			-5:00	Chile	CL%sT	1947 May 22 # Chile Time
      +			-4:00	Chile	CL%sT
      +Zone Pacific/Easter	-7:17:44 -	LMT	1890
      +			-7:17:28 -	EMT	1932 Sep    # Easter Mean Time
      +			-7:00	Chile	EAS%sT	1982 Mar 13 21:00 # Easter I Time
      +			-6:00	Chile	EAS%sT
      +#
      +# Sala y Gomez Island is like Pacific/Easter.
      +# Other Chilean locations, including Juan Fernandez Is, San Ambrosio,
      +# San Felix, and Antarctic bases, are like America/Santiago.
      +
      +# Colombia
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	CO	1992	only	-	May	 3	0:00	1:00	S
      +Rule	CO	1993	only	-	Apr	 4	0:00	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	America/Bogota	-4:56:20 -	LMT	1884 Mar 13
      +			-4:56:20 -	BMT	1914 Nov 23 # Bogota Mean Time
      +			-5:00	CO	CO%sT	# Colombia Time
      +# Malpelo, Providencia, San Andres
      +# no information; probably like America/Bogota
      +
      +# Curacao
      +#
      +# From Paul Eggert (2006-03-22):
      +# Shanks & Pottenger say that The Bottom and Philipsburg have been at
      +# -4:00 since standard time was introduced on 1912-03-02; and that
      +# Kralendijk and Rincon used Kralendijk Mean Time (-4:33:08) from
      +# 1912-02-02 to 1965-01-01.  The former is dubious, since S&P also say
      +# Saba Island has been like Curacao.
      +# This all predates our 1970 cutoff, though.
      +#
      +# By July 2007 Curacao and St Maarten are planned to become
      +# associated states within the Netherlands, much like Aruba;
      +# Bonaire, Saba and St Eustatius would become directly part of the
      +# Netherlands as Kingdom Islands.  This won't affect their time zones
      +# though, as far as we know.
      +#
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	America/Curacao	-4:35:44 -	LMT	1912 Feb 12	# Willemstad
      +			-4:30	-	ANT	1965 # Netherlands Antilles Time
      +			-4:00	-	AST
      +
      +# From Arthur David Olson (2011-06-15):
      +# At least for now, use links for places with new iso3166 codes.
      +# The name "Lower Prince's Quarter" is both longer than fourteen charaters
      +# and contains an apostrophe; use "Lower_Princes" below.
      +
      +Link	America/Curacao	America/Lower_Princes # Sint Maarten
      +Link	America/Curacao	America/Kralendijk # Bonaire, Sint Estatius and Saba
      +
      +# Ecuador
      +#
      +# From Paul Eggert (2007-03-04):
      +# Apparently Ecuador had a failed experiment with DST in 1992.
      +#  (2007-02-27) and
      +#  (2006-11-06) both
      +# talk about "hora Sixto".  Leave this alone for now, as we have no data.
      +#
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Guayaquil	-5:19:20 -	LMT	1890
      +			-5:14:00 -	QMT	1931 # Quito Mean Time
      +			-5:00	-	ECT	     # Ecuador Time
      +Zone Pacific/Galapagos	-5:58:24 -	LMT	1931 # Puerto Baquerizo Moreno
      +			-5:00	-	ECT	1986
      +			-6:00	-	GALT	     # Galapagos Time
      +
      +# Falklands
      +
      +# From Paul Eggert (2006-03-22):
      +# Between 1990 and 2000 inclusive, Shanks & Pottenger and the IATA agree except
      +# the IATA gives 1996-09-08.  Go with Shanks & Pottenger.
      +
      +# From Falkland Islands Government Office, London (2001-01-22)
      +# via Jesper Norgaard:
      +# ... the clocks revert back to Local Mean Time at 2 am on Sunday 15
      +# April 2001 and advance one hour to summer time at 2 am on Sunday 2
      +# September.  It is anticipated that the clocks will revert back at 2
      +# am on Sunday 21 April 2002 and advance to summer time at 2 am on
      +# Sunday 1 September.
      +
      +# From Rives McDow (2001-02-13):
      +#
      +# I have communicated several times with people there, and the last
      +# time I had communications that was helpful was in 1998.  Here is
      +# what was said then:
      +#
      +# "The general rule was that Stanley used daylight saving and the Camp
      +# did not. However for various reasons many people in the Camp have
      +# started to use daylight saving (known locally as 'Stanley Time')
      +# There is no rule as to who uses daylight saving - it is a matter of
      +# personal choice and so it is impossible to draw a map showing who
      +# uses it and who does not. Any list would be out of date as soon as
      +# it was produced. This year daylight saving ended on April 18/19th
      +# and started again on September 12/13th.  I do not know what the rule
      +# is, but can find out if you like.  We do not change at the same time
      +# as UK or Chile."
      +#
      +# I did have in my notes that the rule was "Second Saturday in Sep at
      +# 0:00 until third Saturday in Apr at 0:00".  I think that this does
      +# not agree in some cases with Shanks; is this true?
      +#
      +# Also, there is no mention in the list that some areas in the
      +# Falklands do not use DST.  I have found in my communications there
      +# that these areas are on the western half of East Falkland and all of
      +# West Falkland.  Stanley is the only place that consistently observes
      +# DST.  Again, as in other places in the world, the farmers don't like
      +# it.  West Falkland is almost entirely sheep farmers.
      +#
      +# I know one lady there that keeps a list of which farm keeps DST and
      +# which doesn't each year.  She runs a shop in Stanley, and says that
      +# the list changes each year.  She uses it to communicate to her
      +# customers, catching them when they are home for lunch or dinner.
      +
      +# From Paul Eggert (2001-03-05):
      +# For now, we'll just record the time in Stanley, since we have no
      +# better info.
      +
      +# From Steffen Thorsen (2011-04-01):
      +# The Falkland Islands will not turn back clocks this winter, but stay on
      +# daylight saving time.
      +#
      +# One source:
      +# 
      +# http://www.falklandnews.com/public/story.cfm?get=5914&source=3
      +# 
      +#
      +# We have gotten this confirmed by a clerk of the legislative assembly:
      +# Normally the clocks revert to Local Mean Time (UTC/GMT -4 hours) on the
      +# third Sunday of April at 0200hrs and advance to Summer Time (UTC/GMT -3
      +# hours) on the first Sunday of September at 0200hrs.
      +#
      +# IMPORTANT NOTE: During 2011, on a trial basis, the Falkland Islands
      +# will not revert to local mean time, but clocks will remain on Summer
      +# time (UTC/GMT - 3 hours) throughout the whole of 2011.  Any long term
      +# change to local time following the trial period will be notified.
      +#
      +# From Andrew Newman (2012-02-24)
      +# A letter from Justin McPhee, Chief Executive,
      +# Cable & Wireless Falkland Islands (dated 2012-02-22)
      +# states...
      +#   The current Atlantic/Stanley entry under South America expects the
      +#   clocks to go back to standard Falklands Time (FKT) on the 15th April.
      +#   The database entry states that in 2011 Stanley was staying on fixed
      +#   summer time on a trial basis only.  FIG need to contact IANA and/or
      +#   the maintainers of the database to inform them we're adopting
      +#   the same policy this year and suggest recommendations for future years.
      +#
      +# For now we will assume permanent summer time for the Falklands
      +# until advised differently (to apply for 2012 and beyond, after the 2011
      +# experiment was apparently successful.)
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Falk	1937	1938	-	Sep	lastSun	0:00	1:00	S
      +Rule	Falk	1938	1942	-	Mar	Sun>=19	0:00	0	-
      +Rule	Falk	1939	only	-	Oct	1	0:00	1:00	S
      +Rule	Falk	1940	1942	-	Sep	lastSun	0:00	1:00	S
      +Rule	Falk	1943	only	-	Jan	1	0:00	0	-
      +Rule	Falk	1983	only	-	Sep	lastSun	0:00	1:00	S
      +Rule	Falk	1984	1985	-	Apr	lastSun	0:00	0	-
      +Rule	Falk	1984	only	-	Sep	16	0:00	1:00	S
      +Rule	Falk	1985	2000	-	Sep	Sun>=9	0:00	1:00	S
      +Rule	Falk	1986	2000	-	Apr	Sun>=16	0:00	0	-
      +Rule	Falk	2001	2010	-	Apr	Sun>=15	2:00	0	-
      +Rule	Falk	2001	2010	-	Sep	Sun>=1	2:00	1:00	S
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Atlantic/Stanley	-3:51:24 -	LMT	1890
      +			-3:51:24 -	SMT	1912 Mar 12  # Stanley Mean Time
      +			-4:00	Falk	FK%sT	1983 May     # Falkland Is Time
      +			-3:00	Falk	FK%sT	1985 Sep 15
      +			-4:00	Falk	FK%sT	2010 Sep 5 02:00
      +			-3:00	-	FKST
      +
      +# French Guiana
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Cayenne	-3:29:20 -	LMT	1911 Jul
      +			-4:00	-	GFT	1967 Oct # French Guiana Time
      +			-3:00	-	GFT
      +
      +# Guyana
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	America/Guyana	-3:52:40 -	LMT	1915 Mar	# Georgetown
      +			-3:45	-	GBGT	1966 May 26 # Br Guiana Time
      +			-3:45	-	GYT	1975 Jul 31 # Guyana Time
      +			-3:00	-	GYT	1991
      +# IATA SSIM (1996-06) says -4:00.  Assume a 1991 switch.
      +			-4:00	-	GYT
      +
      +# Paraguay
      +# From Paul Eggert (2006-03-22):
      +# Shanks & Pottenger say that spring transitions are from 01:00 -> 02:00,
      +# and autumn transitions are from 00:00 -> 23:00.  Go with pre-1999
      +# editions of Shanks, and with the IATA, who say transitions occur at 00:00.
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Para	1975	1988	-	Oct	 1	0:00	1:00	S
      +Rule	Para	1975	1978	-	Mar	 1	0:00	0	-
      +Rule	Para	1979	1991	-	Apr	 1	0:00	0	-
      +Rule	Para	1989	only	-	Oct	22	0:00	1:00	S
      +Rule	Para	1990	only	-	Oct	 1	0:00	1:00	S
      +Rule	Para	1991	only	-	Oct	 6	0:00	1:00	S
      +Rule	Para	1992	only	-	Mar	 1	0:00	0	-
      +Rule	Para	1992	only	-	Oct	 5	0:00	1:00	S
      +Rule	Para	1993	only	-	Mar	31	0:00	0	-
      +Rule	Para	1993	1995	-	Oct	 1	0:00	1:00	S
      +Rule	Para	1994	1995	-	Feb	lastSun	0:00	0	-
      +Rule	Para	1996	only	-	Mar	 1	0:00	0	-
      +# IATA SSIM (2000-02) says 1999-10-10; ignore this for now.
      +# From Steffen Thorsen (2000-10-02):
      +# I have three independent reports that Paraguay changed to DST this Sunday
      +# (10-01).
      +#
      +# Translated by Gwillim Law (2001-02-27) from
      +# 
      +# Noticias, a daily paper in Asuncion, Paraguay (2000-10-01)
      +# :
      +# Starting at 0:00 today, the clock will be set forward 60 minutes, in
      +# fulfillment of Decree No. 7,273 of the Executive Power....  The time change
      +# system has been operating for several years.  Formerly there was a separate
      +# decree each year; the new law has the same effect, but permanently.  Every
      +# year, the time will change on the first Sunday of October; likewise, the
      +# clock will be set back on the first Sunday of March.
      +#
      +Rule	Para	1996	2001	-	Oct	Sun>=1	0:00	1:00	S
      +# IATA SSIM (1997-09) says Mar 1; go with Shanks & Pottenger.
      +Rule	Para	1997	only	-	Feb	lastSun	0:00	0	-
      +# Shanks & Pottenger say 1999-02-28; IATA SSIM (1999-02) says 1999-02-27, but
      +# (1999-09) reports no date; go with above sources and Gerd Knops (2001-02-27).
      +Rule	Para	1998	2001	-	Mar	Sun>=1	0:00	0	-
      +# From Rives McDow (2002-02-28):
      +# A decree was issued in Paraguay (no. 16350) on 2002-02-26 that changed the
      +# dst method to be from the first Sunday in September to the first Sunday in
      +# April.
      +Rule	Para	2002	2004	-	Apr	Sun>=1	0:00	0	-
      +Rule	Para	2002	2003	-	Sep	Sun>=1	0:00	1:00	S
      +#
      +# From Jesper Norgaard Welen (2005-01-02):
      +# There are several sources that claim that Paraguay made
      +# a timezone rule change in autumn 2004.
      +# From Steffen Thorsen (2005-01-05):
      +# Decree 1,867 (2004-03-05)
      +# From Carlos Raul Perasso via Jesper Norgaard Welen (2006-10-13)
      +# 
      +Rule	Para	2004	2009	-	Oct	Sun>=15	0:00	1:00	S
      +Rule	Para	2005	2009	-	Mar	Sun>=8	0:00	0	-
      +# From Carlos Raul Perasso (2010-02-18):
      +# By decree number 3958 issued yesterday (
      +# 
      +# http://www.presidencia.gov.py/v1/wp-content/uploads/2010/02/decreto3958.pdf
      +# 
      +# )
      +# Paraguay changes its DST schedule, postponing the March rule to April and
      +# modifying the October date. The decree reads:
      +# ...
      +# Art. 1. It is hereby established that from the second Sunday of the month of
      +# April of this year (2010), the official time is to be set back 60 minutes,
      +# and that on the first Sunday of the month of October, it is to be set
      +# forward 60 minutes, in all the territory of the Paraguayan Republic.
      +# ...
      +Rule	Para	2010	max	-	Oct	Sun>=1	0:00	1:00	S
      +Rule	Para	2010	max	-	Apr	Sun>=8	0:00	0	-
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Asuncion	-3:50:40 -	LMT	1890
      +			-3:50:40 -	AMT	1931 Oct 10 # Asuncion Mean Time
      +			-4:00	-	PYT	1972 Oct # Paraguay Time
      +			-3:00	-	PYT	1974 Apr
      +			-4:00	Para	PY%sT
      +
      +# Peru
      +#
      +# 
      +# From Evelyn C. Leeper via Mark Brader (2003-10-26):
      +# When we were in Peru in 1985-1986, they apparently switched over
      +# sometime between December 29 and January 3 while we were on the Amazon.
      +#
      +# From Paul Eggert (2006-03-22):
      +# Shanks & Pottenger don't have this transition.  Assume 1986 was like 1987.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	Peru	1938	only	-	Jan	 1	0:00	1:00	S
      +Rule	Peru	1938	only	-	Apr	 1	0:00	0	-
      +Rule	Peru	1938	1939	-	Sep	lastSun	0:00	1:00	S
      +Rule	Peru	1939	1940	-	Mar	Sun>=24	0:00	0	-
      +Rule	Peru	1986	1987	-	Jan	 1	0:00	1:00	S
      +Rule	Peru	1986	1987	-	Apr	 1	0:00	0	-
      +Rule	Peru	1990	only	-	Jan	 1	0:00	1:00	S
      +Rule	Peru	1990	only	-	Apr	 1	0:00	0	-
      +# IATA is ambiguous for 1993/1995; go with Shanks & Pottenger.
      +Rule	Peru	1994	only	-	Jan	 1	0:00	1:00	S
      +Rule	Peru	1994	only	-	Apr	 1	0:00	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	America/Lima	-5:08:12 -	LMT	1890
      +			-5:08:36 -	LMT	1908 Jul 28 # Lima Mean Time?
      +			-5:00	Peru	PE%sT	# Peru Time
      +
      +# South Georgia
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone Atlantic/South_Georgia -2:26:08 -	LMT	1890		# Grytviken
      +			-2:00	-	GST	# South Georgia Time
      +
      +# South Sandwich Is
      +# uninhabited; scientific personnel have wintered
      +
      +# Suriname
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Paramaribo	-3:40:40 -	LMT	1911
      +			-3:40:52 -	PMT	1935     # Paramaribo Mean Time
      +			-3:40:36 -	PMT	1945 Oct # The capital moved?
      +			-3:30	-	NEGT	1975 Nov 20 # Dutch Guiana Time
      +			-3:30	-	SRT	1984 Oct # Suriname Time
      +			-3:00	-	SRT
      +
      +# Trinidad and Tobago
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Port_of_Spain -4:06:04 -	LMT	1912 Mar 2
      +			-4:00	-	AST
      +
      +# Uruguay
      +# From Paul Eggert (1993-11-18):
      +# Uruguay wins the prize for the strangest peacetime manipulation of the rules.
      +# From Shanks & Pottenger:
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +# Whitman gives 1923 Oct 1; go with Shanks & Pottenger.
      +Rule	Uruguay	1923	only	-	Oct	 2	 0:00	0:30	HS
      +Rule	Uruguay	1924	1926	-	Apr	 1	 0:00	0	-
      +Rule	Uruguay	1924	1925	-	Oct	 1	 0:00	0:30	HS
      +Rule	Uruguay	1933	1935	-	Oct	lastSun	 0:00	0:30	HS
      +# Shanks & Pottenger give 1935 Apr 1 0:00 & 1936 Mar 30 0:00; go with Whitman.
      +Rule	Uruguay	1934	1936	-	Mar	Sat>=25	23:30s	0	-
      +Rule	Uruguay	1936	only	-	Nov	 1	 0:00	0:30	HS
      +Rule	Uruguay	1937	1941	-	Mar	lastSun	 0:00	0	-
      +# Whitman gives 1937 Oct 3; go with Shanks & Pottenger.
      +Rule	Uruguay	1937	1940	-	Oct	lastSun	 0:00	0:30	HS
      +# Whitman gives 1941 Oct 24 - 1942 Mar 27, 1942 Dec 14 - 1943 Apr 13,
      +# and 1943 Apr 13 ``to present time''; go with Shanks & Pottenger.
      +Rule	Uruguay	1941	only	-	Aug	 1	 0:00	0:30	HS
      +Rule	Uruguay	1942	only	-	Jan	 1	 0:00	0	-
      +Rule	Uruguay	1942	only	-	Dec	14	 0:00	1:00	S
      +Rule	Uruguay	1943	only	-	Mar	14	 0:00	0	-
      +Rule	Uruguay	1959	only	-	May	24	 0:00	1:00	S
      +Rule	Uruguay	1959	only	-	Nov	15	 0:00	0	-
      +Rule	Uruguay	1960	only	-	Jan	17	 0:00	1:00	S
      +Rule	Uruguay	1960	only	-	Mar	 6	 0:00	0	-
      +Rule	Uruguay	1965	1967	-	Apr	Sun>=1	 0:00	1:00	S
      +Rule	Uruguay	1965	only	-	Sep	26	 0:00	0	-
      +Rule	Uruguay	1966	1967	-	Oct	31	 0:00	0	-
      +Rule	Uruguay	1968	1970	-	May	27	 0:00	0:30	HS
      +Rule	Uruguay	1968	1970	-	Dec	 2	 0:00	0	-
      +Rule	Uruguay	1972	only	-	Apr	24	 0:00	1:00	S
      +Rule	Uruguay	1972	only	-	Aug	15	 0:00	0	-
      +Rule	Uruguay	1974	only	-	Mar	10	 0:00	0:30	HS
      +Rule	Uruguay	1974	only	-	Dec	22	 0:00	1:00	S
      +Rule	Uruguay	1976	only	-	Oct	 1	 0:00	0	-
      +Rule	Uruguay	1977	only	-	Dec	 4	 0:00	1:00	S
      +Rule	Uruguay	1978	only	-	Apr	 1	 0:00	0	-
      +Rule	Uruguay	1979	only	-	Oct	 1	 0:00	1:00	S
      +Rule	Uruguay	1980	only	-	May	 1	 0:00	0	-
      +Rule	Uruguay	1987	only	-	Dec	14	 0:00	1:00	S
      +Rule	Uruguay	1988	only	-	Mar	14	 0:00	0	-
      +Rule	Uruguay	1988	only	-	Dec	11	 0:00	1:00	S
      +Rule	Uruguay	1989	only	-	Mar	12	 0:00	0	-
      +Rule	Uruguay	1989	only	-	Oct	29	 0:00	1:00	S
      +# Shanks & Pottenger say no DST was observed in 1990/1 and 1991/2,
      +# and that 1992/3's DST was from 10-25 to 03-01.  Go with IATA.
      +Rule	Uruguay	1990	1992	-	Mar	Sun>=1	 0:00	0	-
      +Rule	Uruguay	1990	1991	-	Oct	Sun>=21	 0:00	1:00	S
      +Rule	Uruguay	1992	only	-	Oct	18	 0:00	1:00	S
      +Rule	Uruguay	1993	only	-	Feb	28	 0:00	0	-
      +# From Eduardo Cota (2004-09-20):
      +# The uruguayan government has decreed a change in the local time....
      +# http://www.presidencia.gub.uy/decretos/2004091502.htm
      +Rule	Uruguay	2004	only	-	Sep	19	 0:00	1:00	S
      +# From Steffen Thorsen (2005-03-11):
      +# Uruguay's DST was scheduled to end on Sunday, 2005-03-13, but in order to
      +# save energy ... it was postponed two weeks....
      +# http://www.presidencia.gub.uy/_Web/noticias/2005/03/2005031005.htm
      +Rule	Uruguay	2005	only	-	Mar	27	 2:00	0	-
      +# From Eduardo Cota (2005-09-27):
      +# http://www.presidencia.gub.uy/_Web/decretos/2005/09/CM%20119_09%2009%202005_00001.PDF
      +# This means that from 2005-10-09 at 02:00 local time, until 2006-03-12 at
      +# 02:00 local time, official time in Uruguay will be at GMT -2.
      +Rule	Uruguay	2005	only	-	Oct	 9	 2:00	1:00	S
      +Rule	Uruguay	2006	only	-	Mar	12	 2:00	0	-
      +# From Jesper Norgaard Welen (2006-09-06):
      +# http://www.presidencia.gub.uy/_web/decretos/2006/09/CM%20210_08%2006%202006_00001.PDF
      +Rule	Uruguay	2006	max	-	Oct	Sun>=1	 2:00	1:00	S
      +Rule	Uruguay	2007	max	-	Mar	Sun>=8	 2:00	0	-
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone America/Montevideo	-3:44:44 -	LMT	1898 Jun 28
      +			-3:44:44 -	MMT	1920 May  1	# Montevideo MT
      +			-3:30	Uruguay	UY%sT	1942 Dec 14	# Uruguay Time
      +			-3:00	Uruguay	UY%sT
      +
      +# Venezuela
      +#
      +# From John Stainforth (2007-11-28):
      +# ... the change for Venezuela originally expected for 2007-12-31 has
      +# been brought forward to 2007-12-09.  The official announcement was
      +# published today in the "Gaceta Oficial de la Republica Bolivariana
      +# de Venezuela, numero 38.819" (official document for all laws or
      +# resolution publication)
      +# http://www.globovision.com/news.php?nid=72208
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	America/Caracas	-4:27:44 -	LMT	1890
      +			-4:27:40 -	CMT	1912 Feb 12 # Caracas Mean Time?
      +			-4:30	-	VET	1965	     # Venezuela Time
      +			-4:00	-	VET	2007 Dec  9 03:00
      +			-4:30	-	VET
      diff --git a/jdk/test/sun/util/calendar/zi/tzdata/systemv b/jdk/test/sun/util/calendar/zi/tzdata/systemv
      new file mode 100644
      index 00000000000..0b0a2665654
      --- /dev/null
      +++ b/jdk/test/sun/util/calendar/zi/tzdata/systemv
      @@ -0,0 +1,61 @@
      +#
      +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      +#  
      +# This code is free software; you can redistribute it and/or modify it
      +# under the terms of the GNU General Public License version 2 only, as
      +# published by the Free Software Foundation.  Oracle designates this
      +# particular file as subject to the "Classpath" exception as provided
      +# by Oracle in the LICENSE file that accompanied this code.
      +#  
      +# This code is distributed in the hope that it will be useful, but WITHOUT
      +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      +# version 2 for more details (a copy is included in the LICENSE file that
      +# accompanied this code).
      +#  
      +# You should have received a copy of the GNU General Public License version
      +# 2 along with this work; if not, write to the Free Software Foundation,
      +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      +#  
      +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      +# or visit www.oracle.com if you need additional information or have any
      +# questions.
      +#
      +# 
      +# This file is in the public domain, so clarified as of
      +# 2009-05-17 by Arthur David Olson.
      +
      +# Old rules, should the need arise.
      +# No attempt is made to handle Newfoundland, since it cannot be expressed
      +# using the System V "TZ" scheme (half-hour offset), or anything outside
      +# North America (no support for non-standard DST start/end dates), nor
      +# the changes in the DST rules in the US after 1976 (which occurred after
      +# the old rules were written).
      +#
      +# If you need the old rules, uncomment ## lines.
      +# Compile this *without* leap second correction for true conformance.
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	SystemV	min	1973	-	Apr	lastSun	2:00	1:00	D
      +Rule	SystemV	min	1973	-	Oct	lastSun	2:00	0	S
      +Rule	SystemV	1974	only	-	Jan	6	2:00	1:00	D
      +Rule	SystemV	1974	only	-	Nov	lastSun	2:00	0	S
      +Rule	SystemV	1975	only	-	Feb	23	2:00	1:00	D
      +Rule	SystemV	1975	only	-	Oct	lastSun	2:00	0	S
      +Rule	SystemV	1976	max	-	Apr	lastSun	2:00	1:00	D
      +Rule	SystemV	1976	max	-	Oct	lastSun	2:00	0	S
      +
      +# Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
      +## Zone	SystemV/AST4ADT	-4:00	SystemV		A%sT
      +## Zone	SystemV/EST5EDT	-5:00	SystemV		E%sT
      +## Zone	SystemV/CST6CDT	-6:00	SystemV		C%sT
      +## Zone	SystemV/MST7MDT	-7:00	SystemV		M%sT
      +## Zone	SystemV/PST8PDT	-8:00	SystemV		P%sT
      +## Zone	SystemV/YST9YDT	-9:00	SystemV		Y%sT
      +## Zone	SystemV/AST4	-4:00	-		AST
      +## Zone	SystemV/EST5	-5:00	-		EST
      +## Zone	SystemV/CST6	-6:00	-		CST
      +## Zone	SystemV/MST7	-7:00	-		MST
      +## Zone	SystemV/PST8	-8:00	-		PST
      +## Zone	SystemV/YST9	-9:00	-		YST
      +## Zone	SystemV/HST10	-10:00	-		HST
      diff --git a/jdk/test/sun/util/calendar/zi/tzdata/zone.tab b/jdk/test/sun/util/calendar/zi/tzdata/zone.tab
      new file mode 100644
      index 00000000000..ef380cd19fb
      --- /dev/null
      +++ b/jdk/test/sun/util/calendar/zi/tzdata/zone.tab
      @@ -0,0 +1,464 @@
      +#
      +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      +#  
      +# This code is free software; you can redistribute it and/or modify it
      +# under the terms of the GNU General Public License version 2 only, as
      +# published by the Free Software Foundation.  Oracle designates this
      +# particular file as subject to the "Classpath" exception as provided
      +# by Oracle in the LICENSE file that accompanied this code.
      +#  
      +# This code is distributed in the hope that it will be useful, but WITHOUT
      +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      +# version 2 for more details (a copy is included in the LICENSE file that
      +# accompanied this code).
      +#  
      +# You should have received a copy of the GNU General Public License version
      +# 2 along with this work; if not, write to the Free Software Foundation,
      +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      +#  
      +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      +# or visit www.oracle.com if you need additional information or have any
      +# questions.
      +#
      +# 
      +# This file is in the public domain, so clarified as of
      +# 2009-05-17 by Arthur David Olson.
      +#
      +# TZ zone descriptions
      +#
      +# From Paul Eggert (1996-08-05):
      +#
      +# This file contains a table with the following columns:
      +# 1.  ISO 3166 2-character country code.  See the file `iso3166.tab'.
      +# 2.  Latitude and longitude of the zone's principal location
      +#     in ISO 6709 sign-degrees-minutes-seconds format,
      +#     either +-DDMM+-DDDMM or +-DDMMSS+-DDDMMSS,
      +#     first latitude (+ is north), then longitude (+ is east).
      +# 3.  Zone name used in value of TZ environment variable.
      +# 4.  Comments; present if and only if the country has multiple rows.
      +#
      +# Columns are separated by a single tab.
      +# The table is sorted first by country, then an order within the country that
      +# (1) makes some geographical sense, and
      +# (2) puts the most populous zones first, where that does not contradict (1).
      +#
      +# Lines beginning with `#' are comments.
      +#
      +#country-
      +#code	coordinates	TZ			comments
      +AD	+4230+00131	Europe/Andorra
      +AE	+2518+05518	Asia/Dubai
      +AF	+3431+06912	Asia/Kabul
      +AG	+1703-06148	America/Antigua
      +AI	+1812-06304	America/Anguilla
      +AL	+4120+01950	Europe/Tirane
      +AM	+4011+04430	Asia/Yerevan
      +AO	-0848+01314	Africa/Luanda
      +AQ	-7750+16636	Antarctica/McMurdo	McMurdo Station, Ross Island
      +AQ	-9000+00000	Antarctica/South_Pole	Amundsen-Scott Station, South Pole
      +AQ	-6734-06808	Antarctica/Rothera	Rothera Station, Adelaide Island
      +AQ	-6448-06406	Antarctica/Palmer	Palmer Station, Anvers Island
      +AQ	-6736+06253	Antarctica/Mawson	Mawson Station, Holme Bay
      +AQ	-6835+07758	Antarctica/Davis	Davis Station, Vestfold Hills
      +AQ	-6617+11031	Antarctica/Casey	Casey Station, Bailey Peninsula
      +AQ	-7824+10654	Antarctica/Vostok	Vostok Station, Lake Vostok
      +AQ	-6640+14001	Antarctica/DumontDUrville	Dumont-d'Urville Station, Terre Adelie
      +AQ	-690022+0393524	Antarctica/Syowa	Syowa Station, E Ongul I
      +AQ	-5430+15857	Antarctica/Macquarie	Macquarie Island Station, Macquarie Island
      +AR	-3436-05827	America/Argentina/Buenos_Aires	Buenos Aires (BA, CF)
      +AR	-3124-06411	America/Argentina/Cordoba	most locations (CB, CC, CN, ER, FM, MN, SE, SF)
      +AR	-2447-06525	America/Argentina/Salta	(SA, LP, NQ, RN)
      +AR	-2411-06518	America/Argentina/Jujuy	Jujuy (JY)
      +AR	-2649-06513	America/Argentina/Tucuman	Tucuman (TM)
      +AR	-2828-06547	America/Argentina/Catamarca	Catamarca (CT), Chubut (CH)
      +AR	-2926-06651	America/Argentina/La_Rioja	La Rioja (LR)
      +AR	-3132-06831	America/Argentina/San_Juan	San Juan (SJ)
      +AR	-3253-06849	America/Argentina/Mendoza	Mendoza (MZ)
      +AR	-3319-06621	America/Argentina/San_Luis	San Luis (SL)
      +AR	-5138-06913	America/Argentina/Rio_Gallegos	Santa Cruz (SC)
      +AR	-5448-06818	America/Argentina/Ushuaia	Tierra del Fuego (TF)
      +AS	-1416-17042	Pacific/Pago_Pago
      +AT	+4813+01620	Europe/Vienna
      +AU	-3133+15905	Australia/Lord_Howe	Lord Howe Island
      +AU	-4253+14719	Australia/Hobart	Tasmania - most locations
      +AU	-3956+14352	Australia/Currie	Tasmania - King Island
      +AU	-3749+14458	Australia/Melbourne	Victoria
      +AU	-3352+15113	Australia/Sydney	New South Wales - most locations
      +AU	-3157+14127	Australia/Broken_Hill	New South Wales - Yancowinna
      +AU	-2728+15302	Australia/Brisbane	Queensland - most locations
      +AU	-2016+14900	Australia/Lindeman	Queensland - Holiday Islands
      +AU	-3455+13835	Australia/Adelaide	South Australia
      +AU	-1228+13050	Australia/Darwin	Northern Territory
      +AU	-3157+11551	Australia/Perth	Western Australia - most locations
      +AU	-3143+12852	Australia/Eucla	Western Australia - Eucla area
      +AW	+1230-06958	America/Aruba
      +AX	+6006+01957	Europe/Mariehamn
      +AZ	+4023+04951	Asia/Baku
      +BA	+4352+01825	Europe/Sarajevo
      +BB	+1306-05937	America/Barbados
      +BD	+2343+09025	Asia/Dhaka
      +BE	+5050+00420	Europe/Brussels
      +BF	+1222-00131	Africa/Ouagadougou
      +BG	+4241+02319	Europe/Sofia
      +BH	+2623+05035	Asia/Bahrain
      +BI	-0323+02922	Africa/Bujumbura
      +BJ	+0629+00237	Africa/Porto-Novo
      +BL	+1753-06251	America/St_Barthelemy
      +BM	+3217-06446	Atlantic/Bermuda
      +BN	+0456+11455	Asia/Brunei
      +BO	-1630-06809	America/La_Paz
      +BQ	+120903-0681636	America/Kralendijk
      +BR	-0351-03225	America/Noronha	Atlantic islands
      +BR	-0127-04829	America/Belem	Amapa, E Para
      +BR	-0343-03830	America/Fortaleza	NE Brazil (MA, PI, CE, RN, PB)
      +BR	-0803-03454	America/Recife	Pernambuco
      +BR	-0712-04812	America/Araguaina	Tocantins
      +BR	-0940-03543	America/Maceio	Alagoas, Sergipe
      +BR	-1259-03831	America/Bahia	Bahia
      +BR	-2332-04637	America/Sao_Paulo	S & SE Brazil (GO, DF, MG, ES, RJ, SP, PR, SC, RS)
      +BR	-2027-05437	America/Campo_Grande	Mato Grosso do Sul
      +BR	-1535-05605	America/Cuiaba	Mato Grosso
      +BR	-0226-05452	America/Santarem	W Para
      +BR	-0846-06354	America/Porto_Velho	Rondonia
      +BR	+0249-06040	America/Boa_Vista	Roraima
      +BR	-0308-06001	America/Manaus	E Amazonas
      +BR	-0640-06952	America/Eirunepe	W Amazonas
      +BR	-0958-06748	America/Rio_Branco	Acre
      +BS	+2505-07721	America/Nassau
      +BT	+2728+08939	Asia/Thimphu
      +BW	-2439+02555	Africa/Gaborone
      +BY	+5354+02734	Europe/Minsk
      +BZ	+1730-08812	America/Belize
      +CA	+4734-05243	America/St_Johns	Newfoundland Time, including SE Labrador
      +CA	+4439-06336	America/Halifax	Atlantic Time - Nova Scotia (most places), PEI
      +CA	+4612-05957	America/Glace_Bay	Atlantic Time - Nova Scotia - places that did not observe DST 1966-1971
      +CA	+4606-06447	America/Moncton	Atlantic Time - New Brunswick
      +CA	+5320-06025	America/Goose_Bay	Atlantic Time - Labrador - most locations
      +CA	+5125-05707	America/Blanc-Sablon	Atlantic Standard Time - Quebec - Lower North Shore
      +CA	+4531-07334	America/Montreal	Eastern Time - Quebec - most locations
      +CA	+4339-07923	America/Toronto	Eastern Time - Ontario - most locations
      +CA	+4901-08816	America/Nipigon	Eastern Time - Ontario & Quebec - places that did not observe DST 1967-1973
      +CA	+4823-08915	America/Thunder_Bay	Eastern Time - Thunder Bay, Ontario
      +CA	+6344-06828	America/Iqaluit	Eastern Time - east Nunavut - most locations
      +CA	+6608-06544	America/Pangnirtung	Eastern Time - Pangnirtung, Nunavut
      +CA	+744144-0944945	America/Resolute	Central Standard Time - Resolute, Nunavut
      +CA	+484531-0913718	America/Atikokan	Eastern Standard Time - Atikokan, Ontario and Southampton I, Nunavut
      +CA	+624900-0920459	America/Rankin_Inlet	Central Time - central Nunavut
      +CA	+4953-09709	America/Winnipeg	Central Time - Manitoba & west Ontario
      +CA	+4843-09434	America/Rainy_River	Central Time - Rainy River & Fort Frances, Ontario
      +CA	+5024-10439	America/Regina	Central Standard Time - Saskatchewan - most locations
      +CA	+5017-10750	America/Swift_Current	Central Standard Time - Saskatchewan - midwest
      +CA	+5333-11328	America/Edmonton	Mountain Time - Alberta, east British Columbia & west Saskatchewan
      +CA	+690650-1050310	America/Cambridge_Bay	Mountain Time - west Nunavut
      +CA	+6227-11421	America/Yellowknife	Mountain Time - central Northwest Territories
      +CA	+682059-1334300	America/Inuvik	Mountain Time - west Northwest Territories
      +CA	+4906-11631	America/Creston	Mountain Standard Time - Creston, British Columbia
      +CA	+5946-12014	America/Dawson_Creek	Mountain Standard Time - Dawson Creek & Fort Saint John, British Columbia
      +CA	+4916-12307	America/Vancouver	Pacific Time - west British Columbia
      +CA	+6043-13503	America/Whitehorse	Pacific Time - south Yukon
      +CA	+6404-13925	America/Dawson	Pacific Time - north Yukon
      +CC	-1210+09655	Indian/Cocos
      +CD	-0418+01518	Africa/Kinshasa	west Dem. Rep. of Congo
      +CD	-1140+02728	Africa/Lubumbashi	east Dem. Rep. of Congo
      +CF	+0422+01835	Africa/Bangui
      +CG	-0416+01517	Africa/Brazzaville
      +CH	+4723+00832	Europe/Zurich
      +CI	+0519-00402	Africa/Abidjan
      +CK	-2114-15946	Pacific/Rarotonga
      +CL	-3327-07040	America/Santiago	most locations
      +CL	-2709-10926	Pacific/Easter	Easter Island & Sala y Gomez
      +CM	+0403+00942	Africa/Douala
      +CN	+3114+12128	Asia/Shanghai	east China - Beijing, Guangdong, Shanghai, etc.
      +CN	+4545+12641	Asia/Harbin	Heilongjiang (except Mohe), Jilin
      +CN	+2934+10635	Asia/Chongqing	central China - Sichuan, Yunnan, Guangxi, Shaanxi, Guizhou, etc.
      +CN	+4348+08735	Asia/Urumqi	most of Tibet & Xinjiang
      +CN	+3929+07559	Asia/Kashgar	west Tibet & Xinjiang
      +CO	+0436-07405	America/Bogota
      +CR	+0956-08405	America/Costa_Rica
      +CU	+2308-08222	America/Havana
      +CV	+1455-02331	Atlantic/Cape_Verde
      +CW	+1211-06900	America/Curacao
      +CX	-1025+10543	Indian/Christmas
      +CY	+3510+03322	Asia/Nicosia
      +CZ	+5005+01426	Europe/Prague
      +DE	+5230+01322	Europe/Berlin
      +DJ	+1136+04309	Africa/Djibouti
      +DK	+5540+01235	Europe/Copenhagen
      +DM	+1518-06124	America/Dominica
      +DO	+1828-06954	America/Santo_Domingo
      +DZ	+3647+00303	Africa/Algiers
      +EC	-0210-07950	America/Guayaquil	mainland
      +EC	-0054-08936	Pacific/Galapagos	Galapagos Islands
      +EE	+5925+02445	Europe/Tallinn
      +EG	+3003+03115	Africa/Cairo
      +EH	+2709-01312	Africa/El_Aaiun
      +ER	+1520+03853	Africa/Asmara
      +ES	+4024-00341	Europe/Madrid	mainland
      +ES	+3553-00519	Africa/Ceuta	Ceuta & Melilla
      +ES	+2806-01524	Atlantic/Canary	Canary Islands
      +ET	+0902+03842	Africa/Addis_Ababa
      +FI	+6010+02458	Europe/Helsinki
      +FJ	-1808+17825	Pacific/Fiji
      +FK	-5142-05751	Atlantic/Stanley
      +FM	+0725+15147	Pacific/Chuuk	Chuuk (Truk) and Yap
      +FM	+0658+15813	Pacific/Pohnpei	Pohnpei (Ponape)
      +FM	+0519+16259	Pacific/Kosrae	Kosrae
      +FO	+6201-00646	Atlantic/Faroe
      +FR	+4852+00220	Europe/Paris
      +GA	+0023+00927	Africa/Libreville
      +GB	+513030-0000731	Europe/London
      +GD	+1203-06145	America/Grenada
      +GE	+4143+04449	Asia/Tbilisi
      +GF	+0456-05220	America/Cayenne
      +GG	+4927-00232	Europe/Guernsey
      +GH	+0533-00013	Africa/Accra
      +GI	+3608-00521	Europe/Gibraltar
      +GL	+6411-05144	America/Godthab	most locations
      +GL	+7646-01840	America/Danmarkshavn	east coast, north of Scoresbysund
      +GL	+7029-02158	America/Scoresbysund	Scoresbysund / Ittoqqortoormiit
      +GL	+7634-06847	America/Thule	Thule / Pituffik
      +GM	+1328-01639	Africa/Banjul
      +GN	+0931-01343	Africa/Conakry
      +GP	+1614-06132	America/Guadeloupe
      +GQ	+0345+00847	Africa/Malabo
      +GR	+3758+02343	Europe/Athens
      +GS	-5416-03632	Atlantic/South_Georgia
      +GT	+1438-09031	America/Guatemala
      +GU	+1328+14445	Pacific/Guam
      +GW	+1151-01535	Africa/Bissau
      +GY	+0648-05810	America/Guyana
      +HK	+2217+11409	Asia/Hong_Kong
      +HN	+1406-08713	America/Tegucigalpa
      +HR	+4548+01558	Europe/Zagreb
      +HT	+1832-07220	America/Port-au-Prince
      +HU	+4730+01905	Europe/Budapest
      +ID	-0610+10648	Asia/Jakarta	Java & Sumatra
      +ID	-0002+10920	Asia/Pontianak	west & central Borneo
      +ID	-0507+11924	Asia/Makassar	east & south Borneo, Sulawesi (Celebes), Bali, Nusa Tengarra, west Timor
      +ID	-0232+14042	Asia/Jayapura	west New Guinea (Irian Jaya) & Malukus (Moluccas)
      +IE	+5320-00615	Europe/Dublin
      +IL	+3146+03514	Asia/Jerusalem
      +IM	+5409-00428	Europe/Isle_of_Man
      +IN	+2232+08822	Asia/Kolkata
      +IO	-0720+07225	Indian/Chagos
      +IQ	+3321+04425	Asia/Baghdad
      +IR	+3540+05126	Asia/Tehran
      +IS	+6409-02151	Atlantic/Reykjavik
      +IT	+4154+01229	Europe/Rome
      +JE	+4912-00207	Europe/Jersey
      +JM	+1800-07648	America/Jamaica
      +JO	+3157+03556	Asia/Amman
      +JP	+353916+1394441	Asia/Tokyo
      +KE	-0117+03649	Africa/Nairobi
      +KG	+4254+07436	Asia/Bishkek
      +KH	+1133+10455	Asia/Phnom_Penh
      +KI	+0125+17300	Pacific/Tarawa	Gilbert Islands
      +KI	-0308-17105	Pacific/Enderbury	Phoenix Islands
      +KI	+0152-15720	Pacific/Kiritimati	Line Islands
      +KM	-1141+04316	Indian/Comoro
      +KN	+1718-06243	America/St_Kitts
      +KP	+3901+12545	Asia/Pyongyang
      +KR	+3733+12658	Asia/Seoul
      +KW	+2920+04759	Asia/Kuwait
      +KY	+1918-08123	America/Cayman
      +KZ	+4315+07657	Asia/Almaty	most locations
      +KZ	+4448+06528	Asia/Qyzylorda	Qyzylorda (Kyzylorda, Kzyl-Orda)
      +KZ	+5017+05710	Asia/Aqtobe	Aqtobe (Aktobe)
      +KZ	+4431+05016	Asia/Aqtau	Atyrau (Atirau, Gur'yev), Mangghystau (Mankistau)
      +KZ	+5113+05121	Asia/Oral	West Kazakhstan
      +LA	+1758+10236	Asia/Vientiane
      +LB	+3353+03530	Asia/Beirut
      +LC	+1401-06100	America/St_Lucia
      +LI	+4709+00931	Europe/Vaduz
      +LK	+0656+07951	Asia/Colombo
      +LR	+0618-01047	Africa/Monrovia
      +LS	-2928+02730	Africa/Maseru
      +LT	+5441+02519	Europe/Vilnius
      +LU	+4936+00609	Europe/Luxembourg
      +LV	+5657+02406	Europe/Riga
      +LY	+3254+01311	Africa/Tripoli
      +MA	+3339-00735	Africa/Casablanca
      +MC	+4342+00723	Europe/Monaco
      +MD	+4700+02850	Europe/Chisinau
      +ME	+4226+01916	Europe/Podgorica
      +MF	+1804-06305	America/Marigot
      +MG	-1855+04731	Indian/Antananarivo
      +MH	+0709+17112	Pacific/Majuro	most locations
      +MH	+0905+16720	Pacific/Kwajalein	Kwajalein
      +MK	+4159+02126	Europe/Skopje
      +ML	+1239-00800	Africa/Bamako
      +MM	+1647+09610	Asia/Rangoon
      +MN	+4755+10653	Asia/Ulaanbaatar	most locations
      +MN	+4801+09139	Asia/Hovd	Bayan-Olgiy, Govi-Altai, Hovd, Uvs, Zavkhan
      +MN	+4804+11430	Asia/Choibalsan	Dornod, Sukhbaatar
      +MO	+2214+11335	Asia/Macau
      +MP	+1512+14545	Pacific/Saipan
      +MQ	+1436-06105	America/Martinique
      +MR	+1806-01557	Africa/Nouakchott
      +MS	+1643-06213	America/Montserrat
      +MT	+3554+01431	Europe/Malta
      +MU	-2010+05730	Indian/Mauritius
      +MV	+0410+07330	Indian/Maldives
      +MW	-1547+03500	Africa/Blantyre
      +MX	+1924-09909	America/Mexico_City	Central Time - most locations
      +MX	+2105-08646	America/Cancun	Central Time - Quintana Roo
      +MX	+2058-08937	America/Merida	Central Time - Campeche, Yucatan
      +MX	+2540-10019	America/Monterrey	Mexican Central Time - Coahuila, Durango, Nuevo Leon, Tamaulipas away from US border
      +MX	+2550-09730	America/Matamoros	US Central Time - Coahuila, Durango, Nuevo Leon, Tamaulipas near US border
      +MX	+2313-10625	America/Mazatlan	Mountain Time - S Baja, Nayarit, Sinaloa
      +MX	+2838-10605	America/Chihuahua	Mexican Mountain Time - Chihuahua away from US border
      +MX	+2934-10425	America/Ojinaga	US Mountain Time - Chihuahua near US border
      +MX	+2904-11058	America/Hermosillo	Mountain Standard Time - Sonora
      +MX	+3232-11701	America/Tijuana	US Pacific Time - Baja California near US border
      +MX	+3018-11452	America/Santa_Isabel	Mexican Pacific Time - Baja California away from US border
      +MX	+2048-10515	America/Bahia_Banderas	Mexican Central Time - Bahia de Banderas
      +MY	+0310+10142	Asia/Kuala_Lumpur	peninsular Malaysia
      +MY	+0133+11020	Asia/Kuching	Sabah & Sarawak
      +MZ	-2558+03235	Africa/Maputo
      +NA	-2234+01706	Africa/Windhoek
      +NC	-2216+16627	Pacific/Noumea
      +NE	+1331+00207	Africa/Niamey
      +NF	-2903+16758	Pacific/Norfolk
      +NG	+0627+00324	Africa/Lagos
      +NI	+1209-08617	America/Managua
      +NL	+5222+00454	Europe/Amsterdam
      +NO	+5955+01045	Europe/Oslo
      +NP	+2743+08519	Asia/Kathmandu
      +NR	-0031+16655	Pacific/Nauru
      +NU	-1901-16955	Pacific/Niue
      +NZ	-3652+17446	Pacific/Auckland	most locations
      +NZ	-4357-17633	Pacific/Chatham	Chatham Islands
      +OM	+2336+05835	Asia/Muscat
      +PA	+0858-07932	America/Panama
      +PE	-1203-07703	America/Lima
      +PF	-1732-14934	Pacific/Tahiti	Society Islands
      +PF	-0900-13930	Pacific/Marquesas	Marquesas Islands
      +PF	-2308-13457	Pacific/Gambier	Gambier Islands
      +PG	-0930+14710	Pacific/Port_Moresby
      +PH	+1435+12100	Asia/Manila
      +PK	+2452+06703	Asia/Karachi
      +PL	+5215+02100	Europe/Warsaw
      +PM	+4703-05620	America/Miquelon
      +PN	-2504-13005	Pacific/Pitcairn
      +PR	+182806-0660622	America/Puerto_Rico
      +PS	+3130+03428	Asia/Gaza	Gaza Strip
      +PS	+313200+0350542	Asia/Hebron	West Bank
      +PT	+3843-00908	Europe/Lisbon	mainland
      +PT	+3238-01654	Atlantic/Madeira	Madeira Islands
      +PT	+3744-02540	Atlantic/Azores	Azores
      +PW	+0720+13429	Pacific/Palau
      +PY	-2516-05740	America/Asuncion
      +QA	+2517+05132	Asia/Qatar
      +RE	-2052+05528	Indian/Reunion
      +RO	+4426+02606	Europe/Bucharest
      +RS	+4450+02030	Europe/Belgrade
      +RU	+5443+02030	Europe/Kaliningrad	Moscow-01 - Kaliningrad
      +RU	+5545+03735	Europe/Moscow	Moscow+00 - west Russia
      +RU	+4844+04425	Europe/Volgograd	Moscow+00 - Caspian Sea
      +RU	+5312+05009	Europe/Samara	Moscow+00 - Samara, Udmurtia
      +RU	+5651+06036	Asia/Yekaterinburg	Moscow+02 - Urals
      +RU	+5500+07324	Asia/Omsk	Moscow+03 - west Siberia
      +RU	+5502+08255	Asia/Novosibirsk	Moscow+03 - Novosibirsk
      +RU	+5345+08707	Asia/Novokuznetsk	Moscow+03 - Novokuznetsk
      +RU	+5601+09250	Asia/Krasnoyarsk	Moscow+04 - Yenisei River
      +RU	+5216+10420	Asia/Irkutsk	Moscow+05 - Lake Baikal
      +RU	+6200+12940	Asia/Yakutsk	Moscow+06 - Lena River
      +RU	+4310+13156	Asia/Vladivostok	Moscow+07 - Amur River
      +RU	+4658+14242	Asia/Sakhalin	Moscow+07 - Sakhalin Island
      +RU	+5934+15048	Asia/Magadan	Moscow+08 - Magadan
      +RU	+5301+15839	Asia/Kamchatka	Moscow+08 - Kamchatka
      +RU	+6445+17729	Asia/Anadyr	Moscow+08 - Bering Sea
      +RW	-0157+03004	Africa/Kigali
      +SA	+2438+04643	Asia/Riyadh
      +SB	-0932+16012	Pacific/Guadalcanal
      +SC	-0440+05528	Indian/Mahe
      +SD	+1536+03232	Africa/Khartoum
      +SE	+5920+01803	Europe/Stockholm
      +SG	+0117+10351	Asia/Singapore
      +SH	-1555-00542	Atlantic/St_Helena
      +SI	+4603+01431	Europe/Ljubljana
      +SJ	+7800+01600	Arctic/Longyearbyen
      +SK	+4809+01707	Europe/Bratislava
      +SL	+0830-01315	Africa/Freetown
      +SM	+4355+01228	Europe/San_Marino
      +SN	+1440-01726	Africa/Dakar
      +SO	+0204+04522	Africa/Mogadishu
      +SR	+0550-05510	America/Paramaribo
      +SS	+0451+03136	Africa/Juba
      +ST	+0020+00644	Africa/Sao_Tome
      +SV	+1342-08912	America/El_Salvador
      +SX	+180305-0630250	America/Lower_Princes
      +SY	+3330+03618	Asia/Damascus
      +SZ	-2618+03106	Africa/Mbabane
      +TC	+2128-07108	America/Grand_Turk
      +TD	+1207+01503	Africa/Ndjamena
      +TF	-492110+0701303	Indian/Kerguelen
      +TG	+0608+00113	Africa/Lome
      +TH	+1345+10031	Asia/Bangkok
      +TJ	+3835+06848	Asia/Dushanbe
      +TK	-0922-17114	Pacific/Fakaofo
      +TL	-0833+12535	Asia/Dili
      +TM	+3757+05823	Asia/Ashgabat
      +TN	+3648+01011	Africa/Tunis
      +TO	-2110-17510	Pacific/Tongatapu
      +TR	+4101+02858	Europe/Istanbul
      +TT	+1039-06131	America/Port_of_Spain
      +TV	-0831+17913	Pacific/Funafuti
      +TW	+2503+12130	Asia/Taipei
      +TZ	-0648+03917	Africa/Dar_es_Salaam
      +UA	+5026+03031	Europe/Kiev	most locations
      +UA	+4837+02218	Europe/Uzhgorod	Ruthenia
      +UA	+4750+03510	Europe/Zaporozhye	Zaporozh'ye, E Lugansk / Zaporizhia, E Luhansk
      +UA	+4457+03406	Europe/Simferopol	central Crimea
      +UG	+0019+03225	Africa/Kampala
      +UM	+1645-16931	Pacific/Johnston	Johnston Atoll
      +UM	+2813-17722	Pacific/Midway	Midway Islands
      +UM	+1917+16637	Pacific/Wake	Wake Island
      +US	+404251-0740023	America/New_York	Eastern Time
      +US	+421953-0830245	America/Detroit	Eastern Time - Michigan - most locations
      +US	+381515-0854534	America/Kentucky/Louisville	Eastern Time - Kentucky - Louisville area
      +US	+364947-0845057	America/Kentucky/Monticello	Eastern Time - Kentucky - Wayne County
      +US	+394606-0860929	America/Indiana/Indianapolis	Eastern Time - Indiana - most locations
      +US	+384038-0873143	America/Indiana/Vincennes	Eastern Time - Indiana - Daviess, Dubois, Knox & Martin Counties
      +US	+410305-0863611	America/Indiana/Winamac	Eastern Time - Indiana - Pulaski County
      +US	+382232-0862041	America/Indiana/Marengo	Eastern Time - Indiana - Crawford County
      +US	+382931-0871643	America/Indiana/Petersburg	Eastern Time - Indiana - Pike County
      +US	+384452-0850402	America/Indiana/Vevay	Eastern Time - Indiana - Switzerland County
      +US	+415100-0873900	America/Chicago	Central Time
      +US	+375711-0864541	America/Indiana/Tell_City	Central Time - Indiana - Perry County
      +US	+411745-0863730	America/Indiana/Knox	Central Time - Indiana - Starke County
      +US	+450628-0873651	America/Menominee	Central Time - Michigan - Dickinson, Gogebic, Iron & Menominee Counties
      +US	+470659-1011757	America/North_Dakota/Center	Central Time - North Dakota - Oliver County
      +US	+465042-1012439	America/North_Dakota/New_Salem	Central Time - North Dakota - Morton County (except Mandan area)
      +US	+471551-1014640	America/North_Dakota/Beulah	Central Time - North Dakota - Mercer County
      +US	+394421-1045903	America/Denver	Mountain Time
      +US	+433649-1161209	America/Boise	Mountain Time - south Idaho & east Oregon
      +US	+364708-1084111	America/Shiprock	Mountain Time - Navajo
      +US	+332654-1120424	America/Phoenix	Mountain Standard Time - Arizona
      +US	+340308-1181434	America/Los_Angeles	Pacific Time
      +US	+611305-1495401	America/Anchorage	Alaska Time
      +US	+581807-1342511	America/Juneau	Alaska Time - Alaska panhandle
      +US	+571035-1351807	America/Sitka	Alaska Time - southeast Alaska panhandle
      +US	+593249-1394338	America/Yakutat	Alaska Time - Alaska panhandle neck
      +US	+643004-1652423	America/Nome	Alaska Time - west Alaska
      +US	+515248-1763929	America/Adak	Aleutian Islands
      +US	+550737-1313435	America/Metlakatla	Metlakatla Time - Annette Island
      +US	+211825-1575130	Pacific/Honolulu	Hawaii
      +UY	-3453-05611	America/Montevideo
      +UZ	+3940+06648	Asia/Samarkand	west Uzbekistan
      +UZ	+4120+06918	Asia/Tashkent	east Uzbekistan
      +VA	+415408+0122711	Europe/Vatican
      +VC	+1309-06114	America/St_Vincent
      +VE	+1030-06656	America/Caracas
      +VG	+1827-06437	America/Tortola
      +VI	+1821-06456	America/St_Thomas
      +VN	+1045+10640	Asia/Ho_Chi_Minh
      +VU	-1740+16825	Pacific/Efate
      +WF	-1318-17610	Pacific/Wallis
      +WS	-1350-17144	Pacific/Apia
      +YE	+1245+04512	Asia/Aden
      +YT	-1247+04514	Indian/Mayotte
      +ZA	-2615+02800	Africa/Johannesburg
      +ZM	-1525+02817	Africa/Lusaka
      +ZW	-1750+03103	Africa/Harare
      diff --git a/jdk/test/sun/util/calendar/zi/tzdata_jdk/gmt b/jdk/test/sun/util/calendar/zi/tzdata_jdk/gmt
      new file mode 100644
      index 00000000000..0be31797d7f
      --- /dev/null
      +++ b/jdk/test/sun/util/calendar/zi/tzdata_jdk/gmt
      @@ -0,0 +1,27 @@
      +#
      +# Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
      +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      +#
      +# This code is free software; you can redistribute it and/or modify it
      +# under the terms of the GNU General Public License version 2 only, as
      +# published by the Free Software Foundation.  Oracle designates this
      +# particular file as subject to the "Classpath" exception as provided
      +# by Oracle in the LICENSE file that accompanied this code.
      +#
      +# This code is distributed in the hope that it will be useful, but WITHOUT
      +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      +# version 2 for more details (a copy is included in the LICENSE file that
      +# accompanied this code).
      +#
      +# You should have received a copy of the GNU General Public License version
      +# 2 along with this work; if not, write to the Free Software Foundation,
      +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      +#
      +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      +# or visit www.oracle.com if you need additional information or have any
      +# questions.
      +#
      +
      +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
      +Zone	GMT		0:00	-	GMT
      diff --git a/jdk/test/sun/util/calendar/zi/tzdata_jdk/jdk11_backward b/jdk/test/sun/util/calendar/zi/tzdata_jdk/jdk11_backward
      new file mode 100644
      index 00000000000..4869516f8dc
      --- /dev/null
      +++ b/jdk/test/sun/util/calendar/zi/tzdata_jdk/jdk11_backward
      @@ -0,0 +1,80 @@
      +#
      +# Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
      +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      +#
      +# This code is free software; you can redistribute it and/or modify it
      +# under the terms of the GNU General Public License version 2 only, as
      +# published by the Free Software Foundation.  Oracle designates this
      +# particular file as subject to the "Classpath" exception as provided
      +# by Oracle in the LICENSE file that accompanied this code.
      +#
      +# This code is distributed in the hope that it will be useful, but WITHOUT
      +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      +# version 2 for more details (a copy is included in the LICENSE file that
      +# accompanied this code).
      +#
      +# You should have received a copy of the GNU General Public License version
      +# 2 along with this work; if not, write to the Free Software Foundation,
      +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      +#
      +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      +# or visit www.oracle.com if you need additional information or have any
      +# questions.
      +#
      +# JDK 1.1.x compatible time zone IDs
      +#
      +
      +Link Australia/Darwin ACT
      +Link Australia/Sydney AET
      +Link America/Argentina/Buenos_Aires AGT
      +Link Africa/Cairo ART
      +Link America/Anchorage AST
      +Link America/Sao_Paulo BET
      +Link Asia/Dhaka BST
      +Link Africa/Harare CAT
      +Link America/St_Johns CNT
      +Link America/Chicago CST
      +Link Asia/Shanghai CTT
      +Link Africa/Addis_Ababa EAT
      +Link Europe/Paris ECT
      +Link America/New_York EST
      +Link Pacific/Honolulu HST
      +Link America/Indianapolis IET
      +Link Asia/Calcutta IST
      +Link Asia/Tokyo JST
      +Link Pacific/Apia MIT
      +Link America/Denver MST
      +Link Asia/Yerevan NET
      +Link Pacific/Auckland NST
      +Link Asia/Karachi PLT
      +Link America/Phoenix PNT
      +Link America/Puerto_Rico PRT
      +Link America/Los_Angeles PST
      +Link Pacific/Guadalcanal SST
      +Link Asia/Saigon VST
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	SystemV	min	1973	-	Apr	lastSun	2:00	1:00	D
      +Rule	SystemV	min	1973	-	Oct	lastSun	2:00	0	S
      +Rule	SystemV	1974	only	-	Jan	6	2:00	1:00	D
      +Rule	SystemV	1974	only	-	Nov	lastSun	2:00	0	S
      +Rule	SystemV	1975	only	-	Feb	23	2:00	1:00	D
      +Rule	SystemV	1975	only	-	Oct	lastSun	2:00	0	S
      +Rule	SystemV	1976	max	-	Apr	lastSun	2:00	1:00	D
      +Rule	SystemV	1976	max	-	Oct	lastSun	2:00	0	S
      +
      +# Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
      +Zone	SystemV/AST4ADT	-4:00	SystemV		A%sT
      +Zone	SystemV/EST5EDT	-5:00	SystemV		E%sT
      +Zone	SystemV/CST6CDT	-6:00	SystemV		C%sT
      +Zone	SystemV/MST7MDT	-7:00	SystemV		M%sT
      +Zone	SystemV/PST8PDT	-8:00	SystemV		P%sT
      +Zone	SystemV/YST9YDT	-9:00	SystemV		Y%sT
      +Zone	SystemV/AST4	-4:00	-		AST
      +Zone	SystemV/EST5	-5:00	-		EST
      +Zone	SystemV/CST6	-6:00	-		CST
      +Zone	SystemV/MST7	-7:00	-		MST
      +Zone	SystemV/PST8	-8:00	-		PST
      +Zone	SystemV/YST9	-9:00	-		YST
      +Zone	SystemV/HST10	-10:00	-		HST
      diff --git a/jdk/test/sun/util/calendar/zi/tzdata_jdk/jdk11_full_backward b/jdk/test/sun/util/calendar/zi/tzdata_jdk/jdk11_full_backward
      new file mode 100644
      index 00000000000..321180aa100
      --- /dev/null
      +++ b/jdk/test/sun/util/calendar/zi/tzdata_jdk/jdk11_full_backward
      @@ -0,0 +1,93 @@
      +#
      +# Copyright (c) 2001, 2006, Oracle and/or its affiliates. All rights reserved.
      +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      +#
      +# This code is free software; you can redistribute it and/or modify it
      +# under the terms of the GNU General Public License version 2 only, as
      +# published by the Free Software Foundation.  Oracle designates this
      +# particular file as subject to the "Classpath" exception as provided
      +# by Oracle in the LICENSE file that accompanied this code.
      +#
      +# This code is distributed in the hope that it will be useful, but WITHOUT
      +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      +# version 2 for more details (a copy is included in the LICENSE file that
      +# accompanied this code).
      +#
      +# You should have received a copy of the GNU General Public License version
      +# 2 along with this work; if not, write to the Free Software Foundation,
      +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      +#
      +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      +# or visit www.oracle.com if you need additional information or have any
      +# questions.
      +#
      +# JDK 1.1.x compatible time zone IDs
      +#
      +
      +Link Australia/Darwin ACT
      +Link Australia/Sydney AET
      +Link America/Argentina/Buenos_Aires AGT
      +Link Africa/Cairo ART
      +Link America/Anchorage AST
      +Link America/Sao_Paulo BET
      +Link Asia/Dhaka BST
      +Link Africa/Harare CAT
      +Link America/St_Johns CNT
      +Link America/Chicago CST
      +Link Asia/Shanghai CTT
      +Link Africa/Addis_Ababa EAT
      +Link Europe/Paris ECT
      +Link America/New_York EST
      +Link Pacific/Honolulu HST
      +Link America/Indiana/Indianapolis IET
      +Link Asia/Calcutta IST
      +Link Asia/Tokyo JST
      +Link Pacific/Apia MIT
      +Link America/Denver MST
      +Link Asia/Yerevan NET
      +Link Pacific/Auckland NST
      +Link Asia/Karachi PLT
      +Link America/Phoenix PNT
      +Link America/Puerto_Rico PRT
      +Link America/Los_Angeles PST
      +Link Pacific/Guadalcanal SST
      +Link Asia/Saigon VST
      +
      +# The follwong link is required to generate JDK 1.2.x and 1.3.x
      +# compatible zones. In the Olson public source, MET is defined as
      +# GMT+1:00 with the C-Eur rules. In JDK, MET is defined as an alias
      +# of Asia/Tehran. This line must be removed if a full set of Olson
      +# zones is generated. Otherwise, MET appears twice in the
      +# ZoneInfoMappings.IDs table.
      +Link Asia/Tehran MET
      +
      +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
      +Rule	SystemV	min	1973	-	Apr	lastSun	2:00	1:00	D
      +Rule	SystemV	min	1973	-	Oct	lastSun	2:00	0	S
      +Rule	SystemV	1974	only	-	Jan	6	2:00	1:00	D
      +Rule	SystemV	1974	only	-	Nov	lastSun	2:00	0	S
      +Rule	SystemV	1975	only	-	Feb	23	2:00	1:00	D
      +Rule	SystemV	1975	only	-	Oct	lastSun	2:00	0	S
      +Rule	SystemV	1976	max	-	Apr	lastSun	2:00	1:00	D
      +Rule	SystemV	1976	max	-	Oct	lastSun	2:00	0	S
      +
      +# Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
      +Zone	SystemV/AST4ADT	-4:00	SystemV		A%sT
      +Zone	SystemV/EST5EDT	-5:00	SystemV		E%sT
      +Zone	SystemV/CST6CDT	-6:00	SystemV		C%sT
      +Zone	SystemV/MST7MDT	-7:00	SystemV		M%sT
      +Zone	SystemV/PST8PDT	-8:00	SystemV		P%sT
      +Zone	SystemV/YST9YDT	-9:00	SystemV		Y%sT
      +Zone	SystemV/AST4	-4:00	-		AST
      +Zone	SystemV/EST5	-5:00	-		EST
      +Zone	SystemV/CST6	-6:00	-		CST
      +Zone	SystemV/MST7	-7:00	-		MST
      +Zone	SystemV/PST8	-8:00	-		PST
      +Zone	SystemV/YST9	-9:00	-		YST
      +Zone	SystemV/HST10	-10:00	-		HST
      +
      +#
      +# For the UTC change in Mustang
      +#
      +Link GMT UTC
      diff --git a/jdk/test/tools/launcher/Arrrghs.java b/jdk/test/tools/launcher/Arrrghs.java
      index 9bf9f21b465..cf0dfbf7410 100644
      --- a/jdk/test/tools/launcher/Arrrghs.java
      +++ b/jdk/test/tools/launcher/Arrrghs.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
      @@ -309,6 +309,7 @@ public class Arrrghs extends TestHelper {
               checkArgumentParsing("../../*", "../../*");
               checkArgumentParsing("..\\..\\", "..\\..\\");
               checkArgumentParsing("../../", "../../");
      +        checkArgumentParsing("a b\\ c", "a", "b\\", "c");
           }
       
           private void initEmptyDir(File emptyDir) throws IOException {
      diff --git a/jdk/test/tools/launcher/VersionCheck.java b/jdk/test/tools/launcher/VersionCheck.java
      index c30ef424011..11f65cb2e9a 100644
      --- a/jdk/test/tools/launcher/VersionCheck.java
      +++ b/jdk/test/tools/launcher/VersionCheck.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
      @@ -42,6 +42,7 @@ public class VersionCheck extends TestHelper {
           // tools that do not accept -J-option
           static final String[] BLACKLIST_JOPTION = {
               "controlpanel",
      +        "jabswitch",
               "java-rmi",
               "java-rmi.cgi",
               "java",
      diff --git a/jdk/test/tools/pack200/InstructionTests.java b/jdk/test/tools/pack200/InstructionTests.java
      new file mode 100644
      index 00000000000..ce92c0ed558
      --- /dev/null
      +++ b/jdk/test/tools/pack200/InstructionTests.java
      @@ -0,0 +1,99 @@
      +/*
      + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
      + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      + *
      + * This code is free software; you can redistribute it and/or modify it
      + * under the terms of the GNU General Public License version 2 only, as
      + * published by the Free Software Foundation.
      + *
      + * This code is distributed in the hope that it will be useful, but WITHOUT
      + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      + * version 2 for more details (a copy is included in the LICENSE file that
      + * accompanied this code).
      + *
      + * You should have received a copy of the GNU General Public License version
      + * 2 along with this work; if not, write to the Free Software Foundation,
      + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      + *
      + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      + * or visit www.oracle.com if you need additional information or have any
      + * questions.
      + */
      +import java.io.File;
      +import java.nio.charset.Charset;
      +import java.nio.file.Files;
      +import java.util.ArrayList;
      +import java.util.List;
      +import static java.nio.file.StandardOpenOption.*;
      +import java.util.regex.Pattern;
      +
      +/*
      + * @test
      + * @bug 8003549
      + * @summary tests class files instruction formats introduced in JSR-335
      + * @compile -XDignore.symbol.file Utils.java InstructionTests.java
      + * @run main InstructionTests
      + * @author ksrini
      + */
      +public class InstructionTests {
      +    public static void main(String... args) throws Exception {
      +        testInvokeOpCodes();
      +    }
      +    /*
      +     * the following should produce invokestatic and invokespecial
      +     * on InterfaceMethodRefs vs. MethodRefs, packer/unpacker should work
      +     */
      +    static void testInvokeOpCodes() throws Exception {
      +        List scratch = new ArrayList<>();
      +        final String fname = "A";
      +        String javaFileName = fname + Utils.JAVA_FILE_EXT;
      +        scratch.add("interface IntIterator {");
      +        scratch.add("    default void forEach(){}");
      +        scratch.add("    static void next() {}");
      +        scratch.add("}");
      +        scratch.add("class A implements IntIterator {");
      +        scratch.add("public void forEach(Object o){");
      +        scratch.add("IntIterator.super.forEach();");
      +        scratch.add("IntIterator.next();");
      +        scratch.add("}");
      +        scratch.add("}");
      +        File cwd = new File(".");
      +        File javaFile = new File(cwd, javaFileName);
      +        Files.write(javaFile.toPath(), scratch, Charset.defaultCharset(),
      +                CREATE, TRUNCATE_EXISTING);
      +
      +        // make sure we have -g so that we  compare LVT and LNT entries
      +        Utils.compiler("-g", javaFile.getName());
      +
      +        // jar the file up
      +        File testjarFile = new File(cwd, "test" + Utils.JAR_FILE_EXT);
      +        Utils.jar("cvf", testjarFile.getName(), ".");
      +
      +        // pack using --repack
      +        File outjarFile = new File(cwd, "out" + Utils.JAR_FILE_EXT);
      +        scratch.clear();
      +        scratch.add(Utils.getPack200Cmd());
      +        scratch.add("-J-ea");
      +        scratch.add("-J-esa");
      +        scratch.add("--repack");
      +        scratch.add(outjarFile.getName());
      +        scratch.add(testjarFile.getName());
      +        List output = Utils.runExec(scratch);
      +        // TODO remove this when we get bc escapes working correctly
      +        // this test anyhow would  fail  at that time
      +        findString("WARNING: Passing.*" + fname + Utils.CLASS_FILE_EXT,
      +                        output);
      +
      +        Utils.doCompareVerify(testjarFile, outjarFile);
      +    }
      +
      +    static boolean findString(String str, List list) {
      +        Pattern p = Pattern.compile(str);
      +        for (String x : list) {
      +            if (p.matcher(x).matches())
      +                return true;
      +        }
      +        throw new RuntimeException("Error: " + str + " not found in output");
      +    }
      +}
      diff --git a/jdk/test/tools/pack200/Pack200Test.java b/jdk/test/tools/pack200/Pack200Test.java
      index 476ece18216..d897bf86824 100644
      --- a/jdk/test/tools/pack200/Pack200Test.java
      +++ b/jdk/test/tools/pack200/Pack200Test.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      @@ -30,7 +30,7 @@ import java.util.jar.*;
       
        /*
         * @test
      -  * @bug 6521334 6712743
      +  * @bug 6521334 6712743 8007902
         * @summary check for memory leaks, test general packer/unpacker functionality\
         *          using native and java unpackers
         * @compile -XDignore.symbol.file Utils.java Pack200Test.java
      diff --git a/jdk/test/tools/pack200/pack200-verifier/data/golden.jar b/jdk/test/tools/pack200/pack200-verifier/data/golden.jar
      index 913fe14340e..511cc0f43ab 100644
      Binary files a/jdk/test/tools/pack200/pack200-verifier/data/golden.jar and b/jdk/test/tools/pack200/pack200-verifier/data/golden.jar differ
      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 177849872a9..db7d0465777 100644
      --- a/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java
      +++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java
      @@ -57,8 +57,10 @@ 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;
      +import com.sun.tools.classfile.RuntimeInvisibleTypeAnnotations_attribute;
       import com.sun.tools.classfile.RuntimeVisibleAnnotations_attribute;
       import com.sun.tools.classfile.RuntimeVisibleParameterAnnotations_attribute;
      +import com.sun.tools.classfile.RuntimeVisibleTypeAnnotations_attribute;
       import com.sun.tools.classfile.Signature_attribute;
       import com.sun.tools.classfile.SourceDebugExtension_attribute;
       import com.sun.tools.classfile.SourceFile_attribute;
      @@ -1214,6 +1216,21 @@ class AttributeVisitor implements Attribute.Visitor {
               p.add(e);
               return null;
           }
      +
      +    /*
      +     * TODO
      +     * add these two for now to keep the compiler happy, we will implement
      +     * these along with the JSR-308 changes.
      +     */
      +    @Override
      +    public Element visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute rvta, Element p) {
      +        throw new UnsupportedOperationException("Not supported yet.");
      +    }
      +
      +    @Override
      +    public Element visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute rita, Element p) {
      +        throw new UnsupportedOperationException("Not supported yet.");
      +    }
       }
       
       class StackMapVisitor implements StackMapTable_attribute.stack_map_frame.Visitor {
      diff --git a/langtools/.hgtags b/langtools/.hgtags
      index f4fbd85e67d..788268b7d8a 100644
      --- a/langtools/.hgtags
      +++ b/langtools/.hgtags
      @@ -196,3 +196,5 @@ d7360bf35ee1f40ff78c2e83a22b5446ee464346 jdk8-b69
       6f0986ed9b7e11d6eb06618f27e20b18f19fb797 jdk8-b72
       8d0baee36c7184d55c80354b45704c37d6b7ac79 jdk8-b73
       56c97aff46bb577b8668874154c24115a7e8a3e8 jdk8-b74
      +c2e11e2ec4a3682513e566849e5562f31ded8c65 jdk8-b75
      +e81839b3233792415daaab051698edc6067f1a16 jdk8-b76
      diff --git a/langtools/make/Makefile-classic b/langtools/make/Makefile-classic
      index f0693b7216b..c253ee8949b 100644
      --- a/langtools/make/Makefile-classic
      +++ b/langtools/make/Makefile-classic
      @@ -241,6 +241,7 @@ JAVAC_DIRS = \
       	javax/annotation/processing \
       	javax/lang/model \
       	javax/tools \
      +        jdk/ \
       	com/sun/source \
       	com/sun/tools/javac 
       
      diff --git a/langtools/make/build.properties b/langtools/make/build.properties
      index 72ae8793c24..7fd5ffcb371 100644
      --- a/langtools/make/build.properties
      +++ b/langtools/make/build.properties
      @@ -116,6 +116,7 @@ javac.includes = \
               javax/annotation/processing/ \
               javax/lang/model/ \
               javax/tools/ \
      +        jdk/ \
               com/sun/source/ \
               com/sun/tools/javac/ \
               com/sun/tools/doclint/
      diff --git a/langtools/makefiles/BuildLangtools.gmk b/langtools/makefiles/BuildLangtools.gmk
      index 833c8654442..cd96a601e00 100644
      --- a/langtools/makefiles/BuildLangtools.gmk
      +++ b/langtools/makefiles/BuildLangtools.gmk
      @@ -112,23 +112,7 @@ ifeq ($(PROPS_ARE_CREATED),yes)
               $(eval $(call SetupArchive,ARCHIVE_BOOTSTRAP_JAVAC,$(BUILD_BOOTSTRAP_LANGTOOLS),\
       		SRCS:=$(LANGTOOLS_OUTPUTDIR)/btclasses/bootstrap,\
       		JAR:=$(LANGTOOLS_OUTPUTDIR)/dist/bootstrap/lib/javac.jar,\
      -		JARMAIN:=com.sun.tools.javac.Main))
      -
      -        $(eval $(call SetupArchive,ARCHIVE_BOOTSTRAP_JAVAH,$(BUILD_BOOTSTRAP_LANGTOOLS),\
      -		SRCS:=$(LANGTOOLS_OUTPUTDIR)/btclasses/bootstrap,\
      -		JAR:=$(LANGTOOLS_OUTPUTDIR)/dist/bootstrap/lib/javah.jar,\
      -		JARMAIN:=com.sun.tools.javah.Main))
      -
      -        $(eval $(call SetupArchive,ARCHIVE_BOOTSTRAP_JAVAP,$(BUILD_BOOTSTRAP_LANGTOOLS),\
      -		SRCS:=$(LANGTOOLS_OUTPUTDIR)/btclasses/bootstrap,\
      -		JAR:=$(LANGTOOLS_OUTPUTDIR)/dist/bootstrap/lib/javap.jar,\
      -		JARMAIN:=com.sun.tools.javap.Main))
      -
      -        $(eval $(call SetupArchive,ARCHIVE_BOOTSTRAP_JAVADOC,$(BUILD_BOOTSTRAP_LANGTOOLS),\
      -		SRCS:=$(LANGTOOLS_OUTPUTDIR)/btclasses/bootstrap,\
      -		JAR:=$(LANGTOOLS_OUTPUTDIR)/dist/bootstrap/lib/javadoc.jar,\
      -		SUFFIXES:=.class $(RESOURCE_SUFFIXES),\
      -		JARMAIN:=com.sun.tools.javadoc.Main))
      +		SUFFIXES:=.class $(RESOURCE_SUFFIXES)))
       
               # GenStubs is used to bootstrap any dependencies from javac to the new JDK that is not 
               # yet built. It is currently not needed but might be again in the future. The following
      @@ -176,7 +160,8 @@ ifeq ($(PROPS_ARE_CREATED),yes)
                       $(eval $(call SetupJavaCompiler,GENERATE_NEWBYTECODE,\
                         JVM:=$(JAVA),\
                         JAVAC:="-Xbootclasspath/p:$(LANGTOOLS_OUTPUTDIR)/dist/bootstrap/lib/javac.jar" \
      -			 -jar $(LANGTOOLS_OUTPUTDIR)/dist/bootstrap/lib/javac.jar,\
      +			 -cp $(LANGTOOLS_OUTPUTDIR)/dist/bootstrap/lib/javac.jar \
      +			 com.sun.tools.javac.Main,\
                         FLAGS:=-XDignore.symbol.file=true -Xlint:all$(COMMA)-deprecation -Werror,\
                         SERVER_DIR:=$(SJAVAC_SERVER_DIR),\
                         SERVER_JVM:=$(SJAVAC_SERVER_JAVA)))
      @@ -201,11 +186,7 @@ ifeq ($(PROPS_ARE_CREATED),yes)
       
                       all: 		$(LANGTOOLS_OUTPUTDIR)/dist/lib/classes.jar \
       				$(LANGTOOLS_OUTPUTDIR)/dist/lib/src.zip \
      -	                 	$(LANGTOOLS_OUTPUTDIR)/dist/bootstrap/lib/javac.jar \
      -				$(LANGTOOLS_OUTPUTDIR)/dist/bootstrap/lib/javah.jar \
      -				$(LANGTOOLS_OUTPUTDIR)/dist/bootstrap/lib/javap.jar \
      -				$(LANGTOOLS_OUTPUTDIR)/dist/bootstrap/lib/javadoc.jar
      -
      +	                 	$(LANGTOOLS_OUTPUTDIR)/dist/bootstrap/lib/javac.jar
       
               endif
       endif
      diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexWriter.java
      index 77d2bae2fe4..c5df5f3413a 100644
      --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexWriter.java
      +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexWriter.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
      @@ -196,10 +196,7 @@ public class PackageIndexWriter extends AbstractPackageIndexWriter {
           protected void addOverviewComment(Content htmltree) {
               if (root.inlineTags().length > 0) {
                   htmltree.addContent(getMarkerAnchor("overview_description"));
      -            HtmlTree div = new HtmlTree(HtmlTag.DIV);
      -            div.addStyle(HtmlStyle.subTitle);
      -            addInlineComment(root, div);
      -            htmltree.addContent(div);
      +            addInlineComment(root, htmltree);
               }
           }
       
      @@ -211,7 +208,7 @@ public class PackageIndexWriter extends AbstractPackageIndexWriter {
            */
           protected void addOverview(Content body) throws IOException {
               HtmlTree div = new HtmlTree(HtmlTag.DIV);
      -        div.addStyle(HtmlStyle.footer);
      +        div.addStyle(HtmlStyle.contentContainer);
               addOverviewComment(div);
               addTagsInfo(root, div);
               body.addContent(div);
      diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java
      index a970da60530..0bc115e1041 100644
      --- a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java
      +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java
      @@ -496,9 +496,9 @@ public abstract class Symbol implements Element {
               return l.toList();
           }
       
      -    public static class DelegatedSymbol extends Symbol {
      -        protected Symbol other;
      -        public DelegatedSymbol(Symbol other) {
      +    public static class DelegatedSymbol extends Symbol {
      +        protected T other;
      +        public DelegatedSymbol(T other) {
                   super(other.kind, other.flags_field, other.name, other.type, other.owner);
                   this.other = other;
               }
      @@ -532,6 +532,10 @@ public abstract class Symbol implements Element {
               public  R accept(Symbol.Visitor v, P p) {
                   return v.visitSymbol(other, p);
               }
      +
      +        public T getUnderlyingSymbol() {
      +            return other;
      +        }
           }
       
           /** A class for type symbols. Type variables are represented by instances
      diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java
      index bb3e913c33d..fb5202dffcb 100644
      --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java
      +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java
      @@ -570,10 +570,19 @@ public class Lower extends TreeTranslator {
            *  @param flags    The class symbol's flags
            *  @param owner    The class symbol's owner
            */
      -    ClassSymbol makeEmptyClass(long flags, ClassSymbol owner) {
      +    JCClassDecl makeEmptyClass(long flags, ClassSymbol owner) {
      +        return makeEmptyClass(flags, owner, null, true);
      +    }
      +
      +    JCClassDecl makeEmptyClass(long flags, ClassSymbol owner, Name flatname,
      +            boolean addToDefs) {
               // Create class symbol.
               ClassSymbol c = reader.defineClass(names.empty, owner);
      -        c.flatname = chk.localClassName(c);
      +        if (flatname != null) {
      +            c.flatname = flatname;
      +        } else {
      +            c.flatname = chk.localClassName(c);
      +        }
               c.sourcefile = owner.sourcefile;
               c.completer = null;
               c.members_field = new Scope(c);
      @@ -597,9 +606,8 @@ public class Lower extends TreeTranslator {
               cdef.type = c.type;
       
               // Append class definition tree to owner's definitions.
      -        odef.defs = odef.defs.prepend(cdef);
      -
      -        return c;
      +        if (addToDefs) odef.defs = odef.defs.prepend(cdef);
      +        return cdef;
           }
       
       /**************************************************************************
      @@ -706,7 +714,7 @@ public class Lower extends TreeTranslator {
            * and synthethise a class (with makeEmptyClass) if one is not available.
            * However, there is a small possibility that an existing class will not
            * be generated as expected if it is inside a conditional with a constant
      -     * expression. If that is found to be the case, create an empty class here.
      +     * expression. If that is found to be the case, create an empty class tree here.
            */
           private void checkAccessConstructorTags() {
               for (List l = accessConstrTags; l.nonEmpty(); l = l.tail) {
      @@ -714,14 +722,10 @@ public class Lower extends TreeTranslator {
                   if (isTranslatedClassAvailable(c))
                       continue;
                   // Create class definition tree.
      -            JCClassDecl cdef = make.ClassDef(
      -                make.Modifiers(STATIC | SYNTHETIC), names.empty,
      -                List.nil(),
      -                null, List.nil(), List.nil());
      -            cdef.sym = c;
      -            cdef.type = c.type;
      -            // add it to the list of classes to be generated
      -            translated.append(cdef);
      +            JCClassDecl cdec = makeEmptyClass(STATIC | SYNTHETIC,
      +                    c.outermostClass(), c.flatname, false);
      +            swapAccessConstructorTag(c, cdec.sym);
      +            translated.append(cdec);
               }
           }
           // where
      @@ -735,6 +739,19 @@ public class Lower extends TreeTranslator {
               return false;
           }
       
      +    void swapAccessConstructorTag(ClassSymbol oldCTag, ClassSymbol newCTag) {
      +        for (MethodSymbol methodSymbol : accessConstrs.values()) {
      +            Assert.check(methodSymbol.type.hasTag(METHOD));
      +            MethodType oldMethodType =
      +                    (MethodType)methodSymbol.type;
      +            if (oldMethodType.argtypes.head.tsym == oldCTag)
      +                methodSymbol.type =
      +                    types.createMethodTypeWithParameters(oldMethodType,
      +                        oldMethodType.getParameterTypes().tail
      +                            .prepend(newCTag.erasure(types)));
      +        }
      +    }
      +
       /**************************************************************************
        * Access methods
        *************************************************************************/
      @@ -1211,7 +1228,7 @@ public class Lower extends TreeTranslator {
                                                "1");
               ClassSymbol ctag = chk.compiled.get(flatname);
               if (ctag == null)
      -            ctag = makeEmptyClass(STATIC | SYNTHETIC, topClass);
      +            ctag = makeEmptyClass(STATIC | SYNTHETIC, topClass).sym;
               // keep a record of all tags, to verify that all are generated as required
               accessConstrTags = accessConstrTags.prepend(ctag);
               return ctag;
      @@ -1778,7 +1795,7 @@ public class Lower extends TreeTranslator {
                   if (e.sym.kind == TYP &&
                       e.sym.name == names.empty &&
                       (e.sym.flags() & INTERFACE) == 0) return (ClassSymbol) e.sym;
      -        return makeEmptyClass(STATIC | SYNTHETIC, clazz);
      +        return makeEmptyClass(STATIC | SYNTHETIC, clazz).sym;
           }
       
           /** Return symbol for "class$" method. If there is no method definition
      diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java
      index b48701ee37c..8c1e3204c5d 100644
      --- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java
      +++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java
      @@ -482,10 +482,8 @@ public class ClassWriter extends ClassFile {
               while (i < pool.pp) {
                   Object value = pool.pool[i];
                   Assert.checkNonNull(value);
      -            if (value instanceof Method)
      -                value = ((Method)value).m;
      -            else if (value instanceof Variable)
      -                value = ((Variable)value).v;
      +            if (value instanceof Method || value instanceof Variable)
      +                value = ((DelegatedSymbol)value).getUnderlyingSymbol();
       
                   if (value instanceof MethodSymbol) {
                       MethodSymbol m = (MethodSymbol)value;
      diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/Pool.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/Pool.java
      index 08a5d57d87f..553cc3ae1a1 100644
      --- a/langtools/src/share/classes/com/sun/tools/javac/jvm/Pool.java
      +++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/Pool.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
      @@ -140,23 +140,23 @@ public class Pool {
               return n == null ? -1 : n.intValue();
           }
       
      -    static class Method extends DelegatedSymbol {
      -        MethodSymbol m;
      +    static class Method extends DelegatedSymbol {
               UniqueType uniqueType;
               Method(MethodSymbol m, Types types) {
                   super(m);
      -            this.m = m;
                   this.uniqueType = new UniqueType(m.type, types);
               }
      -        public boolean equals(Object other) {
      -            if (!(other instanceof Method)) return false;
      -            MethodSymbol o = ((Method)other).m;
      +        public boolean equals(Object any) {
      +            if (!(any instanceof Method)) return false;
      +            MethodSymbol o = ((Method)any).other;
      +            MethodSymbol m = this.other;
                   return
                       o.name == m.name &&
                       o.owner == m.owner &&
      -                ((Method)other).uniqueType.equals(uniqueType);
      +                ((Method)any).uniqueType.equals(uniqueType);
               }
               public int hashCode() {
      +            MethodSymbol m = this.other;
                   return
                       m.name.hashCode() * 33 +
                       m.owner.hashCode() * 9 +
      @@ -173,21 +173,21 @@ public class Pool {
               }
       
               @Override
      -        public boolean equals(Object other) {
      -            if (!super.equals(other)) return false;
      -            if (!(other instanceof DynamicMethod)) return false;
      -            DynamicMethodSymbol dm1 = (DynamicMethodSymbol)m;
      -            DynamicMethodSymbol dm2 = (DynamicMethodSymbol)((DynamicMethod)other).m;
      +        public boolean equals(Object any) {
      +            if (!super.equals(any)) return false;
      +            if (!(any instanceof DynamicMethod)) return false;
      +            DynamicMethodSymbol dm1 = (DynamicMethodSymbol)other;
      +            DynamicMethodSymbol dm2 = (DynamicMethodSymbol)((DynamicMethod)any).other;
                   return dm1.bsm == dm2.bsm &&
                               dm1.bsmKind == dm2.bsmKind &&
                               Arrays.equals(uniqueStaticArgs,
      -                            ((DynamicMethod)other).uniqueStaticArgs);
      +                            ((DynamicMethod)any).uniqueStaticArgs);
               }
       
               @Override
               public int hashCode() {
                   int hash = super.hashCode();
      -            DynamicMethodSymbol dm = (DynamicMethodSymbol)m;
      +            DynamicMethodSymbol dm = (DynamicMethodSymbol)other;
                   hash += dm.bsmKind * 7 +
                           dm.bsm.hashCode() * 11;
                   for (int i = 0; i < dm.staticArgs.length; i++) {
      @@ -209,23 +209,23 @@ public class Pool {
               }
           }
       
      -    static class Variable extends DelegatedSymbol {
      -        VarSymbol v;
      +    static class Variable extends DelegatedSymbol {
               UniqueType uniqueType;
               Variable(VarSymbol v, Types types) {
                   super(v);
      -            this.v = v;
                   this.uniqueType = new UniqueType(v.type, types);
               }
      -        public boolean equals(Object other) {
      -            if (!(other instanceof Variable)) return false;
      -            VarSymbol o = ((Variable)other).v;
      +        public boolean equals(Object any) {
      +            if (!(any instanceof Variable)) return false;
      +            VarSymbol o = ((Variable)any).other;
      +            VarSymbol v = other;
                   return
                       o.name == v.name &&
                       o.owner == v.owner &&
      -                ((Variable)other).uniqueType.equals(uniqueType);
      +                ((Variable)any).uniqueType.equals(uniqueType);
               }
               public int hashCode() {
      +            VarSymbol v = other;
                   return
                       v.name.hashCode() * 33 +
                       v.owner.hashCode() * 9 +
      diff --git a/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java b/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java
      index 5bf9d276872..fc4786a2a60 100644
      --- a/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java
      +++ b/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java
      @@ -629,6 +629,8 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
                   if (!taskListener.isEmpty()) {
                       TaskEvent e = new TaskEvent(TaskEvent.Kind.PARSE, filename);
                       taskListener.started(e);
      +                keepComments = true;
      +                genEndPos = true;
                   }
                   Parser parser = parserFactory.newParser(content, keepComments(), genEndPos, lineDebugInfo);
                   tree = parser.parseCompilationUnit();
      diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/DocCommentParser.java b/langtools/src/share/classes/com/sun/tools/javac/parser/DocCommentParser.java
      index 989e42d066e..bbc4d81d5c7 100644
      --- a/langtools/src/share/classes/com/sun/tools/javac/parser/DocCommentParser.java
      +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/DocCommentParser.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
      @@ -279,13 +279,7 @@ public class DocCommentParser {
               try {
                   nextChar();
                   if (isIdentifierStart(ch)) {
      -                int namePos = bp;
      -                nextChar();
      -                while (isIdentifierPart(ch))
      -                    nextChar();
      -                int nameLen = bp - namePos;
      -
      -                Name name = names.fromChars(buf, namePos, nameLen);
      +                Name name = readIdentifier();
                       TagParser tp = tagParsers.get(name);
                       if (tp == null) {
                           List content = blockContent();
      @@ -334,14 +328,9 @@ public class DocCommentParser {
               try {
                   nextChar();
                   if (isIdentifierStart(ch)) {
      -                int namePos = bp;
      -                nextChar();
      -                while (isIdentifierPart(ch))
      -                    nextChar();
      -                int nameLen = bp - namePos;
      +                Name name = readIdentifier();
                       skipWhitespace();
       
      -                Name name = names.fromChars(buf, namePos, nameLen);
                       TagParser tp = tagParsers.get(name);
                       if (tp == null) {
                           DCTree text = inlineText();
      @@ -575,10 +564,8 @@ public class DocCommentParser {
               int pos = bp;
       
               if (isJavaIdentifierStart(ch)) {
      -            nextChar();
      -            while (isJavaIdentifierPart(ch))
      -                nextChar();
      -            return m.at(pos).Identifier(names.fromChars(buf, pos, bp - pos));
      +            Name name = readJavaIdentifier();
      +            return m.at(pos).Identifier(name);
               }
       
               throw new ParseException("dc.identifier.expected");
      @@ -703,39 +690,36 @@ public class DocCommentParser {
           protected DCTree entity() {
               int p = bp;
               nextChar();
      -        int namep = bp;
      +        Name name = null;
               boolean checkSemi = false;
               if (ch == '#') {
      +            int namep = bp;
                   nextChar();
                   if (isDecimalDigit(ch)) {
                       nextChar();
                       while (isDecimalDigit(ch))
                           nextChar();
      -                checkSemi = true;
      +                name = names.fromChars(buf, namep, bp - namep);
                   } else if (ch == 'x' || ch == 'X') {
                       nextChar();
                       if (isHexDigit(ch)) {
                           nextChar();
                           while (isHexDigit(ch))
                               nextChar();
      -                    checkSemi = true;
      +                    name = names.fromChars(buf, namep, bp - namep);
                       }
                   }
               } else if (isIdentifierStart(ch)) {
      -            nextChar();
      -            while (isIdentifierPart(ch))
      -                nextChar();
      -            checkSemi = true;
      +            name = readIdentifier();
               }
       
      -        if (checkSemi && ch == ';') {
      +        if (name == null)
      +            return erroneous("dc.bad.entity", p);
      +        else {
      +            if (ch != ';')
      +                return erroneous("dc.missing.semicolon", p);
                   nextChar();
      -            return m.at(p).Entity(names.fromChars(buf, namep, bp - namep - 1));
      -        } else {
      -            String code = checkSemi
      -                    ? "dc.missing.semicolon"
      -                    : "dc.bad.entity";
      -            return erroneous(code, p);
      +            return m.at(p).Entity(name);
               }
           }
       
      @@ -747,11 +731,7 @@ public class DocCommentParser {
               int p = bp;
               nextChar();
               if (isIdentifierStart(ch)) {
      -            int namePos = bp;
      -            nextChar();
      -            while (isIdentifierPart(ch))
      -                nextChar();
      -            int nameLen = bp - namePos;
      +            Name name = readIdentifier();
                   List attrs = htmlAttrs();
                   if (attrs != null) {
                       boolean selfClosing = false;
      @@ -761,22 +741,16 @@ public class DocCommentParser {
                       }
                       if (ch == '>') {
                           nextChar();
      -                    Name name = names.fromChars(buf, namePos, nameLen);
                           return m.at(p).StartElement(name, attrs, selfClosing);
                       }
                   }
               } else if (ch == '/') {
                   nextChar();
                   if (isIdentifierStart(ch)) {
      -                int namePos = bp;
      -                nextChar();
      -                while (isIdentifierPart(ch))
      -                    nextChar();
      -                int nameLen = bp - namePos;
      +                Name name = readIdentifier();
                       skipWhitespace();
                       if (ch == '>') {
                           nextChar();
      -                    Name name = names.fromChars(buf, namePos, nameLen);
                           return m.at(p).EndElement(name);
                       }
                   }
      @@ -822,10 +796,7 @@ public class DocCommentParser {
               loop:
               while (isIdentifierStart(ch)) {
                   int namePos = bp;
      -            nextChar();
      -            while (isIdentifierPart(ch))
      -                nextChar();
      -            int nameLen = bp - namePos;
      +            Name name = readIdentifier();
                   skipWhitespace();
                   List value = null;
                   ValueKind vkind = ValueKind.EMPTY;
      @@ -862,7 +833,6 @@ public class DocCommentParser {
                       skipWhitespace();
                       value = v.toList();
                   }
      -            Name name = names.fromChars(buf, namePos, nameLen);
                   DCAttribute attr = m.at(namePos).Attribute(name, vkind, value);
                   attrs.add(attr);
               }
      @@ -897,7 +867,7 @@ public class DocCommentParser {
           protected DCErroneous erroneous(String code, int pos) {
               int i = bp - 1;
               loop:
      -        while (i > 0) {
      +        while (i > pos) {
                   switch (buf[i]) {
                       case '\f': case '\n': case '\r':
                           newline = true;
      @@ -926,16 +896,24 @@ public class DocCommentParser {
               return Character.isUnicodeIdentifierStart(ch);
           }
       
      -    protected boolean isIdentifierPart(char ch) {
      -        return Character.isUnicodeIdentifierPart(ch);
      +    protected Name readIdentifier() {
      +        int start = bp;
      +        nextChar();
      +        while (bp < buflen && Character.isUnicodeIdentifierPart(ch))
      +            nextChar();
      +        return names.fromChars(buf, start, bp - start);
           }
       
           protected boolean isJavaIdentifierStart(char ch) {
               return Character.isJavaIdentifierStart(ch);
           }
       
      -    protected boolean isJavaIdentifierPart(char ch) {
      -        return Character.isJavaIdentifierPart(ch);
      +    protected Name readJavaIdentifier() {
      +        int start = bp;
      +        nextChar();
      +        while (bp < buflen && Character.isJavaIdentifierPart(ch))
      +            nextChar();
      +        return names.fromChars(buf, start, bp - start);
           }
       
           protected boolean isDecimalDigit(char ch) {
      diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/JavadocTokenizer.java b/langtools/src/share/classes/com/sun/tools/javac/parser/JavadocTokenizer.java
      index d52a62ef704..847a42b17c8 100644
      --- a/langtools/src/share/classes/com/sun/tools/javac/parser/JavadocTokenizer.java
      +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavadocTokenizer.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      @@ -236,7 +236,7 @@ public class JavadocTokenizer extends JavaTokenizer {
                   // relative to the best match found in the array.
                   if (pos == Position.NOPOS)
                       return Position.NOPOS;
      -            if (pos < 0 || pos >= docComment.length())
      +            if (pos < 0 || pos > docComment.length())
                       throw new StringIndexOutOfBoundsException(String.valueOf(pos));
                   if (docPosns == null)
                       return Position.NOPOS;
      diff --git a/langtools/src/share/classes/com/sun/tools/javac/tree/DCTree.java b/langtools/src/share/classes/com/sun/tools/javac/tree/DCTree.java
      index e49cabe0838..c2ca23caf4b 100644
      --- a/langtools/src/share/classes/com/sun/tools/javac/tree/DCTree.java
      +++ b/langtools/src/share/classes/com/sun/tools/javac/tree/DCTree.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
      @@ -119,7 +119,7 @@ public abstract class DCTree implements DocTree {
       
           }
       
      -    public static abstract class DCBlockTag extends DCTree implements InlineTagTree {
      +    public static abstract class DCBlockTag extends DCTree implements BlockTagTree {
               public String getTagName() {
                   return getKind().tagName;
               }
      @@ -169,7 +169,7 @@ public abstract class DCTree implements DocTree {
               }
           }
       
      -    public static class DCAuthor extends DCInlineTag implements AuthorTree {
      +    public static class DCAuthor extends DCBlockTag implements AuthorTree {
               public final List name;
       
               DCAuthor(List name) {
      @@ -640,7 +640,7 @@ public abstract class DCTree implements DocTree {
               }
           }
       
      -    public static class DCSince extends DCInlineTag implements SinceTree {
      +    public static class DCSince extends DCBlockTag implements SinceTree {
               public final List body;
       
               DCSince(List body) {
      diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/api/JavadocTool.java b/langtools/src/share/classes/com/sun/tools/javadoc/api/JavadocTool.java
      index a8aa2786577..5df92804aa1 100644
      --- a/langtools/src/share/classes/com/sun/tools/javadoc/api/JavadocTool.java
      +++ b/langtools/src/share/classes/com/sun/tools/javadoc/api/JavadocTool.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
      @@ -139,12 +139,13 @@ public class JavadocTool implements DocumentationTool {
       
           @Override
           public int run(InputStream in, OutputStream out, OutputStream err, String... arguments) {
      -        PrintWriter err_pw = new PrintWriter(err, true);
      -        PrintWriter out_pw = new PrintWriter(out);
      +        PrintWriter err_pw = new PrintWriter(err == null ? System.err : err, true);
      +        PrintWriter out_pw = new PrintWriter(out == null ? System.out : out);
               try {
                   String standardDocletName = "com.sun.tools.doclets.standard.Standard";
      +            ClassLoader cl = getClass().getClassLoader();
                   return com.sun.tools.javadoc.Main.execute(
      -                    "javadoc", err_pw, err_pw, out_pw, standardDocletName, arguments);
      +                    "javadoc", err_pw, err_pw, out_pw, standardDocletName, cl, arguments);
               } finally {
                   err_pw.flush();
                   out_pw.flush();
      diff --git a/langtools/src/share/classes/jdk/Supported.java b/langtools/src/share/classes/jdk/Supported.java
      new file mode 100644
      index 00000000000..f5bf1c54ba6
      --- /dev/null
      +++ b/langtools/src/share/classes/jdk/Supported.java
      @@ -0,0 +1,53 @@
      +/*
      + * 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 jdk;
      +
      +import java.lang.annotation.*;
      +
      +/**
      +  * Indicates whether or not a JDK specific type or package is a
      +  * supported part of the JDK.
      +  *
      +  * This annotation should only be applied to types and packages
      +  * outside of the Java SE namespaces of {@code java.*} and
      +  * {@code javax.*} packages.  For example, certain portions of {@code
      +  * com.sun.*} are official parts of the JDK meant to be generally
      +  * usable while other portions of {@code com.sun.*} are not.  This
      +  * annotation type allows those portions to be easily and
      +  * programmaticly distinguished.
      +  *
      +  * @since 1.8
      +  */
      +@Documented
      +@Retention(RetentionPolicy.RUNTIME)
      +@Target({ElementType.TYPE, ElementType.PACKAGE})
      +@Supported
      +public @interface Supported {
      +    /**
      +     * Whether or not this package or type is a supported part of the JDK.
      +     */
      +    boolean value() default true;
      +}
      diff --git a/langtools/test/tools/doclint/EndWithIdentifierTest.java b/langtools/test/tools/doclint/EndWithIdentifierTest.java
      new file mode 100644
      index 00000000000..afd20a3353c
      --- /dev/null
      +++ b/langtools/test/tools/doclint/EndWithIdentifierTest.java
      @@ -0,0 +1,32 @@
      +/*
      + * @test /nodynamiccopyright/
      + * @bug 8007096
      + * @summary DocLint parsing problems with some comments
      + * @build DocLintTester
      + * @run main DocLintTester -Xmsgs:-html EndWithIdentifierTest.java
      + * @run main DocLintTester -Xmsgs -ref EndWithIdentifierTest.out EndWithIdentifierTest.java
      + * @author jlahoda
      + */
      +
      +/**@deprecated*/
      +public class EndWithIdentifierTest {
      +
      +    /**{@link*/
      +    private void unfinishedInlineTagName() {}
      +
      +    /**@see List*/
      +    private void endsWithIdentifier() {}
      +
      +    /**&*/
      +    private void entityName() {}
      +
      +    /** { }
       @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
       @interface RTA { }
       
      -@ContainerFor(RTA.class)
       @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
       @interface RTAs {
           RTA[] value();
      diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/newlocations/Varargs.java b/langtools/test/tools/javac/annotations/typeAnnotations/newlocations/Varargs.java
      index d28c108a6c6..e0c3082ebb6 100644
      --- a/langtools/test/tools/javac/annotations/typeAnnotations/newlocations/Varargs.java
      +++ b/langtools/test/tools/javac/annotations/typeAnnotations/newlocations/Varargs.java
      @@ -1,6 +1,5 @@
      -
       /*
      - * Copyright (c) 2008 Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      @@ -22,8 +21,6 @@
        * questions.
        */
       
      -import java.lang.annotation.*;
      -
       /*
        * @test
        * @summary test acceptance of varargs annotations
      @@ -31,6 +28,8 @@ import java.lang.annotation.*;
        * @compile Varargs.java
        */
       
      +import java.lang.annotation.*;
      +
       @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
       @interface A {}
       
      diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/packageanno/PackageProcessor.java b/langtools/test/tools/javac/annotations/typeAnnotations/packageanno/PackageProcessor.java
      index 4f0d56522f9..02e20ad3b19 100644
      --- a/langtools/test/tools/javac/annotations/typeAnnotations/packageanno/PackageProcessor.java
      +++ b/langtools/test/tools/javac/annotations/typeAnnotations/packageanno/PackageProcessor.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2009 Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/packageanno/mypackage/Anno.java b/langtools/test/tools/javac/annotations/typeAnnotations/packageanno/mypackage/Anno.java
      index 25f05341fbc..901cb6c9850 100644
      --- a/langtools/test/tools/javac/annotations/typeAnnotations/packageanno/mypackage/Anno.java
      +++ b/langtools/test/tools/javac/annotations/typeAnnotations/packageanno/mypackage/Anno.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2009 Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/packageanno/mypackage/MyClass.java b/langtools/test/tools/javac/annotations/typeAnnotations/packageanno/mypackage/MyClass.java
      index e955ffc825e..98f9e433880 100644
      --- a/langtools/test/tools/javac/annotations/typeAnnotations/packageanno/mypackage/MyClass.java
      +++ b/langtools/test/tools/javac/annotations/typeAnnotations/packageanno/mypackage/MyClass.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2009 Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/packageanno/mypackage/package-info.java b/langtools/test/tools/javac/annotations/typeAnnotations/packageanno/mypackage/package-info.java
      index f80bd8afa53..bcd7fb672e8 100644
      --- a/langtools/test/tools/javac/annotations/typeAnnotations/packageanno/mypackage/package-info.java
      +++ b/langtools/test/tools/javac/annotations/typeAnnotations/packageanno/mypackage/package-info.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2009 Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/ClassExtends.java b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/ClassExtends.java
      index 5fd9751879a..4d5f2db0a12 100644
      --- a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/ClassExtends.java
      +++ b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/ClassExtends.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2009 Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/ClassTypeParam.java b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/ClassTypeParam.java
      index 0d82706984f..2fca8089824 100644
      --- a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/ClassTypeParam.java
      +++ b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/ClassTypeParam.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2009 Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Constructors.java b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Constructors.java
      index 2ad8b31badc..bbdcba3f319 100644
      --- a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Constructors.java
      +++ b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Constructors.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2012 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
      diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Driver.java b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Driver.java
      index 5986fa95de8..042b7b0b1db 100644
      --- a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Driver.java
      +++ b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Driver.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2009 Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      @@ -241,8 +241,8 @@ public class Driver {
               sb.append("\n@Repeatable(RTAs.class) @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @interface RTA {}");
               sb.append("\n@Repeatable(RTBs.class) @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @interface RTB {}");
       
      -        sb.append("\n@ContainerFor(RTA.class) @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @interface RTAs { RTA[] value(); }");
      -        sb.append("\n@ContainerFor(RTB.class) @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @interface RTBs { RTB[] value(); }");
      +        sb.append("\n@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @interface RTAs { RTA[] value(); }");
      +        sb.append("\n@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @interface RTBs { RTB[] value(); }");
       
               sb.append("\n@Target(value={ElementType.TYPE,ElementType.FIELD,ElementType.METHOD,ElementType.PARAMETER,ElementType.CONSTRUCTOR,ElementType.LOCAL_VARIABLE})");
               sb.append("\n@interface Decl {}");
      diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/ExceptionParameters.java b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/ExceptionParameters.java
      index 70ca77aa560..a7c2818cf5d 100644
      --- a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/ExceptionParameters.java
      +++ b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/ExceptionParameters.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2013 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
      diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Fields.java b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Fields.java
      index d352fa79b23..91bc6496a98 100644
      --- a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Fields.java
      +++ b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Fields.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2009 Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/FromSpecification.java b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/FromSpecification.java
      index e8e111d8c30..c3006390219 100644
      --- a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/FromSpecification.java
      +++ b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/FromSpecification.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2012 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
      diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/MethodParameters.java b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/MethodParameters.java
      index cfe36ed9ae2..c23636c2f82 100644
      --- a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/MethodParameters.java
      +++ b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/MethodParameters.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2009 Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/MethodReceivers.java b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/MethodReceivers.java
      index c834d0cef56..dc19f8d12fd 100644
      --- a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/MethodReceivers.java
      +++ b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/MethodReceivers.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2009 Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/MethodReturns.java b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/MethodReturns.java
      index 07fc9f23742..b6946817666 100644
      --- a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/MethodReturns.java
      +++ b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/MethodReturns.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2009 Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/MethodThrows.java b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/MethodThrows.java
      index 155e4bbfb71..457ca5b0a10 100644
      --- a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/MethodThrows.java
      +++ b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/MethodThrows.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2009 Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/MethodTypeParam.java b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/MethodTypeParam.java
      index 4b7b521904f..5798eaa9b49 100644
      --- a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/MethodTypeParam.java
      +++ b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/MethodTypeParam.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2009 Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/MultiCatch.java b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/MultiCatch.java
      index d62d52ff158..69694e453be 100644
      --- a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/MultiCatch.java
      +++ b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/MultiCatch.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2013 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
      diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/NestedTypes.java b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/NestedTypes.java
      index 476e23f05ce..e98df7bd0c2 100644
      --- a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/NestedTypes.java
      +++ b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/NestedTypes.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2012 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
      diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/NewObjects.java b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/NewObjects.java
      index b56dbb74d23..fb3e3f55eeb 100644
      --- a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/NewObjects.java
      +++ b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/NewObjects.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2009 Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/ReferenceInfoUtil.java b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/ReferenceInfoUtil.java
      index 0a94ee07de3..33ae4edaabf 100644
      --- a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/ReferenceInfoUtil.java
      +++ b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/ReferenceInfoUtil.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2009 Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/RepeatingTypeAnnotations.java b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/RepeatingTypeAnnotations.java
      index 2755b4871c7..22982ae4d27 100644
      --- a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/RepeatingTypeAnnotations.java
      +++ b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/RepeatingTypeAnnotations.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2012 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
      diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/TypeCasts.java b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/TypeCasts.java
      index c77dcdc5857..84e5e01b358 100644
      --- a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/TypeCasts.java
      +++ b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/TypeCasts.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2009 Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/TypeTests.java b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/TypeTests.java
      index 5aa07b88db6..3b319197afe 100644
      --- a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/TypeTests.java
      +++ b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/TypeTests.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2009 Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      diff --git a/langtools/test/tools/javac/api/8007344/Test.java b/langtools/test/tools/javac/api/8007344/Test.java
      new file mode 100644
      index 00000000000..871faa70617
      --- /dev/null
      +++ b/langtools/test/tools/javac/api/8007344/Test.java
      @@ -0,0 +1,227 @@
      +/*
      + * 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
      + * 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 8007344
      + * @summary javac may not make tree end positions and/or doc comments
      + *          available to processors and listeners
      + * @library /tools/javac/lib
      + * @build JavacTestingAbstractProcessor
      + * @run main Test
      + */
      +
      +import java.io.File;
      +import java.io.PrintWriter;
      +import java.util.Arrays;
      +import java.util.Set;
      +
      +import javax.annotation.processing.RoundEnvironment;
      +import javax.lang.model.element.Element;
      +import javax.lang.model.element.TypeElement;
      +import javax.tools.JavaFileObject;
      +import javax.tools.StandardJavaFileManager;
      +
      +import com.sun.source.doctree.DocCommentTree;
      +import com.sun.source.tree.*;
      +import com.sun.source.util.DocTrees;
      +import com.sun.source.util.JavacTask;
      +import com.sun.source.util.SourcePositions;
      +import com.sun.source.util.TaskEvent;
      +import com.sun.source.util.TaskListener;
      +import com.sun.source.util.TreePath;
      +import com.sun.source.util.TreePathScanner;
      +import com.sun.tools.javac.api.JavacTool;
      +import com.sun.tools.javac.tree.JCTree;
      +import com.sun.tools.javac.tree.Pretty;
      +import com.sun.tools.javac.util.Position;
      +
      +/** Doc comment: Test */
      +public class Test {
      +    public static final int EXPECT_DOC_COMMENTS = 3;
      +
      +    /** Doc comment: main */
      +    public static void main(String... args) throws Exception {
      +        PrintWriter out = new PrintWriter(System.err);
      +        try {
      +            new Test(out).run();
      +        } finally {
      +            out.flush();
      +        }
      +    }
      +
      +    PrintWriter out;
      +    int errors;
      +
      +    Test(PrintWriter out) {
      +        this.out = out;
      +    }
      +
      +    /** Doc comment: run */
      +    void run() throws Exception {
      +        File testSrc = new File(System.getProperty("test.src"));
      +        File thisFile = new File(testSrc, getClass().getName() + ".java");
      +        JavacTool javac = JavacTool.create();
      +        StandardJavaFileManager fm = javac.getStandardFileManager(null, null, null);
      +        Iterable fos = fm.getJavaFileObjects(thisFile);
      +        testAnnoProcessor(javac, fm, fos, out, EXPECT_DOC_COMMENTS);
      +        testTaskListener(javac, fm, fos, out, EXPECT_DOC_COMMENTS);
      +
      +        if (errors > 0)
      +            throw new Exception(errors + " errors occurred");
      +    }
      +
      +    void testAnnoProcessor(JavacTool javac, StandardJavaFileManager fm,
      +            Iterable files, PrintWriter out,
      +            int expectedDocComments) {
      +        out.println("Test annotation processor");
      +        JavacTask task = javac.getTask(out, fm, null, null, null, files);
      +        AnnoProc ap = new AnnoProc(DocTrees.instance(task));
      +        task.setProcessors(Arrays.asList(ap));
      +        task.call();
      +        ap.checker.checkDocComments(expectedDocComments);
      +    }
      +
      +    void testTaskListener(JavacTool javac, StandardJavaFileManager fm,
      +            Iterable files, PrintWriter out,
      +            int expectedDocComments) {
      +        out.println("Test task listener");
      +        JavacTask task = javac.getTask(out, fm, null, null, null, files);
      +        TaskListnr tl = new TaskListnr(DocTrees.instance(task));
      +        task.addTaskListener(tl);
      +        task.call();
      +        tl.checker.checkDocComments(expectedDocComments);
      +    }
      +
      +    void error(String msg) {
      +        out.println("Error: " + msg);
      +        errors++;
      +    }
      +
      +    class AnnoProc extends JavacTestingAbstractProcessor {
      +        Checker checker;
      +
      +        AnnoProc(DocTrees trees) {
      +            checker = new Checker(trees);
      +        }
      +
      +        @Override
      +        public boolean process(Set annotations, RoundEnvironment roundEnv) {
      +            for (Element e : roundEnv.getRootElements()) {
      +                checker.scan(checker.trees.getPath(e), null);
      +            }
      +            return true;
      +        }
      +    }
      +
      +    class TaskListnr implements TaskListener {
      +        Checker checker;
      +
      +        TaskListnr(DocTrees trees) {
      +            checker = new Checker(trees);
      +        }
      +
      +        public void started(TaskEvent e) {
      +            if (e.getKind() == TaskEvent.Kind.ANALYZE)
      +                checker.scan(new TreePath(e.getCompilationUnit()), null);
      +        }
      +
      +        public void finished(TaskEvent e) {
      +        }
      +    }
      +
      +    class Checker extends TreePathScanner {
      +        DocTrees trees;
      +        SourcePositions srcPosns;
      +
      +        int docComments = 0;
      +
      +        Checker(DocTrees trees) {
      +            this.trees = trees;
      +            srcPosns = trees.getSourcePositions();
      +        }
      +
      +        @Override
      +        public Void scan(Tree tree, Void ignore) {
      +            if (tree != null) {
      +                switch (tree.getKind()) {
      +                    // HACK: Workaround 8007350
      +                    // Some tree nodes do not have endpos set
      +                    case ASSIGNMENT:
      +                    case BLOCK:
      +                    case IDENTIFIER:
      +                    case METHOD_INVOCATION:
      +                        break;
      +
      +                    default:
      +                        checkEndPos(getCurrentPath().getCompilationUnit(), tree);
      +                }
      +            }
      +            return super.scan(tree, ignore);
      +        }
      +
      +        @Override
      +        public Void visitClass(ClassTree tree, Void ignore) {
      +            checkComment();
      +            return super.visitClass(tree, ignore);
      +        }
      +
      +        @Override
      +        public Void visitMethod(MethodTree tree, Void ignore) {
      +            checkComment();
      +            return super.visitMethod(tree, ignore);
      +        }
      +
      +        @Override
      +        public Void visitVariable(VariableTree tree, Void ignore) {
      +            checkComment();
      +            return super.visitVariable(tree, ignore);
      +        }
      +
      +        void checkComment() {
      +            DocCommentTree dc = trees.getDocCommentTree(getCurrentPath());
      +            if (dc != null) {
      +                out.println("comment: " + dc.toString().replaceAll("\\s+", " "));
      +                docComments++;
      +            }
      +        }
      +
      +        void checkEndPos(CompilationUnitTree unit, Tree tree) {
      +            long sp = srcPosns.getStartPosition(unit, tree);
      +            long ep = srcPosns.getEndPosition(unit, tree);
      +            if (sp >= 0 && ep == Position.NOPOS) {
      +                error("endpos not set for " + tree.getKind()
      +                        + " " + Pretty.toSimpleString(((JCTree) tree))
      +                        +", start:" + sp);
      +            }
      +        }
      +
      +        void checkDocComments(int expected) {
      +            if (docComments != expected) {
      +                error("Unexpected number of doc comments received: "
      +                        + docComments + ", expected: " + expected);
      +            }
      +        }
      +
      +    }
      +}
      diff --git a/langtools/test/tools/javac/api/T6306137.java b/langtools/test/tools/javac/api/T6306137.java
      index b961d800e4b..8ccf577b088 100644
      --- a/langtools/test/tools/javac/api/T6306137.java
      +++ b/langtools/test/tools/javac/api/T6306137.java
      @@ -26,9 +26,6 @@
        * @bug     6306137
        * @summary JSR 199: encoding option doesn't affect standard file manager
        * @author  Peter von der Ahé
      - * @ignore
      - *    Need to make the contentCache in JavacFileManager be aware of changes to the encoding.
      - *    Need to propogate -source (and -encoding?) down to the JavacFileManager
        */
       
       import java.io.File;
      diff --git a/langtools/test/tools/javac/defaultMethods/TestNoBridgeOnDefaults.java b/langtools/test/tools/javac/defaultMethods/TestNoBridgeOnDefaults.java
      index a52cfb7240e..328629c51e7 100644
      --- a/langtools/test/tools/javac/defaultMethods/TestNoBridgeOnDefaults.java
      +++ b/langtools/test/tools/javac/defaultMethods/TestNoBridgeOnDefaults.java
      @@ -23,7 +23,6 @@
       
       /*
        * @test
      - * @ignore awaits for VM support
        * @summary  check that javac does not generate bridge methods for defaults
        */
       
      diff --git a/langtools/test/tools/javac/lambda/LambdaCapture06.java b/langtools/test/tools/javac/lambda/LambdaCapture06.java
      index 85a6feb0e23..99a72d26af6 100644
      --- a/langtools/test/tools/javac/lambda/LambdaCapture06.java
      +++ b/langtools/test/tools/javac/lambda/LambdaCapture06.java
      @@ -23,7 +23,6 @@
       
       /*
        * @test
      - * @ignore investigate as to whether code generation fails
        * @bug 8003280
        * @summary Add lambda tests
        *  Compiler crash when local inner class nested inside lambda captures local variables from enclosing scope
      diff --git a/langtools/test/tools/javac/lambda/LambdaExpr15.java b/langtools/test/tools/javac/lambda/LambdaExpr15.java
      index 3b38e8039b6..fd5f4e14bf0 100644
      --- a/langtools/test/tools/javac/lambda/LambdaExpr15.java
      +++ b/langtools/test/tools/javac/lambda/LambdaExpr15.java
      @@ -23,7 +23,6 @@
       
       /*
        * @test
      - * @ignore investigate as to whether code generation fails
        * @bug 8003280
        * @summary Add lambda tests
        *  check that nested inner class in statement lambdas don't get corrupted return statements
      diff --git a/langtools/test/tools/javac/lib/DPrinter.java b/langtools/test/tools/javac/lib/DPrinter.java
      new file mode 100644
      index 00000000000..45d1296cdda
      --- /dev/null
      +++ b/langtools/test/tools/javac/lib/DPrinter.java
      @@ -0,0 +1,1331 @@
      +/*
      + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
      + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      + *
      + * This code is free software; you can redistribute it and/or modify it
      + * under the terms of the GNU General Public License version 2 only, as
      + * published by the Free Software Foundation.
      + *
      + * This code is distributed in the hope that it will be useful, but WITHOUT
      + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      + * version 2 for more details (a copy is included in the LICENSE file that
      + * accompanied this code).
      + *
      + * You should have received a copy of the GNU General Public License version
      + * 2 along with this work; if not, write to the Free Software Foundation,
      + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      + *
      + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      + * or visit www.oracle.com if you need additional information or have any
      + * questions.
      + */
      +
      +import java.io.File;
      +import java.io.IOException;
      +import java.io.PrintWriter;
      +import java.lang.reflect.Field;
      +import java.util.ArrayList;
      +import java.util.Arrays;
      +import java.util.Collection;
      +import java.util.EnumSet;
      +import java.util.HashMap;
      +import java.util.List;
      +import java.util.Locale;
      +import java.util.Map;
      +import java.util.Set;
      +
      +import javax.lang.model.element.Name;
      +import javax.lang.model.element.TypeElement;
      +import javax.tools.FileObject;
      +import javax.tools.JavaCompiler;
      +import javax.tools.JavaFileObject;
      +import javax.tools.StandardJavaFileManager;
      +import javax.tools.StandardLocation;
      +import javax.tools.ToolProvider;
      +
      +import com.sun.source.util.JavacTask;
      +import com.sun.source.util.TaskEvent;
      +import com.sun.source.util.TaskListener;
      +import com.sun.source.util.Trees;
      +import com.sun.tools.javac.api.JavacTrees;
      +import com.sun.tools.javac.code.Annotations;
      +import com.sun.tools.javac.code.Attribute;
      +import com.sun.tools.javac.code.Flags;
      +import com.sun.tools.javac.code.Kinds;
      +import com.sun.tools.javac.code.Printer;
      +import com.sun.tools.javac.code.Scope;
      +import com.sun.tools.javac.code.Scope.CompoundScope;
      +import com.sun.tools.javac.code.Symbol;
      +import com.sun.tools.javac.code.Symbol.*;
      +import com.sun.tools.javac.code.Type;
      +import com.sun.tools.javac.code.Type.*;
      +import com.sun.tools.javac.code.TypeTag;
      +import com.sun.tools.javac.tree.JCTree;
      +import com.sun.tools.javac.tree.JCTree.*;
      +import com.sun.tools.javac.tree.Pretty;
      +import com.sun.tools.javac.tree.TreeInfo;
      +import com.sun.tools.javac.tree.TreeScanner;
      +import com.sun.tools.javac.util.Assert;
      +import com.sun.tools.javac.util.Context;
      +import com.sun.tools.javac.util.Log;
      +
      +
      +/**
      + * Debug printer for javac internals, for when toString() just isn't enough.
      + *
      + * 

      + * The printer provides an API to generate structured views of javac objects, + * such as AST nodes, symbol, types and annotations. Various aspects of the + * output can be configured, such as whether to show nulls, empty lists, or + * a compressed representation of the source code. Visitors are used to walk + * object hierarchies, and can be replaced with custom visitors if the default + * visitors are not flexible enough. + * + *

      + * In general, nodes are printed with an initial line identifying the node + * followed by indented lines for the child nodes. Currently, graphs are + * represented by printing a spanning subtree. + * + *

      + * The printer can be accessed via a simple command-line utility, + * which makes it easy to see the internal representation of source code, + * such as simple test programs, during the compilation pipeline. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + */ + +public class DPrinter { + protected final PrintWriter out; + protected final Trees trees; + protected Printer printer; + protected boolean showEmptyItems = true; + protected boolean showNulls = true; + protected boolean showPositions = false; + protected boolean showSrc; + protected boolean showTreeSymbols; + protected boolean showTreeTypes; + protected int maxSrcLength = 32; + protected Locale locale = Locale.getDefault(); + protected static final String NULL = "#null"; + + // + + public static DPrinter instance(Context context) { + DPrinter dp = context.get(DPrinter.class); + if (dp == null) { + dp = new DPrinter(context); + } + return dp; + + } + + protected DPrinter(Context context) { + context.put(DPrinter.class, this); + out = context.get(Log.outKey); + trees = JavacTrees.instance(context); + } + + public DPrinter(PrintWriter out, Trees trees) { + this.out = out; + this.trees = trees; + } + + public DPrinter emptyItems(boolean showEmptyItems) { + this.showEmptyItems = showEmptyItems; + return this; + } + + public DPrinter nulls(boolean showNulls) { + this.showNulls = showNulls; + return this; + } + + public DPrinter positions(boolean showPositions) { + this.showPositions = showPositions; + return this; + } + + public DPrinter source(boolean showSrc) { + this.showSrc = showSrc; + return this; + } + + public DPrinter source(int maxSrcLength) { + this.showSrc = true; + this.maxSrcLength = maxSrcLength; + return this; + } + + public DPrinter treeSymbols(boolean showTreeSymbols) { + this.showTreeSymbols = showTreeSymbols; + return this; + } + + public DPrinter treeTypes(boolean showTreeTypes) { + this.showTreeTypes = showTreeTypes; + return this; + } + + public DPrinter typeSymbolPrinter(Printer p) { + printer = p; + return this; + } + + // + + // + + protected enum Details { + /** A one-line non-recursive summary */ + SUMMARY, + /** Multi-line, possibly recursive. */ + FULL + }; + + public void printAnnotations(String label, Annotations annotations) { + printAnnotations(label, annotations, Details.FULL); + } + + protected void printAnnotations(String label, Annotations annotations, Details details) { + if (annotations == null) { + printNull(label); + } else { + // no SUMMARY format currently available to use + + // use reflection to get at private fields + Object DECL_NOT_STARTED = getField(null, Annotations.class, "DECL_NOT_STARTED"); + Object DECL_IN_PROGRESS = getField(null, Annotations.class, "DECL_IN_PROGRESS"); + Object attributes = getField(annotations, Annotations.class, "attributes"); + Object type_attributes = getField(annotations, Annotations.class, "type_attributes"); + + if (!showEmptyItems) { + if (attributes instanceof List && ((List) attributes).isEmpty() + && attributes != DECL_NOT_STARTED + && attributes != DECL_IN_PROGRESS + && type_attributes instanceof List && ((List) type_attributes).isEmpty()) + return; + } + + printString(label, hashString(annotations)); + + indent(+1); + if (attributes == DECL_NOT_STARTED) + printString("attributes", "DECL_NOT_STARTED"); + else if (attributes == DECL_IN_PROGRESS) + printString("attributes", "DECL_IN_PROGRESS"); + else if (attributes instanceof List) + printList("attributes", (List) attributes); + else + printObject("attributes", attributes, Details.SUMMARY); + + if (attributes instanceof List) + printList("type_attributes", (List) type_attributes); + else + printObject("type_attributes", type_attributes, Details.SUMMARY); + indent(-1); + } + } + + public void printAttribute(String label, Attribute attr) { + if (attr == null) { + printNull(label); + } else { + printString(label, attr.getClass().getSimpleName()); + + indent(+1); + attr.accept(attrVisitor); + indent(-1); + } + } + + public void printFileObject(String label, FileObject fo) { + if (fo == null) { + printNull(label); + } else { + printString(label, fo.getName()); + } + } + + protected void printImplClass(T item, Class stdImplClass) { + if (item.getClass() != stdImplClass) + printString("impl", item.getClass().getName()); + } + + public void printInt(String label, int i) { + printString(label, String.valueOf(i)); + } + + public void printList(String label, List list) { + if (list == null) { + printNull(label); + } else if (!list.isEmpty() || showEmptyItems) { + printString(label, "[" + list.size() + "]"); + + indent(+1); + int i = 0; + for (Object item: list) { + printObject(String.valueOf(i++), item, Details.FULL); + } + indent(-1); + } + } + + public void printName(String label, Name name) { + if (name == null) { + printNull(label); + } else { + printString(label, name.toString()); + } + } + + public void printNull(String label) { + if (showNulls) + printString(label, NULL); + } + + protected void printObject(String label, Object item, Details details) { + if (item == null) { + printNull(label); + } else if (item instanceof Attribute) { + printAttribute(label, (Attribute) item); + } else if (item instanceof Symbol) { + printSymbol(label, (Symbol) item, details); + } else if (item instanceof Type) { + printType(label, (Type) item, details); + } else if (item instanceof JCTree) { + printTree(label, (JCTree) item); + } else if (item instanceof List) { + printList(label, (List) item); + } else if (item instanceof Name) { + printName(label, (Name) item); + } else { + printString(label, String.valueOf(item)); + } + } + + public void printScope(String label, Scope scope) { + printScope(label, scope, Details.FULL); + } + + public void printScope(String label, Scope scope, Details details) { + if (scope == null) { + printNull(label); + } else { + switch (details) { + case SUMMARY: { + indent(); + out.print(label); + out.print(": ["); + String sep = ""; + for (Symbol sym: scope.getElements()) { + out.print(sep); + out.print(sym.name); + sep = ","; + } + out.println("]"); + break; + } + + case FULL: { + indent(); + out.println(label); + + indent(+1); + printImplClass(scope, Scope.class); + printSymbol("owner", scope.owner, Details.SUMMARY); + printScope("next", scope.next, Details.SUMMARY); + printObject("shared", getField(scope, Scope.class, "shared"), Details.SUMMARY); + if (scope instanceof CompoundScope) { + printObject("subScopes", + getField(scope, CompoundScope.class, "subScopes"), + Details.FULL); + } else { + for (Symbol sym : scope.getElements()) { + printSymbol(sym.name.toString(), sym, Details.SUMMARY); + } + } + indent(-1); + break; + } + } + } + } + + public void printSource(String label, JCTree tree) { + printString(label, Pretty.toSimpleString(tree, maxSrcLength)); + } + + public void printString(String label, String text) { + indent(); + out.print(label); + out.print(": "); + out.print(text); + out.println(); + } + + public void printSymbol(String label, Symbol symbol) { + printSymbol(label, symbol, Details.FULL); + } + + protected void printSymbol(String label, Symbol sym, Details details) { + if (sym == null) { + printNull(label); + } else { + switch (details) { + case SUMMARY: + printString(label, toString(sym)); + break; + + case FULL: + indent(); + out.print(label); + out.println(": " + + info(sym.getClass(), + String.format("0x%x--%s", sym.kind, Kinds.kindName(sym)), + sym.getKind()) + + " " + sym.name + + " " + hashString(sym)); + + indent(+1); + if (showSrc) { + JCTree tree = (JCTree) trees.getTree(sym); + if (tree != null) + printSource("src", tree); + } + printString("flags", String.format("0x%x--%s", + sym.flags_field, Flags.toString(sym.flags_field))); + printObject("completer", sym.completer, Details.SUMMARY); // what if too long? + printSymbol("owner", sym.owner, Details.SUMMARY); + printType("type", sym.type, Details.SUMMARY); + printType("erasure", sym.erasure_field, Details.SUMMARY); + sym.accept(symVisitor, null); + printAnnotations("annotations", sym.annotations, Details.SUMMARY); + indent(-1); + } + } + } + + protected String toString(Symbol sym) { + return (printer != null) ? printer.visit(sym, locale) : String.valueOf(sym); + } + + protected void printTree(String label, JCTree tree) { + if (tree == null) { + printNull(label); + } else { + indent(); + String ext; + try { + ext = tree.getKind().name(); + } catch (Throwable t) { + ext = "n/a"; + } + out.print(label + ": " + info(tree.getClass(), tree.getTag(), ext)); + if (showPositions) { + // We can always get start position, but to get end position + // and/or line+offset, we would need a JCCompilationUnit + out.print(" pos:" + tree.pos); + } + if (showTreeTypes && tree.type != null) + out.print(" type:" + toString(tree.type)); + Symbol sym; + if (showTreeSymbols && (sym = TreeInfo.symbolFor(tree)) != null) + out.print(" sym:" + toString(sym)); + out.println(); + + indent(+1); + if (showSrc) { + indent(); + out.println("src: " + Pretty.toSimpleString(tree, maxSrcLength)); + } + tree.accept(treeVisitor); + indent(-1); + } + } + + public void printType(String label, Type type) { + printType(label, type, Details.FULL); + } + + protected void printType(String label, Type type, Details details) { + if (type == null) + printNull(label); + else { + switch (details) { + case SUMMARY: + printString(label, toString(type)); + break; + + case FULL: + indent(); + out.print(label); + out.println(": " + info(type.getClass(), type.getTag(), type.getKind()) + + " " + hashString(type)); + + indent(+1); + printSymbol("tsym", type.tsym, Details.SUMMARY); + printObject("constValue", type.constValue(), Details.SUMMARY); + type.accept(typeVisitor, null); + indent(-1); + } + } + } + + protected String toString(Type type) { + return (printer != null) ? printer.visit(type, locale) : String.valueOf(type); + } + + protected String hashString(Object obj) { + return String.format("#%x", obj.hashCode()); + } + + protected String info(Class clazz, Object internal, Object external) { + return String.format("%s,%s,%s", clazz.getSimpleName(), internal, external); + } + + private int indent = 0; + + protected void indent() { + for (int i = 0; i < indent; i++) { + out.print(" "); + } + } + + protected void indent(int n) { + indent += n; + } + + protected Object getField(Object o, Class clazz, String name) { + try { + Field f = clazz.getDeclaredField(name); + boolean prev = f.isAccessible(); + f.setAccessible(true); + try { + return f.get(o); + } finally { + f.setAccessible(prev); + } + } catch (ReflectiveOperationException e) { + return e; + } catch (SecurityException e) { + return e; + } + } + + // + + // + + protected JCTree.Visitor treeVisitor = new TreeVisitor(); + + /** + * Default visitor class for JCTree (AST) objects. + */ + public class TreeVisitor extends JCTree.Visitor { + @Override + public void visitTopLevel(JCCompilationUnit tree) { + printList("packageAnnotations", tree.packageAnnotations); + printTree("pid", tree.pid); + printList("defs", tree.defs); + } + + @Override + public void visitImport(JCImport tree) { + printTree("qualid", tree.qualid); + } + + @Override + public void visitClassDef(JCClassDecl tree) { + printName("name", tree.name); + printTree("mods", tree.mods); + printList("typarams", tree.typarams); + printTree("extending", tree.extending); + printList("implementing", tree.implementing); + printList("defs", tree.defs); + } + + @Override + public void visitMethodDef(JCMethodDecl tree) { + printName("name", tree.name); + printTree("mods", tree.mods); + printTree("restype", tree.restype); + printList("typarams", tree.typarams); + printTree("recvparam", tree.recvparam); + printList("params", tree.params); + printList("thrown", tree.thrown); + printTree("defaultValue", tree.defaultValue); + printTree("body", tree.body); + } + + @Override + public void visitVarDef(JCVariableDecl tree) { + printName("name", tree.name); + printTree("mods", tree.mods); + printTree("vartype", tree.vartype); + printTree("init", tree.init); + } + + @Override + public void visitSkip(JCSkip tree) { + } + + @Override + public void visitBlock(JCBlock tree) { + printList("stats", tree.stats); + } + + @Override + public void visitDoLoop(JCDoWhileLoop tree) { + printTree("body", tree.body); + printTree("cond", tree.cond); + } + + @Override + public void visitWhileLoop(JCWhileLoop tree) { + printTree("cond", tree.cond); + printTree("body", tree.body); + } + + @Override + public void visitForLoop(JCForLoop tree) { + printList("init", tree.init); + printTree("cond", tree.cond); + printList("step", tree.step); + printTree("body", tree.body); + } + + @Override + public void visitForeachLoop(JCEnhancedForLoop tree) { + printTree("var", tree.var); + printTree("expr", tree.expr); + printTree("body", tree.body); + } + + @Override + public void visitLabelled(JCLabeledStatement tree) { + printTree("body", tree.body); + } + + @Override + public void visitSwitch(JCSwitch tree) { + printTree("selector", tree.selector); + printList("cases", tree.cases); + } + + @Override + public void visitCase(JCCase tree) { + printTree("pat", tree.pat); + printList("stats", tree.stats); + } + + @Override + public void visitSynchronized(JCSynchronized tree) { + printTree("lock", tree.lock); + printTree("body", tree.body); + } + + @Override + public void visitTry(JCTry tree) { + printList("resources", tree.resources); + printTree("body", tree.body); + printList("catchers", tree.catchers); + printTree("finalizer", tree.finalizer); + } + + @Override + public void visitCatch(JCCatch tree) { + printTree("param", tree.param); + printTree("body", tree.body); + } + + @Override + public void visitConditional(JCConditional tree) { + printTree("cond", tree.cond); + printTree("truepart", tree.truepart); + printTree("falsepart", tree.falsepart); + } + + @Override + public void visitIf(JCIf tree) { + printTree("cond", tree.cond); + printTree("thenpart", tree.thenpart); + printTree("elsepart", tree.elsepart); + } + + @Override + public void visitExec(JCExpressionStatement tree) { + printTree("expr", tree.expr); + } + + @Override + public void visitBreak(JCBreak tree) { + printName("label", tree.label); + } + + @Override + public void visitContinue(JCContinue tree) { + printName("label", tree.label); + } + + @Override + public void visitReturn(JCReturn tree) { + printTree("expr", tree.expr); + } + + @Override + public void visitThrow(JCThrow tree) { + printTree("expr", tree.expr); + } + + @Override + public void visitAssert(JCAssert tree) { + printTree("cond", tree.cond); + printTree("detail", tree.detail); + } + + @Override + public void visitApply(JCMethodInvocation tree) { + printList("typeargs", tree.typeargs); + printTree("meth", tree.meth); + printList("args", tree.args); + } + + @Override + public void visitNewClass(JCNewClass tree) { + printTree("encl", tree.encl); + printList("typeargs", tree.typeargs); + printTree("clazz", tree.clazz); + printList("args", tree.args); + printTree("def", tree.def); + } + + @Override + public void visitNewArray(JCNewArray tree) { + printList("annotations", tree.annotations); + printTree("elemtype", tree.elemtype); + printList("dims", tree.dims); + printList("dimAnnotations", tree.dimAnnotations); + printList("elems", tree.elems); + } + + @Override + public void visitLambda(JCLambda tree) { + printTree("body", tree.body); + printList("params", tree.params); + } + + @Override + public void visitParens(JCParens tree) { + printTree("expr", tree.expr); + } + + @Override + public void visitAssign(JCAssign tree) { + printTree("lhs", tree.lhs); + printTree("rhs", tree.rhs); + } + + @Override + public void visitAssignop(JCAssignOp tree) { + printTree("lhs", tree.lhs); + printTree("rhs", tree.rhs); + } + + @Override + public void visitUnary(JCUnary tree) { + printTree("arg", tree.arg); + } + + @Override + public void visitBinary(JCBinary tree) { + printTree("lhs", tree.lhs); + printTree("rhs", tree.rhs); + } + + @Override + public void visitTypeCast(JCTypeCast tree) { + printTree("clazz", tree.clazz); + printTree("expr", tree.expr); + } + + @Override + public void visitTypeTest(JCInstanceOf tree) { + printTree("expr", tree.expr); + printTree("clazz", tree.clazz); + } + + @Override + public void visitIndexed(JCArrayAccess tree) { + printTree("indexed", tree.indexed); + printTree("index", tree.index); + } + + @Override + public void visitSelect(JCFieldAccess tree) { + printTree("selected", tree.selected); + } + + @Override + public void visitReference(JCMemberReference tree) { + printTree("expr", tree.expr); + printList("typeargs", tree.typeargs); + } + + @Override + public void visitIdent(JCIdent tree) { + printName("name", tree.name); + } + + @Override + public void visitLiteral(JCLiteral tree) { + printString("value", Pretty.toSimpleString(tree, 32)); + } + + @Override + public void visitTypeIdent(JCPrimitiveTypeTree tree) { + printString("typetag", tree.typetag.name()); + } + + @Override + public void visitTypeArray(JCArrayTypeTree tree) { + printTree("elemtype", tree.elemtype); + } + + @Override + public void visitTypeApply(JCTypeApply tree) { + printTree("clazz", tree.clazz); + printList("arguments", tree.arguments); + } + + @Override + public void visitTypeUnion(JCTypeUnion tree) { + printList("alternatives", tree.alternatives); + } + + @Override + public void visitTypeIntersection(JCTypeIntersection tree) { + printList("bounds", tree.bounds); + } + + @Override + public void visitTypeParameter(JCTypeParameter tree) { + printName("name", tree.name); + printList("annotations", tree.annotations); + printList("bounds", tree.bounds); + } + + @Override + public void visitWildcard(JCWildcard tree) { + printTree("kind", tree.kind); + printTree("inner", tree.inner); + } + + @Override + public void visitTypeBoundKind(TypeBoundKind tree) { + printString("kind", tree.kind.name()); + } + + @Override + public void visitModifiers(JCModifiers tree) { + printList("annotations", tree.annotations); + printString("flags", String.valueOf(Flags.asFlagSet(tree.flags))); + } + + @Override + public void visitAnnotation(JCAnnotation tree) { + printTree("annotationType", tree.annotationType); + printList("args", tree.args); + } + + @Override + public void visitAnnotatedType(JCAnnotatedType tree) { + printList("annotations", tree.annotations); + printTree("underlyingType", tree.underlyingType); + } + + @Override + public void visitErroneous(JCErroneous tree) { + printList("errs", tree.errs); + } + + @Override + public void visitLetExpr(LetExpr tree) { + printList("defs", tree.defs); + printTree("expr", tree.expr); + } + + @Override + public void visitTree(JCTree tree) { + Assert.error(); + } + } + + // + + // + + protected Symbol.Visitor symVisitor = new SymbolVisitor(); + + /** + * Default visitor class for Symbol objects. + * Note: each visitXYZ method ends by calling the corresponding + * visit method for its superclass. + */ + class SymbolVisitor implements Symbol.Visitor { + @Override + public Void visitClassSymbol(ClassSymbol sym, Void ignore) { + printName("fullname", sym.fullname); + printName("flatname", sym.flatname); + printScope("members", sym.members_field); + printFileObject("sourcefile", sym.sourcefile); + printFileObject("classfile", sym.classfile); + // trans-local? + // pool? + return visitTypeSymbol(sym, null); + } + + @Override + public Void visitMethodSymbol(MethodSymbol sym, Void ignore) { + // code + printList("params", sym.params); + printList("savedParameterNames", sym.savedParameterNames); + return visitSymbol(sym, null); + } + + @Override + public Void visitPackageSymbol(PackageSymbol sym, Void ignore) { + printName("fullname", sym.fullname); + printScope("members", sym.members_field); + printSymbol("package-info", sym.package_info, Details.SUMMARY); + return visitTypeSymbol(sym, null); + } + + @Override + public Void visitOperatorSymbol(OperatorSymbol sym, Void ignore) { + printInt("opcode", sym.opcode); + return visitMethodSymbol(sym, null); + } + + @Override + public Void visitVarSymbol(VarSymbol sym, Void ignore) { + printInt("pos", sym.pos); + printInt("adm", sym.adr); + // data is a private field, and the standard accessors may + // mutate it as part of lazy evaluation. Therefore, use + // reflection to get the raw data. + printObject("data", getField(sym, VarSymbol.class, "data"), Details.SUMMARY); + return visitSymbol(sym, null); + } + + @Override + public Void visitTypeSymbol(TypeSymbol sym, Void ignore) { + return visitSymbol(sym, null); + } + + @Override + public Void visitSymbol(Symbol sym, Void ignore) { + return null; + } + } + + // + + // + + protected Type.Visitor typeVisitor = new TypeVisitor(); + + /** + * Default visitor class for Type objects. + * Note: each visitXYZ method ends by calling the corresponding + * visit method for its superclass. + */ + public class TypeVisitor implements Type.Visitor { + public Void visitAnnotatedType(AnnotatedType type, Void ignore) { + printList("typeAnnotations", type.typeAnnotations); + printType("underlyingType", type.underlyingType, Details.FULL); + return visitType(type, null); + } + + public Void visitArrayType(ArrayType type, Void ignore) { + printType("elemType", type.elemtype, Details.FULL); + return visitType(type, null); + } + + public Void visitCapturedType(CapturedType type, Void ignore) { + printType("wildcard", type.wildcard, Details.FULL); + return visitTypeVar(type, null); + } + + public Void visitClassType(ClassType type, Void ignore) { + printType("outer", type.getEnclosingType(), Details.SUMMARY); + printList("typarams", type.typarams_field); + printList("allparams", type.allparams_field); + printType("supertype", type.supertype_field, Details.SUMMARY); + printList("interfaces", type.interfaces_field); + printList("allinterfaces", type.all_interfaces_field); + return visitType(type, null); + } + + public Void visitErrorType(ErrorType type, Void ignore) { + printType("originalType", type.getOriginalType(), Details.FULL); + return visitClassType(type, null); + } + + public Void visitForAll(ForAll type, Void ignore) { + printList("tvars", type.tvars); + return visitDelegatedType(type); + } + + public Void visitMethodType(MethodType type, Void ignore) { + printList("argtypes", type.argtypes); + printType("restype", type.restype, Details.FULL); + printList("thrown", type.thrown); + return visitType(type, null); + } + + public Void visitPackageType(PackageType type, Void ignore) { + return visitType(type, null); + } + + public Void visitTypeVar(TypeVar type, Void ignore) { + // For TypeVars (and not subtypes), the bound should always be + // null or bot. So, only print the bound for subtypes of TypeVar, + // or if the bound is (erroneously) not null or bot. + if (!type.hasTag(TypeTag.TYPEVAR) + || !(type.bound == null || type.bound.hasTag(TypeTag.BOT))) { + printType("bound", type.bound, Details.FULL); + } + printType("lower", type.lower, Details.FULL); + return visitType(type, null); + } + + public Void visitUndetVar(UndetVar type, Void ignore) { + for (UndetVar.InferenceBound ib: UndetVar.InferenceBound.values()) + printList("bounds." + ib, type.getBounds(ib)); + printType("inst", type.inst, Details.SUMMARY); + return visitDelegatedType(type); + } + + public Void visitWildcardType(WildcardType type, Void ignore) { + printType("type", type.type, Details.SUMMARY); + printString("kind", type.kind.name()); + printType("bound", type.bound, Details.SUMMARY); + return visitType(type, null); + } + + protected Void visitDelegatedType(DelegatedType type) { + printType("qtype", type.qtype, Details.FULL); + return visitType(type, null); + } + + public Void visitType(Type type, Void ignore) { + return null; + } + } + + // + + // + + protected Attribute.Visitor attrVisitor = new AttributeVisitor(); + + /** + * Default visitor class for Attribute (annotation) objects. + */ + public class AttributeVisitor implements Attribute.Visitor { + + public void visitConstant(Attribute.Constant a) { + printObject("value", a.value, Details.SUMMARY); + visitAttribute(a); + } + + public void visitClass(Attribute.Class a) { + printObject("classType", a.classType, Details.SUMMARY); + visitAttribute(a); + } + + public void visitCompound(Attribute.Compound a) { + if (a instanceof Attribute.TypeCompound) { + Attribute.TypeCompound ta = (Attribute.TypeCompound) a; + // consider a custom printer? + printObject("position", ta.position, Details.SUMMARY); + } + printObject("synthesized", a.isSynthesized(), Details.SUMMARY); + printList("values", a.values); + visitAttribute(a); + } + + public void visitArray(Attribute.Array a) { + printList("values", Arrays.asList(a.values)); + visitAttribute(a); + } + + public void visitEnum(Attribute.Enum a) { + printSymbol("value", a.value, Details.SUMMARY); + visitAttribute(a); + } + + public void visitError(Attribute.Error a) { + visitAttribute(a); + } + + public void visitAttribute(Attribute a) { + printType("type", a.type, Details.SUMMARY); + } + + } + // + + // + + /** + * Utility class to invoke DPrinter from the command line. + */ + static class Main { + public static void main(String... args) throws IOException { + Main m = new Main(); + PrintWriter out = new PrintWriter(System.out); + try { + if (args.length == 0) + m.usage(out); + else + m.run(out, args); + } finally { + out.flush(); + } + } + + void usage(PrintWriter out) { + out.println("Usage:"); + out.println(" java " + Main.class.getName() + " mode [options] [javac-options]"); + out.print("where mode is one of: "); + String sep = ""; + for (Handler h: getHandlers().values()) { + out.print(sep); + out.print(h.name); + sep = ", "; + } + out.println(); + out.println("and where options include:"); + out.println(" -before PARSE|ENTER|ANALYZE|GENERATE|ANNOTATION_PROCESSING|ANNOTATION_PROCESSING_ROUND"); + out.println(" -after PARSE|ENTER|ANALYZE|GENERATE|ANNOTATION_PROCESSING|ANNOTATION_PROCESSING_ROUND"); + out.println(" -showPositions"); + out.println(" -showSource"); + out.println(" -showTreeSymbols"); + out.println(" -showTreeTypes"); + out.println(" -hideEmptyItems"); + out.println(" -hideNulls"); + } + + void run(PrintWriter out, String... args) throws IOException { + JavaCompiler c = ToolProvider.getSystemJavaCompiler(); + StandardJavaFileManager fm = c.getStandardFileManager(null, null, null); + + // DPrinter options + final Set before = EnumSet.noneOf(TaskEvent.Kind.class); + final Set after = EnumSet.noneOf(TaskEvent.Kind.class); + boolean showPositions = false; + boolean showSource = false; + boolean showTreeSymbols = false; + boolean showTreeTypes = false; + boolean showEmptyItems = true; + boolean showNulls = true; + + // javac options + Collection options = new ArrayList(); + Collection files = new ArrayList(); + String classpath = null; + String classoutdir = null; + + final Handler h = getHandlers().get(args[0]); + if (h == null) + throw new IllegalArgumentException(args[0]); + + for (int i = 1; i < args.length; i++) { + String arg = args[i]; + if (arg.equals("-before") && i + 1 < args.length) { + before.add(getKind(args[++i])); + } else if (arg.equals("-after") && i + 1 < args.length) { + after.add(getKind(args[++i])); + } else if (arg.equals("-showPositions")) { + showPositions = true; + } else if (arg.equals("-showSource")) { + showSource = true; + } else if (arg.equals("-showTreeSymbols")) { + showTreeSymbols = true; + } else if (arg.equals("-showTreeTypes")) { + showTreeTypes = true; + } else if (arg.equals("-hideEmptyLists")) { + showEmptyItems = false; + } else if (arg.equals("-hideNulls")) { + showNulls = false; + } else if (arg.equals("-classpath") && i + 1 < args.length) { + classpath = args[++i]; + } else if (arg.equals("-d") && i + 1 < args.length) { + classoutdir = args[++i]; + } else if (arg.startsWith("-")) { + int n = c.isSupportedOption(arg); + if (n < 0) throw new IllegalArgumentException(arg); + options.add(arg); + while (n > 0) options.add(args[++i]); + } else if (arg.endsWith(".java")) { + files.add(new File(arg)); + } + } + + if (classoutdir != null) { + fm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(new File(classoutdir))); + } + + if (classpath != null) { + Collection path = new ArrayList(); + for (String p: classpath.split(File.pathSeparator)) { + if (p.isEmpty()) continue; + File f = new File(p); + if (f.exists()) path.add(f); + } + fm.setLocation(StandardLocation.CLASS_PATH, path); + } + Iterable fos = fm.getJavaFileObjectsFromFiles(files); + + JavacTask task = (JavacTask) c.getTask(out, fm, null, options, null, fos); + final Trees trees = Trees.instance(task); + + final DPrinter dprinter = new DPrinter(out, trees); + dprinter.source(showSource) + .emptyItems(showEmptyItems) + .nulls(showNulls) + .positions(showPositions) + .treeSymbols(showTreeSymbols) + .treeTypes(showTreeTypes); + + if (before.isEmpty() && after.isEmpty()) { + if (h.name.equals("trees") && !showTreeSymbols && !showTreeTypes) + after.add(TaskEvent.Kind.PARSE); + else + after.add(TaskEvent.Kind.ANALYZE); + } + + task.addTaskListener(new TaskListener() { + public void started(TaskEvent e) { + if (before.contains(e.getKind())) + handle(e); + } + + public void finished(TaskEvent e) { + if (after.contains(e.getKind())) + handle(e); + } + + private void handle(TaskEvent e) { + switch (e.getKind()) { + case PARSE: + case ENTER: + h.handle(e.getSourceFile().getName(), + (JCTree) e.getCompilationUnit(), + dprinter); + break; + + default: + TypeElement elem = e.getTypeElement(); + h.handle(elem.toString(), + (JCTree) trees.getTree(elem), + dprinter); + break; + } + } + }); + + task.call(); + } + + TaskEvent.Kind getKind(String s) { + return TaskEvent.Kind.valueOf(s.toUpperCase()); + } + + static protected abstract class Handler { + final String name; + Handler(String name) { + this.name = name; + } + abstract void handle(String label, JCTree tree, DPrinter dprinter); + } + + Map getHandlers() { + Map map = new HashMap(); + for (Handler h: defaultHandlers) { + map.put(h.name, h); + } + return map; + } + + protected final Handler[] defaultHandlers = { + new Handler("trees") { + @Override + void handle(String name, JCTree tree, DPrinter dprinter) { + dprinter.printTree(name, tree); + dprinter.out.println(); + } + }, + + new Handler("symbols") { + @Override + void handle(String name, JCTree tree, final DPrinter dprinter) { + TreeScanner ds = new TreeScanner() { + @Override + public void visitClassDef(JCClassDecl tree) { + visitDecl(tree, tree.sym); + super.visitClassDef(tree); + } + + @Override + public void visitMethodDef(JCMethodDecl tree) { + visitDecl(tree, tree.sym); + super.visitMethodDef(tree); + } + + @Override + public void visitVarDef(JCVariableDecl tree) { + visitDecl(tree, tree.sym); + super.visitVarDef(tree); + } + + void visitDecl(JCTree tree, Symbol sym) { + dprinter.printSymbol(sym.name.toString(), sym); + dprinter.out.println(); + } + }; + ds.scan(tree); + } + }, + + new Handler("types") { + @Override + void handle(String name, JCTree tree, final DPrinter dprinter) { + TreeScanner ts = new TreeScanner() { + @Override + public void scan(JCTree tree) { + if (tree == null) { + return; + } + if (tree.type != null) { + String label = Pretty.toSimpleString(tree); + dprinter.printType(label, tree.type); + dprinter.out.println(); + } + super.scan(tree); + } + }; + ts.scan(tree); + } + } + }; + } + + // + +} diff --git a/langtools/test/tools/javac/lib/JavacTestingAbstractThreadedTest.java b/langtools/test/tools/javac/lib/JavacTestingAbstractThreadedTest.java index edb2aac3111..34029854351 100644 --- a/langtools/test/tools/javac/lib/JavacTestingAbstractThreadedTest.java +++ b/langtools/test/tools/javac/lib/JavacTestingAbstractThreadedTest.java @@ -41,14 +41,20 @@ import javax.tools.ToolProvider; * * If the property is not set the class will use a heuristic to determine the * maximum number of threads that can be fired to execute a given test. + * + * This code will have to be revisited if jprt starts using concurrency for + * for running jtreg tests. */ public abstract class JavacTestingAbstractThreadedTest { + protected static AtomicInteger numberOfThreads = new AtomicInteger(); + protected static int getThreadPoolSize() { Integer testConc = Integer.getInteger("test.concurrency"); if (testConc != null) return testConc; int cores = Runtime.getRuntime().availableProcessors(); - return Math.max(2, Math.min(8, cores / 2)); + numberOfThreads.set(Math.max(2, Math.min(8, cores / 2))); + return numberOfThreads.get(); } protected static void checkAfterExec() throws InterruptedException { @@ -82,11 +88,18 @@ public abstract class JavacTestingAbstractThreadedTest { } else if (printCheckCount) { outWriter.println("Total check executed: " + checkCount.get()); } + /* + * This output is for supporting debugging. It does not mean that a given + * test had executed that number of threads concurrently. The value printed + * here is the maximum possible amount. + */ closePrinters(); if (printAll) { System.out.println(errSWriter.toString()); System.out.println(outSWriter.toString()); } + System.out.println("Total number of threads in thread pool: " + + numberOfThreads.get()); } protected static void closePrinters() { diff --git a/langtools/test/tools/javadoc/api/basic/RunTest.java b/langtools/test/tools/javadoc/api/basic/RunTest.java index 2e6c65252df..380f5b69a9d 100644 --- a/langtools/test/tools/javadoc/api/basic/RunTest.java +++ b/langtools/test/tools/javadoc/api/basic/RunTest.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 6493690 + * @bug 6493690 8007490 * @summary javadoc should have a javax.tools.Tool service provider * @build APITest * @run main RunTest @@ -31,6 +31,7 @@ import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.PrintStream; import javax.tools.DocumentationTool; import javax.tools.ToolProvider; @@ -46,7 +47,7 @@ public class RunTest extends APITest { * Verify that run method can be invoked. */ @Test - public void testRun() throws Exception { + public void testRunOK() throws Exception { File testSrc = new File(System.getProperty("test.src")); File srcFile = new File(testSrc, "pkg/C.java"); File outDir = getOutDir(); @@ -77,7 +78,7 @@ public class RunTest extends APITest { * Verify that run method can be invoked. */ @Test - public void testRun2() throws Exception { + public void testRunFail() throws Exception { File outDir = getOutDir(); String badfile = "badfile.java"; String[] args = { "-d", outDir.getPath(), badfile }; @@ -100,5 +101,48 @@ public class RunTest extends APITest { } } + /** + * Verify that null args are accepted. + */ + @Test + public void testNullArgs() throws Exception { + File testSrc = new File(System.getProperty("test.src")); + File srcFile = new File(testSrc, "pkg/C.java"); + File outDir = getOutDir(); + String[] args = { "-d", outDir.getPath(), srcFile.getPath() }; + + ByteArrayOutputStream stdout = new ByteArrayOutputStream(); + PrintStream prevStdout = System.out; + System.setOut(new PrintStream(stdout)); + + ByteArrayOutputStream stderr = new ByteArrayOutputStream(); + PrintStream prevStderr = System.err; + System.setErr(new PrintStream(stderr)); + + int rc ; + try { + DocumentationTool tool = ToolProvider.getSystemDocumentationTool(); + rc = tool.run(null, null, null, args); + } finally { + System.setOut(prevStdout); + System.setErr(prevStderr); + } + + System.err.println("stdout >>" + stdout.toString() + "<<"); + System.err.println("stderr >>" + stderr.toString() + "<<"); + + if (rc == 0) { + System.err.println("call succeeded"); + checkFiles(outDir, standardExpectFiles); + String out = stdout.toString(); + for (String f: standardExpectFiles) { + String f1 = f.replace('/', File.separatorChar); + if (f1.endsWith(".html") && !out.contains(f1)) + error("expected string not found: " + f1); + } + } else { + error("call failed"); + } + } }