8003680: JSR 310 Date/Time API
authorsherman
Tue, 22 Jan 2013 20:59:21 -0800
changeset 15289 3ac550392e43
parent 15288 3fd913435103
child 15290 bcbe5d3c4789
8003680: JSR 310 Date/Time API Summary: Integration of JSR310 Date/Time API for M6 Reviewed-by: alanb, naoto, dholmes Contributed-by: scolebourne@joda.org, roger.riggs@oracle.com, richard.warburton@gmail.com, misterm@gmail.com
jdk/make/docs/CORE_PKGS.gmk
jdk/make/java/Makefile
jdk/make/java/time/Makefile
jdk/make/jprt.properties
jdk/make/sun/Makefile
jdk/make/sun/tzdb/Makefile
jdk/make/tools/Makefile
jdk/make/tools/src/build/tools/tzdb/ChronoField.java
jdk/make/tools/src/build/tools/tzdb/DateTimeException.java
jdk/make/tools/src/build/tools/tzdb/LocalDate.java
jdk/make/tools/src/build/tools/tzdb/LocalDateTime.java
jdk/make/tools/src/build/tools/tzdb/LocalTime.java
jdk/make/tools/src/build/tools/tzdb/TimeDefinition.java
jdk/make/tools/src/build/tools/tzdb/TzdbZoneRulesCompiler.java
jdk/make/tools/src/build/tools/tzdb/Utils.java
jdk/make/tools/src/build/tools/tzdb/ZoneOffset.java
jdk/make/tools/src/build/tools/tzdb/ZoneOffsetTransition.java
jdk/make/tools/src/build/tools/tzdb/ZoneOffsetTransitionRule.java
jdk/make/tools/src/build/tools/tzdb/ZoneRules.java
jdk/make/tools/src/build/tools/tzdb/ZoneRulesBuilder.java
jdk/make/tools/tzdb/Makefile
jdk/makefiles/CreateJars.gmk
jdk/makefiles/GendataTZDB.gmk
jdk/makefiles/GenerateData.gmk
jdk/makefiles/Tools.gmk
jdk/src/share/classes/java/time/Clock.java
jdk/src/share/classes/java/time/DateTimeException.java
jdk/src/share/classes/java/time/DayOfWeek.java
jdk/src/share/classes/java/time/Duration.java
jdk/src/share/classes/java/time/Instant.java
jdk/src/share/classes/java/time/LocalDate.java
jdk/src/share/classes/java/time/LocalDateTime.java
jdk/src/share/classes/java/time/LocalTime.java
jdk/src/share/classes/java/time/Month.java
jdk/src/share/classes/java/time/Period.java
jdk/src/share/classes/java/time/PeriodParser.java
jdk/src/share/classes/java/time/Ser.java
jdk/src/share/classes/java/time/ZoneId.java
jdk/src/share/classes/java/time/ZoneOffset.java
jdk/src/share/classes/java/time/ZoneRegion.java
jdk/src/share/classes/java/time/ZonedDateTime.java
jdk/src/share/classes/java/time/calendar/ChronoDateImpl.java
jdk/src/share/classes/java/time/calendar/HijrahChrono.java
jdk/src/share/classes/java/time/calendar/HijrahDate.java
jdk/src/share/classes/java/time/calendar/HijrahDeviationReader.java
jdk/src/share/classes/java/time/calendar/HijrahEra.java
jdk/src/share/classes/java/time/calendar/JapaneseChrono.java
jdk/src/share/classes/java/time/calendar/JapaneseDate.java
jdk/src/share/classes/java/time/calendar/JapaneseEra.java
jdk/src/share/classes/java/time/calendar/MinguoChrono.java
jdk/src/share/classes/java/time/calendar/MinguoDate.java
jdk/src/share/classes/java/time/calendar/MinguoEra.java
jdk/src/share/classes/java/time/calendar/Ser.java
jdk/src/share/classes/java/time/calendar/ThaiBuddhistChrono.java
jdk/src/share/classes/java/time/calendar/ThaiBuddhistDate.java
jdk/src/share/classes/java/time/calendar/ThaiBuddhistEra.java
jdk/src/share/classes/java/time/calendar/package-info.java
jdk/src/share/classes/java/time/format/DateTimeBuilder.java
jdk/src/share/classes/java/time/format/DateTimeFormatStyleProvider.java
jdk/src/share/classes/java/time/format/DateTimeFormatSymbols.java
jdk/src/share/classes/java/time/format/DateTimeFormatter.java
jdk/src/share/classes/java/time/format/DateTimeFormatterBuilder.java
jdk/src/share/classes/java/time/format/DateTimeFormatters.java
jdk/src/share/classes/java/time/format/DateTimeParseContext.java
jdk/src/share/classes/java/time/format/DateTimeParseException.java
jdk/src/share/classes/java/time/format/DateTimePrintContext.java
jdk/src/share/classes/java/time/format/DateTimePrintException.java
jdk/src/share/classes/java/time/format/DateTimeTextProvider.java
jdk/src/share/classes/java/time/format/FormatStyle.java
jdk/src/share/classes/java/time/format/SignStyle.java
jdk/src/share/classes/java/time/format/TextStyle.java
jdk/src/share/classes/java/time/format/package-info.java
jdk/src/share/classes/java/time/overview.html
jdk/src/share/classes/java/time/package-info.java
jdk/src/share/classes/java/time/temporal/Adjusters.java
jdk/src/share/classes/java/time/temporal/Chrono.java
jdk/src/share/classes/java/time/temporal/ChronoField.java
jdk/src/share/classes/java/time/temporal/ChronoLocalDate.java
jdk/src/share/classes/java/time/temporal/ChronoLocalDateTime.java
jdk/src/share/classes/java/time/temporal/ChronoLocalDateTimeImpl.java
jdk/src/share/classes/java/time/temporal/ChronoUnit.java
jdk/src/share/classes/java/time/temporal/ChronoZonedDateTime.java
jdk/src/share/classes/java/time/temporal/ChronoZonedDateTimeImpl.java
jdk/src/share/classes/java/time/temporal/Era.java
jdk/src/share/classes/java/time/temporal/ISOChrono.java
jdk/src/share/classes/java/time/temporal/ISOEra.java
jdk/src/share/classes/java/time/temporal/ISOFields.java
jdk/src/share/classes/java/time/temporal/JulianFields.java
jdk/src/share/classes/java/time/temporal/MonthDay.java
jdk/src/share/classes/java/time/temporal/OffsetDate.java
jdk/src/share/classes/java/time/temporal/OffsetDateTime.java
jdk/src/share/classes/java/time/temporal/OffsetTime.java
jdk/src/share/classes/java/time/temporal/Queries.java
jdk/src/share/classes/java/time/temporal/Ser.java
jdk/src/share/classes/java/time/temporal/SimplePeriod.java
jdk/src/share/classes/java/time/temporal/Temporal.java
jdk/src/share/classes/java/time/temporal/TemporalAccessor.java
jdk/src/share/classes/java/time/temporal/TemporalAdder.java
jdk/src/share/classes/java/time/temporal/TemporalAdjuster.java
jdk/src/share/classes/java/time/temporal/TemporalField.java
jdk/src/share/classes/java/time/temporal/TemporalQuery.java
jdk/src/share/classes/java/time/temporal/TemporalSubtractor.java
jdk/src/share/classes/java/time/temporal/TemporalUnit.java
jdk/src/share/classes/java/time/temporal/ValueRange.java
jdk/src/share/classes/java/time/temporal/WeekFields.java
jdk/src/share/classes/java/time/temporal/Year.java
jdk/src/share/classes/java/time/temporal/YearMonth.java
jdk/src/share/classes/java/time/temporal/package-info.java
jdk/src/share/classes/java/time/zone/Ser.java
jdk/src/share/classes/java/time/zone/TzdbZoneRulesProvider.java
jdk/src/share/classes/java/time/zone/ZoneOffsetTransition.java
jdk/src/share/classes/java/time/zone/ZoneOffsetTransitionRule.java
jdk/src/share/classes/java/time/zone/ZoneRules.java
jdk/src/share/classes/java/time/zone/ZoneRulesException.java
jdk/src/share/classes/java/time/zone/ZoneRulesProvider.java
jdk/src/share/classes/java/time/zone/package-info.java
jdk/src/share/classes/java/util/Formatter.java
jdk/test/Makefile
jdk/test/java/time/META-INF/services/java.time.temporal.Chrono
jdk/test/java/time/TEST.properties
jdk/test/java/time/tck/java/time/AbstractDateTimeTest.java
jdk/test/java/time/tck/java/time/AbstractTCKTest.java
jdk/test/java/time/tck/java/time/TCKClock.java
jdk/test/java/time/tck/java/time/TCKClock_Fixed.java
jdk/test/java/time/tck/java/time/TCKClock_Offset.java
jdk/test/java/time/tck/java/time/TCKClock_System.java
jdk/test/java/time/tck/java/time/TCKClock_Tick.java
jdk/test/java/time/tck/java/time/TCKDayOfWeek.java
jdk/test/java/time/tck/java/time/TCKDuration.java
jdk/test/java/time/tck/java/time/TCKInstant.java
jdk/test/java/time/tck/java/time/TCKLocalDate.java
jdk/test/java/time/tck/java/time/TCKLocalDateTime.java
jdk/test/java/time/tck/java/time/TCKLocalTime.java
jdk/test/java/time/tck/java/time/TCKMonth.java
jdk/test/java/time/tck/java/time/TCKZoneId.java
jdk/test/java/time/tck/java/time/TCKZoneOffset.java
jdk/test/java/time/tck/java/time/TCKZonedDateTime.java
jdk/test/java/time/tck/java/time/calendar/CopticChrono.java
jdk/test/java/time/tck/java/time/calendar/CopticDate.java
jdk/test/java/time/tck/java/time/calendar/CopticEra.java
jdk/test/java/time/tck/java/time/calendar/TestChronoLocalDate.java
jdk/test/java/time/tck/java/time/calendar/TestChronoLocalDateTime.java
jdk/test/java/time/tck/java/time/calendar/TestHijrahChrono.java
jdk/test/java/time/tck/java/time/calendar/TestJapaneseChrono.java
jdk/test/java/time/tck/java/time/calendar/TestMinguoChrono.java
jdk/test/java/time/tck/java/time/calendar/TestServiceLoader.java
jdk/test/java/time/tck/java/time/calendar/TestThaiBuddhistChrono.java
jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatSymbols.java
jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatter.java
jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java
jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatters.java
jdk/test/java/time/tck/java/time/format/TCKDateTimePrintException.java
jdk/test/java/time/tck/java/time/format/TCKDateTimeTextPrinting.java
jdk/test/java/time/tck/java/time/format/TCKLocalizedFieldParser.java
jdk/test/java/time/tck/java/time/format/TCKLocalizedFieldPrinter.java
jdk/test/java/time/tck/java/time/temporal/TCKDateTimeAdjusters.java
jdk/test/java/time/tck/java/time/temporal/TCKISOFields.java
jdk/test/java/time/tck/java/time/temporal/TCKJulianFields.java
jdk/test/java/time/tck/java/time/temporal/TCKMonthDay.java
jdk/test/java/time/tck/java/time/temporal/TCKOffsetDate.java
jdk/test/java/time/tck/java/time/temporal/TCKOffsetDateTime.java
jdk/test/java/time/tck/java/time/temporal/TCKOffsetTime.java
jdk/test/java/time/tck/java/time/temporal/TCKSimplePeriod.java
jdk/test/java/time/tck/java/time/temporal/TCKWeekFields.java
jdk/test/java/time/tck/java/time/temporal/TCKYear.java
jdk/test/java/time/tck/java/time/temporal/TCKYearMonth.java
jdk/test/java/time/tck/java/time/temporal/TestChrono.java
jdk/test/java/time/tck/java/time/temporal/TestChronoLocalDate.java
jdk/test/java/time/tck/java/time/temporal/TestChronoLocalDateTime.java
jdk/test/java/time/tck/java/time/temporal/TestChronoZonedDateTime.java
jdk/test/java/time/tck/java/time/temporal/TestISOChrono.java
jdk/test/java/time/tck/java/time/zone/TCKFixedZoneRules.java
jdk/test/java/time/tck/java/time/zone/TCKZoneOffsetTransition.java
jdk/test/java/time/tck/java/time/zone/TCKZoneOffsetTransitionRule.java
jdk/test/java/time/tck/java/time/zone/TCKZoneRules.java
jdk/test/java/time/tck/java/time/zone/TCKZoneRulesProvider.java
jdk/test/java/time/test/java/time/AbstractTest.java
jdk/test/java/time/test/java/time/MockSimplePeriod.java
jdk/test/java/time/test/java/time/TestClock_Fixed.java
jdk/test/java/time/test/java/time/TestClock_Offset.java
jdk/test/java/time/test/java/time/TestClock_System.java
jdk/test/java/time/test/java/time/TestClock_Tick.java
jdk/test/java/time/test/java/time/TestDuration.java
jdk/test/java/time/test/java/time/TestInstant.java
jdk/test/java/time/test/java/time/TestLocalDate.java
jdk/test/java/time/test/java/time/TestLocalDateTime.java
jdk/test/java/time/test/java/time/TestLocalTime.java
jdk/test/java/time/test/java/time/TestPeriod.java
jdk/test/java/time/test/java/time/TestPeriodParser.java
jdk/test/java/time/test/java/time/TestZoneId.java
jdk/test/java/time/test/java/time/TestZoneOffset.java
jdk/test/java/time/test/java/time/TestZonedDateTime.java
jdk/test/java/time/test/java/time/format/AbstractTestPrinterParser.java
jdk/test/java/time/test/java/time/format/MockIOExceptionAppendable.java
jdk/test/java/time/test/java/time/format/TestCharLiteralParser.java
jdk/test/java/time/test/java/time/format/TestCharLiteralPrinter.java
jdk/test/java/time/test/java/time/format/TestDateTimeFormatSymbols.java
jdk/test/java/time/test/java/time/format/TestDateTimeFormatter.java
jdk/test/java/time/test/java/time/format/TestDateTimeFormatters.java
jdk/test/java/time/test/java/time/format/TestDateTimePrintException.java
jdk/test/java/time/test/java/time/format/TestDateTimeTextProvider.java
jdk/test/java/time/test/java/time/format/TestFractionPrinterParser.java
jdk/test/java/time/test/java/time/format/TestNumberParser.java
jdk/test/java/time/test/java/time/format/TestNumberPrinter.java
jdk/test/java/time/test/java/time/format/TestPadParserDecorator.java
jdk/test/java/time/test/java/time/format/TestPadPrinterDecorator.java
jdk/test/java/time/test/java/time/format/TestReducedParser.java
jdk/test/java/time/test/java/time/format/TestReducedPrinter.java
jdk/test/java/time/test/java/time/format/TestSettingsParser.java
jdk/test/java/time/test/java/time/format/TestStringLiteralParser.java
jdk/test/java/time/test/java/time/format/TestStringLiteralPrinter.java
jdk/test/java/time/test/java/time/format/TestTextParser.java
jdk/test/java/time/test/java/time/format/TestTextPrinter.java
jdk/test/java/time/test/java/time/format/TestZoneIdParser.java
jdk/test/java/time/test/java/time/format/TestZoneOffsetParser.java
jdk/test/java/time/test/java/time/format/TestZoneOffsetPrinter.java
jdk/test/java/time/test/java/time/format/TestZoneTextPrinterParser.java
jdk/test/java/time/test/java/time/temporal/MockFieldNoValue.java
jdk/test/java/time/test/java/time/temporal/MockFieldValue.java
jdk/test/java/time/test/java/time/temporal/TestChronoUnit.java
jdk/test/java/time/test/java/time/temporal/TestDateTimeAdjusters.java
jdk/test/java/time/test/java/time/temporal/TestDateTimeBuilderCombinations.java
jdk/test/java/time/test/java/time/temporal/TestDateTimeValueRange.java
jdk/test/java/time/test/java/time/temporal/TestISOChronoImpl.java
jdk/test/java/time/test/java/time/temporal/TestJapaneseChronoImpl.java
jdk/test/java/time/test/java/time/temporal/TestMonthDay.java
jdk/test/java/time/test/java/time/temporal/TestOffsetDate.java
jdk/test/java/time/test/java/time/temporal/TestOffsetDateTime.java
jdk/test/java/time/test/java/time/temporal/TestOffsetDateTime_instants.java
jdk/test/java/time/test/java/time/temporal/TestOffsetTime.java
jdk/test/java/time/test/java/time/temporal/TestThaiBuddhistChronoImpl.java
jdk/test/java/time/test/java/time/temporal/TestYear.java
jdk/test/java/time/test/java/time/temporal/TestYearMonth.java
jdk/test/java/time/test/java/time/zone/TestFixedZoneRules.java
jdk/test/java/time/test/java/util/TestFormatter.java
--- a/jdk/make/docs/CORE_PKGS.gmk	Tue Jan 22 18:30:49 2013 -0800
+++ b/jdk/make/docs/CORE_PKGS.gmk	Tue Jan 22 20:59:21 2013 -0800
@@ -127,6 +127,11 @@
   java.sql                                       \
   java.text                                      \
   java.text.spi                                  \
+  java.time                                      \
+  java.time.temporal                             \
+  java.time.calendar                             \
+  java.time.format                               \
+  java.time.zone                                 \
   java.util                                      \
   java.util.concurrent                           \
   java.util.concurrent.atomic                    \
--- a/jdk/make/java/Makefile	Tue Jan 22 18:30:49 2013 -0800
+++ b/jdk/make/java/Makefile	Tue Jan 22 20:59:21 2013 -0800
@@ -39,7 +39,7 @@
 # Others
 #    Note: java_crw_demo java_hprof_demo are demos but must be delivered built in sdk
 
-SUBDIRS += security math util text net nio jar
+SUBDIRS += security math util text net nio jar time
 
 SUBDIRS_desktop    = awt applet beans
 SUBDIRS_management = management
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/java/time/Makefile	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,42 @@
+#
+# Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+#
+# Makefile for building jar utility.
+#
+
+BUILDDIR = ../../
+PACKAGE = java.time
+include $(BUILDDIR)/common/Defs.gmk
+
+#
+# Files
+#
+AUTO_FILES_JAVA_DIRS = java/time
+
+#
+# Rules
+#
+include $(BUILDDIR)/common/Classes.gmk
--- a/jdk/make/jprt.properties	Tue Jan 22 18:30:49 2013 -0800
+++ b/jdk/make/jprt.properties	Tue Jan 22 20:59:21 2013 -0800
@@ -87,6 +87,7 @@
     ${jprt.my.test.target.set:TESTNAME=jdk_text},               \
     ${jprt.my.test.target.set:TESTNAME=jdk_tools},              \
     ${jprt.my.test.target.set:TESTNAME=jdk_jfr},                \
+    ${jprt.my.test.target.set:TESTNAME=jdk_time},               \
     ${jprt.my.test.target.set:TESTNAME=jdk_other}
 
 # All vm test targets (testset=all)
--- a/jdk/make/sun/Makefile	Tue Jan 22 18:30:49 2013 -0800
+++ b/jdk/make/sun/Makefile	Tue Jan 22 20:59:21 2013 -0800
@@ -70,7 +70,7 @@
 endif
 
 # nio need to be compiled before awt to have all charsets ready
-SUBDIRS            = jar security javazic misc net nio text util launcher cldr
+SUBDIRS            = jar security javazic misc net nio text util launcher cldr tzdb
 
 ifdef BUILD_HEADLESS_ONLY
   DISPLAY_LIBS = awt $(HEADLESS_SUBDIR)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/sun/tzdb/Makefile	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,68 @@
+#
+# Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+#
+# Makefile for building tzdb compiler utility.
+#
+
+BUILDDIR = ../..
+PACKAGE = sun.tzdb
+PRODUCT = sun
+include $(BUILDDIR)/common/Defs.gmk
+
+# This program must contain a manifest that defines the execution level
+# needed to follow standard Vista User Access Control Guidelines
+# This must be set before Program.gmk is included
+#
+BUILD_MANIFEST=true
+
+#
+# Time zone data file creation
+#
+TZDATA_DIR := ../javazic/tzdata
+TZDATA_VER := $(subst tzdata,,$(shell $(GREP) '^tzdata' $(TZDATA_DIR)/VERSION))
+TZFILE := africa antarctica asia australasia europe northamerica southamerica backward etcetera
+TZFILES := $(addprefix $(TZDATA_DIR)/,$(TZFILE))
+
+TZDB_JAR = tzdb.jar
+
+#
+# Rules
+#
+include $(BUILDDIR)/common/Classes.gmk
+
+#
+# Add to the build rule
+#
+build: $(LIBDIR)/$(TZDB_JAR)
+
+$(LIBDIR)/$(TZDB_JAR): $(TZFILES)
+	$(prep-target)
+	echo build tzdb from version $(TZDATA_VER)
+	$(BOOT_JAVA_CMD) -jar $(BUILDTOOLJARDIR)/tzdb.jar -verbose \
+	  -version $(TZDATA_VER) -srcdir $(TZDATA_DIR) -dstdir $(LIBDIR) $(TZFILE)
+
+clean clobber::
+	$(RM) $(LIBDIR)/$(TZDB_JAR)
--- a/jdk/make/tools/Makefile	Tue Jan 22 18:30:49 2013 -0800
+++ b/jdk/make/tools/Makefile	Tue Jan 22 20:59:21 2013 -0800
@@ -53,6 +53,7 @@
   makeclasslist             \
   strip_properties          \
   spp                       \
+  tzdb                      \
   CharsetMapping
 
 ifndef DISABLE_NIMBUS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/tools/src/build/tools/tzdb/ChronoField.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package build.tools.tzdb;
+
+/**
+ * A standard set of date/time fields.
+ *
+ * @since 1.8
+ */
+enum ChronoField {
+
+    /**
+     * The second-of-minute.
+     * <p>
+     * This counts the second within the minute, from 0 to 59.
+     * This field has the same meaning for all calendar systems.
+     */
+    SECOND_OF_MINUTE("SecondOfMinute", 0, 59),
+
+    /**
+     * The second-of-day.
+     * <p>
+     * This counts the second within the day, from 0 to (24 * 60 * 60) - 1.
+     * This field has the same meaning for all calendar systems.
+     */
+    SECOND_OF_DAY("SecondOfDay", 0, 86400 - 1),
+
+    /**
+     * The minute-of-hour.
+     * <p>
+     * This counts the minute within the hour, from 0 to 59.
+     * This field has the same meaning for all calendar systems.
+     */
+    MINUTE_OF_HOUR("MinuteOfHour", 0, 59),
+
+    /**
+     * The hour-of-day.
+     * <p>
+     * This counts the hour within the day, from 0 to 23.
+     * This is the hour that would be observed on a standard 24-hour digital clock.
+     * This field has the same meaning for all calendar systems.
+     */
+    HOUR_OF_DAY("HourOfDay", 0, 23),
+
+
+    /**
+     * The day-of-month.
+     * <p>
+     * This represents the concept of the day within the month.
+     * In the default ISO calendar system, this has values from 1 to 31 in most months.
+     * April, June, September, November have days from 1 to 30, while February has days
+     * from 1 to 28, or 29 in a leap year.
+     * <p>
+     * Non-ISO calendar systems should implement this field using the most recognized
+     * day-of-month values for users of the calendar system.
+     * Normally, this is a count of days from 1 to the length of the month.
+     */
+    DAY_OF_MONTH("DayOfMonth", 1, 31),
+
+    /**
+     * The month-of-year, such as March.
+     * <p>
+     * This represents the concept of the month within the year.
+     * In the default ISO calendar system, this has values from January (1) to December (12).
+     * <p>
+     * Non-ISO calendar systems should implement this field using the most recognized
+     * month-of-year values for users of the calendar system.
+     * Normally, this is a count of months starting from 1.
+     */
+    MONTH_OF_YEAR("MonthOfYear", 1, 12),
+
+    /**
+     * The proleptic year, such as 2012.
+     * <p>
+     * This represents the concept of the year, counting sequentially and using negative numbers.
+     * The proleptic year is not interpreted in terms of the era.
+     * See {@link #YEAR_OF_ERA} for an example showing the mapping from proleptic year to year-of-era.
+     * <p>
+     * The standard mental model for a date is based on three concepts - year, month and day.
+     * These map onto the {@code YEAR}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} fields.
+     * Note that there is no reference to eras.
+     * The full model for a date requires four concepts - era, year, month and day. These map onto
+     * the {@code ERA}, {@code YEAR_OF_ERA}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} fields.
+     * Whether this field or {@code YEAR_OF_ERA} is used depends on which mental model is being used.
+     * See {@link ChronoLocalDate} for more discussion on this topic.
+     * <p>
+     * Non-ISO calendar systems should implement this field as follows.
+     * If the calendar system has only two eras, before and after a fixed date, then the
+     * proleptic-year value must be the same as the year-of-era value for the later era,
+     * and increasingly negative for the earlier era.
+     * If the calendar system has more than two eras, then the proleptic-year value may be
+     * defined with any appropriate value, although defining it to be the same as ISO may be
+     * the best option.
+     */
+    YEAR("Year", -999_999_999, 999_999_999);
+
+    private final String name;
+    private final int min;
+    private final int max;
+
+    private ChronoField(String name, int min, int max) {
+        this.name = name;
+        this.min= min;
+        this.max= max;
+    }
+
+    /**
+     * Checks that the specified value is valid for this field.
+     * <p>
+     *
+     * @param value  the value to check
+     * @return the value that was passed in
+     */
+    public int checkValidValue(int value) {
+        if (value >= min && value <= max) {
+            return value;
+        }
+        throw new DateTimeException("Invalid value for " + name + " value: " + value);
+    }
+
+    public String toString() {
+        return name;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/tools/src/build/tools/tzdb/DateTimeException.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package build.tools.tzdb;
+
+/**
+ * Exception used to indicate a problem while calculating a date-time.
+ * <p>
+ * This exception is used to indicate problems with creating, querying
+ * and manipulating date-time objects.
+ *
+ * @since 1.8
+ */
+class DateTimeException extends RuntimeException {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -1632418723876261839L;
+
+    /**
+     * Constructs a new date-time exception with the specified message.
+     *
+     * @param message  the message to use for this exception, may be null
+     */
+    public DateTimeException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new date-time exception with the specified message and cause.
+     *
+     * @param message  the message to use for this exception, may be null
+     * @param cause  the cause of the exception, may be null
+     */
+    public DateTimeException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/tools/src/build/tools/tzdb/LocalDate.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,363 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package build.tools.tzdb;
+
+import static build.tools.tzdb.Utils.*;
+import static build.tools.tzdb.LocalTime.SECONDS_PER_DAY;
+import static build.tools.tzdb.ChronoField.DAY_OF_MONTH;
+import static build.tools.tzdb.ChronoField.MONTH_OF_YEAR;
+import static build.tools.tzdb.ChronoField.YEAR;
+
+import java.util.Objects;
+
+/**
+ * A date without a time-zone in the ISO-8601 calendar system,
+ * such as {@code 2007-12-03}.
+ *
+ * @since 1.8
+ */
+final class LocalDate {
+
+    /**
+     * The minimum supported {@code LocalDate}, '-999999999-01-01'.
+     * This could be used by an application as a "far past" date.
+     */
+    public static final LocalDate MIN = new LocalDate(YEAR_MIN_VALUE, 1, 1);
+    /**
+     * The maximum supported {@code LocalDate}, '+999999999-12-31'.
+     * This could be used by an application as a "far future" date.
+     */
+    public static final LocalDate MAX = new LocalDate(YEAR_MAX_VALUE, 12, 31);
+
+    /**
+     * The number of days in a 400 year cycle.
+     */
+    private static final int DAYS_PER_CYCLE = 146097;
+    /**
+     * The number of days from year zero to year 1970.
+     * There are five 400 year cycles from year zero to 2000.
+     * There are 7 leap years from 1970 to 2000.
+     */
+    static final long DAYS_0000_TO_1970 = (DAYS_PER_CYCLE * 5L) - (30L * 365L + 7L);
+
+    /**
+     * The year.
+     */
+    private final int year;
+    /**
+     * The month-of-year.
+     */
+    private final short month;
+    /**
+     * The day-of-month.
+     */
+    private final short day;
+
+    /**
+     * Obtains an instance of {@code LocalDate} from a year, month and day.
+     * <p>
+     * The day must be valid for the year and month, otherwise an exception will be thrown.
+     *
+     * @param year  the year to represent, from MIN_YEAR to MAX_YEAR
+     * @param month  the month-of-year to represent, from 1 (January) to 12 (December)
+     * @param dayOfMonth  the day-of-month to represent, from 1 to 31
+     * @return the local date, not null
+     * @throws DateTimeException if the value of any field is out of range
+     * @throws DateTimeException if the day-of-month is invalid for the month-year
+     */
+    public static LocalDate of(int year, int month, int dayOfMonth) {
+        YEAR.checkValidValue(year);
+        MONTH_OF_YEAR.checkValidValue(month);
+        DAY_OF_MONTH.checkValidValue(dayOfMonth);
+        if (dayOfMonth > 28 && dayOfMonth > lengthOfMonth(month, isLeapYear(year))) {
+            if (dayOfMonth == 29) {
+                throw new DateTimeException("Invalid date 'February 29' as '" + year + "' is not a leap year");
+            } else {
+                throw new DateTimeException("Invalid date '" + month + " " + dayOfMonth + "'");
+            }
+        }
+        return new LocalDate(year, month, dayOfMonth);
+    }
+
+    /**
+     * Constructor, previously validated.
+     *
+     * @param year  the year to represent, from MIN_YEAR to MAX_YEAR
+     * @param month  the month-of-year to represent, not null
+     * @param dayOfMonth  the day-of-month to represent, valid for year-month, from 1 to 31
+     */
+    private LocalDate(int year, int month, int dayOfMonth) {
+        this.year = year;
+        this.month = (short) month;
+        this.day = (short) dayOfMonth;
+    }
+
+    /**
+     * Gets the year field.
+     * <p>
+     * This method returns the primitive {@code int} value for the year.
+     * <p>
+     * The year returned by this method is proleptic as per {@code get(YEAR)}.
+     * To obtain the year-of-era, use {@code get(YEAR_OF_ERA}.
+     *
+     * @return the year, from MIN_YEAR to MAX_YEAR
+     */
+    public int getYear() {
+        return year;
+    }
+
+    /**
+     * Gets the month-of-year field as an int from 1 to 12.
+     *
+     * @return the month-of-year
+     */
+    public int getMonth() {
+        return month;
+    }
+
+    /**
+     * Gets the day-of-month field.
+     * <p>
+     * This method returns the primitive {@code int} value for the day-of-month.
+     *
+     * @return the day-of-month, from 1 to 31
+     */
+    public int getDayOfMonth() {
+        return day;
+    }
+
+    /**
+     * Gets the day-of-week field, which is an int from 1 to 7.
+     *
+     * @return the day-of-week
+     */
+    public int getDayOfWeek() {
+        return (int)floorMod(toEpochDay() + 3, 7) + 1;
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDate} with the specified number of days added.
+     * <p>
+     * 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.
+     * <p>
+     * For example, 2008-12-31 plus one day would result in 2009-01-01.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param daysToAdd  the days to add, may be negative
+     * @return a {@code LocalDate} based on this date with the days added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDate plusDays(long daysToAdd) {
+        if (daysToAdd == 0) {
+            return this;
+        }
+        long mjDay = addExact(toEpochDay(), daysToAdd);
+        return LocalDate.ofEpochDay(mjDay);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDate} with the specified number of days subtracted.
+     * <p>
+     * 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.
+     * <p>
+     * For example, 2009-01-01 minus one day would result in 2008-12-31.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param daysToSubtract  the days to subtract, may be negative
+     * @return a {@code LocalDate} based on this date with the days subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDate minusDays(long daysToSubtract) {
+        return (daysToSubtract == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-daysToSubtract));
+    }
+
+    /**
+     * Obtains an instance of {@code LocalDate} from the epoch day count.
+     * <p>
+     * The Epoch Day count is a simple incrementing count of days
+     * where day 0 is 1970-01-01. Negative numbers represent earlier days.
+     *
+     * @param epochDay  the Epoch Day to convert, based on the epoch 1970-01-01
+     * @return the local date, not null
+     * @throws DateTimeException if the epoch days exceeds the supported date range
+     */
+    public static LocalDate ofEpochDay(long epochDay) {
+        long zeroDay = epochDay + DAYS_0000_TO_1970;
+        // find the march-based year
+        zeroDay -= 60;  // adjust to 0000-03-01 so leap day is at end of four year cycle
+        long adjust = 0;
+        if (zeroDay < 0) {
+            // adjust negative years to positive for calculation
+            long adjustCycles = (zeroDay + 1) / DAYS_PER_CYCLE - 1;
+            adjust = adjustCycles * 400;
+            zeroDay += -adjustCycles * DAYS_PER_CYCLE;
+        }
+        long yearEst = (400 * zeroDay + 591) / DAYS_PER_CYCLE;
+        long doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400);
+        if (doyEst < 0) {
+            // fix estimate
+            yearEst--;
+            doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400);
+        }
+        yearEst += adjust;  // reset any negative year
+        int marchDoy0 = (int) doyEst;
+
+        // convert march-based values back to january-based
+        int marchMonth0 = (marchDoy0 * 5 + 2) / 153;
+        int month = (marchMonth0 + 2) % 12 + 1;
+        int dom = marchDoy0 - (marchMonth0 * 306 + 5) / 10 + 1;
+        yearEst += marchMonth0 / 10;
+
+        // check year now we are certain it is correct
+        int year = YEAR.checkValidValue((int)yearEst);
+        return new LocalDate(year, month, dom);
+    }
+
+    public long toEpochDay() {
+        long y = year;
+        long m = month;
+        long total = 0;
+        total += 365 * y;
+        if (y >= 0) {
+            total += (y + 3) / 4 - (y + 99) / 100 + (y + 399) / 400;
+        } else {
+            total -= y / -4 - y / -100 + y / -400;
+        }
+        total += ((367 * m - 362) / 12);
+        total += day - 1;
+        if (m > 2) {
+            total--;
+            if (isLeapYear(year) == false) {
+                total--;
+            }
+        }
+        return total - DAYS_0000_TO_1970;
+    }
+
+    /**
+     * Compares this date to another date.
+     * <p>
+     * The comparison is primarily based on the date, from earliest to latest.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     * <p>
+     * If all the dates being compared are instances of {@code LocalDate},
+     * then the comparison will be entirely based on the date.
+     * If some dates being compared are in different chronologies, then the
+     * chronology is also considered, see {@link java.time.temporal.ChronoLocalDate#compareTo}.
+     *
+     * @param other  the other date to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     */
+    public int compareTo(LocalDate otherDate) {
+        int cmp = (year - otherDate.year);
+        if (cmp == 0) {
+            cmp = (month - otherDate.month);
+            if (cmp == 0) {
+                cmp = (day - otherDate.day);
+            }
+        }
+        return cmp;
+    }
+
+    /**
+     * Checks if this date is equal to another date.
+     * <p>
+     * Compares this {@code LocalDate} with another ensuring that the date is the same.
+     * <p>
+     * Only objects of type {@code LocalDate} are compared, other types return false.
+     * To compare the dates of two {@code TemporalAccessor} instances, including dates
+     * in two different chronologies, use {@link ChronoField#EPOCH_DAY} as a comparator.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other date
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof LocalDate) {
+            return compareTo((LocalDate) obj) == 0;
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this date.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        int yearValue = year;
+        int monthValue = month;
+        int dayValue = day;
+        return (yearValue & 0xFFFFF800) ^ ((yearValue << 11) + (monthValue << 6) + (dayValue));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/tools/src/build/tools/tzdb/LocalDateTime.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,427 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package build.tools.tzdb;
+
+import static build.tools.tzdb.Utils.*;
+import static build.tools.tzdb.LocalTime.HOURS_PER_DAY;
+import static build.tools.tzdb.LocalTime.MICROS_PER_DAY;
+import static build.tools.tzdb.LocalTime.MILLIS_PER_DAY;
+import static build.tools.tzdb.LocalTime.MINUTES_PER_DAY;
+import static build.tools.tzdb.LocalTime.SECONDS_PER_DAY;
+import static build.tools.tzdb.LocalTime.SECONDS_PER_MINUTE;
+import static build.tools.tzdb.LocalTime.SECONDS_PER_HOUR;
+
+import java.util.Objects;
+
+/**
+ * A date-time without a time-zone in the ISO-8601 calendar system,
+ * such as {@code 2007-12-03T10:15:30}.
+ *
+ * @since 1.8
+ */
+final class LocalDateTime {
+
+    /**
+     * The minimum supported {@code LocalDateTime}, '-999999999-01-01T00:00:00'.
+     * This is the local date-time of midnight at the start of the minimum date.
+     * This combines {@link LocalDate#MIN} and {@link LocalTime#MIN}.
+     * This could be used by an application as a "far past" date-time.
+     */
+    public static final LocalDateTime MIN = LocalDateTime.of(LocalDate.MIN, LocalTime.MIN);
+    /**
+     * The maximum supported {@code LocalDateTime}, '+999999999-12-31T23:59:59.999999999'.
+     * This is the local date-time just before midnight at the end of the maximum date.
+     * This combines {@link LocalDate#MAX} and {@link LocalTime#MAX}.
+     * This could be used by an application as a "far future" date-time.
+     */
+    public static final LocalDateTime MAX = LocalDateTime.of(LocalDate.MAX, LocalTime.MAX);
+
+    /**
+     * The date part.
+     */
+    private final LocalDate date;
+    /**
+     * The time part.
+     */
+    private final LocalTime time;
+
+    /**
+     * Obtains an instance of {@code LocalDateTime} from year, month,
+     * day, hour and minute, setting the second and nanosecond to zero.
+     * <p>
+     * The day must be valid for the year and month, otherwise an exception will be thrown.
+     * The second and nanosecond fields will be set to zero.
+     *
+     * @param year  the year to represent, from MIN_YEAR to MAX_YEAR
+     * @param month  the month-of-year to represent, from 1 (January) to 12 (December)
+     * @param dayOfMonth  the day-of-month to represent, from 1 to 31
+     * @param hour  the hour-of-day to represent, from 0 to 23
+     * @param minute  the minute-of-hour to represent, from 0 to 59
+     * @return the local date-time, not null
+     * @throws DateTimeException if the value of any field is out of range
+     * @throws DateTimeException if the day-of-month is invalid for the month-year
+     */
+    public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute) {
+        LocalDate date = LocalDate.of(year, month, dayOfMonth);
+        LocalTime time = LocalTime.of(hour, minute);
+        return new LocalDateTime(date, time);
+    }
+
+    /**
+     * Obtains an instance of {@code LocalDateTime} from a date and time.
+     *
+     * @param date  the local date, not null
+     * @param time  the local time, not null
+     * @return the local date-time, not null
+     */
+    public static LocalDateTime of(LocalDate date, LocalTime time) {
+        Objects.requireNonNull(date, "date");
+        Objects.requireNonNull(time, "time");
+        return new LocalDateTime(date, time);
+    }
+
+    /**
+     * Obtains an instance of {@code LocalDateTime} using seconds from the
+     * epoch of 1970-01-01T00:00:00Z.
+     * <p>
+     * This allows the {@link ChronoField#INSTANT_SECONDS epoch-second} field
+     * to be converted to a local date-time. This is primarily intended for
+     * low-level conversions rather than general application usage.
+     *
+     * @param epochSecond  the number of seconds from the epoch of 1970-01-01T00:00:00Z
+     * @param nanoOfSecond  the nanosecond within the second, from 0 to 999,999,999
+     * @param offset  the zone offset, not null
+     * @return the local date-time, not null
+     * @throws DateTimeException if the result exceeds the supported range
+     */
+    public static LocalDateTime ofEpochSecond(long epochSecond, int nanoOfSecond, ZoneOffset offset) {
+        Objects.requireNonNull(offset, "offset");
+        long localSecond = epochSecond + offset.getTotalSeconds();  // overflow caught later
+        long localEpochDay = floorDiv(localSecond, SECONDS_PER_DAY);
+        int secsOfDay = (int)floorMod(localSecond, SECONDS_PER_DAY);
+        LocalDate date = LocalDate.ofEpochDay(localEpochDay);
+        LocalTime time = LocalTime.ofSecondOfDay(secsOfDay);  // ignore nano
+        return new LocalDateTime(date, time);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param date  the date part of the date-time, validated not null
+     * @param time  the time part of the date-time, validated not null
+     */
+    private LocalDateTime(LocalDate date, LocalTime time) {
+        this.date = date;
+        this.time = time;
+    }
+
+    /**
+     * Returns a copy of this date-time with the new date and time, checking
+     * to see if a new object is in fact required.
+     *
+     * @param newDate  the date of the new date-time, not null
+     * @param newTime  the time of the new date-time, not null
+     * @return the date-time, not null
+     */
+    private LocalDateTime with(LocalDate newDate, LocalTime newTime) {
+        if (date == newDate && time == newTime) {
+            return this;
+        }
+        return new LocalDateTime(newDate, newTime);
+    }
+
+    /**
+     * Gets the {@code LocalDate} part of this date-time.
+     * <p>
+     * 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.
+     * <p>
+     * This method returns the primitive {@code int} value for the year.
+     * <p>
+     * The year returned by this method is proleptic as per {@code get(YEAR)}.
+     * To obtain the year-of-era, use {@code get(YEAR_OF_ERA}.
+     *
+     * @return the year, from MIN_YEAR to MAX_YEAR
+     */
+    public int getYear() {
+        return date.getYear();
+    }
+
+    /**
+     * Gets the month-of-year field as an int from 1 to 12.
+     *
+     * @return the month-of-year
+     */
+    public int getMonth() {
+        return date.getMonth();
+    }
+
+    /**
+     * Gets the day-of-month field.
+     * <p>
+     * This method returns the primitive {@code int} value for the day-of-month.
+     *
+     * @return the day-of-month, from 1 to 31
+     */
+    public int getDayOfMonth() {
+        return date.getDayOfMonth();
+    }
+
+    /**
+     * Gets the day-of-week field, which is an integer from 1 to 7.
+     *
+     * @return the day-of-week, from 1 to 7
+     */
+    public int getDayOfWeek() {
+        return date.getDayOfWeek();
+    }
+
+    /**
+     * Gets the {@code LocalTime} part of this date-time.
+     * <p>
+     * This returns a {@code LocalTime} with the same hour, minute, second and
+     * nanosecond as this date-time.
+     *
+     * @return the time part of this date-time, not null
+     */
+    public LocalTime getTime() {
+        return time;
+    }
+
+    /**
+     * Gets the hour-of-day field.
+     *
+     * @return the hour-of-day, from 0 to 23
+     */
+    public int getHour() {
+        return time.getHour();
+    }
+
+    /**
+     * Gets the minute-of-hour field.
+     *
+     * @return the minute-of-hour, from 0 to 59
+     */
+    public int getMinute() {
+        return time.getMinute();
+    }
+
+    /**
+     * Gets the second-of-minute field.
+     *
+     * @return the second-of-minute, from 0 to 59
+     */
+    public int getSecond() {
+        return time.getSecond();
+    }
+
+    /**
+     * Converts this date-time to the number of seconds from the epoch
+     * of 1970-01-01T00:00:00Z.
+     * <p>
+     * This combines this local date-time and the specified offset to calculate the
+     * epoch-second value, which is the number of elapsed seconds from 1970-01-01T00:00:00Z.
+     * Instants on the time-line after the epoch are positive, earlier are negative.
+     * <p>
+     * This default implementation calculates from the epoch-day of the date and the
+     * second-of-day of the time.
+     *
+     * @param offset  the offset to use for the conversion, not null
+     * @return the number of seconds from the epoch of 1970-01-01T00:00:00Z
+     */
+    public long toEpochSecond(ZoneOffset offset) {
+        Objects.requireNonNull(offset, "offset");
+        long epochDay = getDate().toEpochDay();
+        long secs = epochDay * 86400 + getTime().toSecondOfDay();
+        secs -= offset.getTotalSeconds();
+        return secs;
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified period in days added.
+     * <p>
+     * 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.
+     * <p>
+     * For example, 2008-12-31 plus one day would result in 2009-01-01.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param days  the days to add, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the days added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime plusDays(long days) {
+        LocalDate newDate = date.plusDays(days);
+        return with(newDate, time);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified period in seconds added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param seconds  the seconds to add, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the seconds added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime plusSeconds(long seconds) {
+        return plusWithOverflow(date, 0, 0, seconds, 1);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified period added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param newDate  the new date to base the calculation on, not null
+     * @param hours  the hours to add, may be negative
+     * @param minutes the minutes to add, may be negative
+     * @param seconds the seconds to add, may be negative
+     * @param nanos the nanos to add, may be negative
+     * @param sign  the sign to determine add or subtract
+     * @return the combined result, not null
+     */
+    private LocalDateTime plusWithOverflow(LocalDate newDate, long hours, long minutes, long seconds, int sign) {
+        if ((hours | minutes | seconds) == 0) {
+            return with(newDate, time);
+        }
+        long totDays = seconds / SECONDS_PER_DAY +                //   max/24*60*60
+                       minutes / MINUTES_PER_DAY +                //   max/24*60
+                       hours / HOURS_PER_DAY;                     //   max/24
+        totDays *= sign;                                          // total max*0.4237...
+        long totSecs = (seconds % SECONDS_PER_DAY) +
+                       (minutes % MINUTES_PER_DAY) * SECONDS_PER_MINUTE +
+                       (hours % HOURS_PER_DAY) * SECONDS_PER_HOUR;
+        long curSoD = time.toSecondOfDay();
+        totSecs = totSecs * sign + curSoD;                    // total 432000000000000
+        totDays += floorDiv(totSecs, SECONDS_PER_DAY);
+
+        int newSoD = (int)floorMod(totSecs, SECONDS_PER_DAY);
+        LocalTime newTime = (newSoD == curSoD ? time : LocalTime.ofSecondOfDay(newSoD));
+        return with(newDate.plusDays(totDays), newTime);
+    }
+
+    /**
+     * Compares this date-time to another date-time.
+     * <p>
+     * The comparison is primarily based on the date-time, from earliest to latest.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     * <p>
+     * If all the date-times being compared are instances of {@code LocalDateTime},
+     * then the comparison will be entirely based on the date-time.
+     * If some dates being compared are in different chronologies, then the
+     * chronology is also considered, see {@link ChronoLocalDateTime#compareTo}.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     */
+    public int compareTo(LocalDateTime other) {
+        int cmp = date.compareTo(other.getDate());
+        if (cmp == 0) {
+            cmp = time.compareTo(other.getTime());
+        }
+        return cmp;
+    }
+
+    /**
+     * Checks if this date-time is equal to another date-time.
+     * <p>
+     * Compares this {@code LocalDateTime} with another ensuring that the date-time is the same.
+     * Only objects of type {@code LocalDateTime} are compared, other types return false.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other date-time
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof LocalDateTime) {
+            LocalDateTime other = (LocalDateTime) obj;
+            return date.equals(other.date) && time.equals(other.time);
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this date-time.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return date.hashCode() ^ time.hashCode();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/tools/src/build/tools/tzdb/LocalTime.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,388 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package build.tools.tzdb;
+
+import static build.tools.tzdb.ChronoField.HOUR_OF_DAY;
+import static build.tools.tzdb.ChronoField.MINUTE_OF_HOUR;
+import static build.tools.tzdb.ChronoField.SECOND_OF_MINUTE;
+import static build.tools.tzdb.ChronoField.SECOND_OF_DAY;
+
+import java.util.Objects;
+
+/**
+ * A time without time-zone in the ISO-8601 calendar system,
+ * such as {@code 10:15:30}.
+ *
+ */
+final class LocalTime {
+
+    /**
+     * The minimum supported {@code LocalTime}, '00:00'.
+     * This is the time of midnight at the start of the day.
+     */
+    public static final LocalTime MIN;
+    /**
+     * The minimum supported {@code LocalTime}, '23:59:59.999999999'.
+     * This is the time just before midnight at the end of the day.
+     */
+    public static final LocalTime MAX;
+    /**
+     * The time of midnight at the start of the day, '00:00'.
+     */
+    public static final LocalTime MIDNIGHT;
+    /**
+     * The time of noon in the middle of the day, '12:00'.
+     */
+    public static final LocalTime NOON;
+    /**
+     * Constants for the local time of each hour.
+     */
+    private static final LocalTime[] HOURS = new LocalTime[24];
+    static {
+        for (int i = 0; i < HOURS.length; i++) {
+            HOURS[i] = new LocalTime(i, 0, 0);
+        }
+        MIDNIGHT = HOURS[0];
+        NOON = HOURS[12];
+        MIN = HOURS[0];
+        MAX = new LocalTime(23, 59, 59);
+    }
+
+    /**
+     * Hours per day.
+     */
+    static final int HOURS_PER_DAY = 24;
+    /**
+     * Minutes per hour.
+     */
+    static final int MINUTES_PER_HOUR = 60;
+    /**
+     * Minutes per day.
+     */
+    static final int MINUTES_PER_DAY = MINUTES_PER_HOUR * HOURS_PER_DAY;
+    /**
+     * Seconds per minute.
+     */
+    static final int SECONDS_PER_MINUTE = 60;
+    /**
+     * Seconds per hour.
+     */
+    static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;
+    /**
+     * Seconds per day.
+     */
+    static final int SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY;
+    /**
+     * Milliseconds per day.
+     */
+    static final long MILLIS_PER_DAY = SECONDS_PER_DAY * 1000L;
+    /**
+     * Microseconds per day.
+     */
+    static final long MICROS_PER_DAY = SECONDS_PER_DAY * 1000_000L;
+
+    /**
+     * The hour.
+     */
+    private final byte hour;
+    /**
+     * The minute.
+     */
+    private final byte minute;
+    /**
+     * The second.
+     */
+    private final byte second;
+
+    /**
+     * Obtains an instance of {@code LocalTime} from an hour and minute.
+     * <p>
+     * The second and nanosecond fields will be set to zero by this factory method.
+     * <p>
+     * This factory may return a cached value, but applications must not rely on this.
+     *
+     * @param hour  the hour-of-day to represent, from 0 to 23
+     * @param minute  the minute-of-hour to represent, from 0 to 59
+     * @return the local time, not null
+     * @throws DateTimeException if the value of any field is out of range
+     */
+    public static LocalTime of(int hour, int minute) {
+        HOUR_OF_DAY.checkValidValue(hour);
+        if (minute == 0) {
+            return HOURS[hour];  // for performance
+        }
+        MINUTE_OF_HOUR.checkValidValue(minute);
+        return new LocalTime(hour, minute, 0);
+    }
+
+    /**
+     * Obtains an instance of {@code LocalTime} from an hour, minute and second.
+     * <p>
+     * The nanosecond field will be set to zero by this factory method.
+     * <p>
+     * This factory may return a cached value, but applications must not rely on this.
+     *
+     * @param hour  the hour-of-day to represent, from 0 to 23
+     * @param minute  the minute-of-hour to represent, from 0 to 59
+     * @param second  the second-of-minute to represent, from 0 to 59
+     * @return the local time, not null
+     * @throws DateTimeException if the value of any field is out of range
+     */
+    public static LocalTime of(int hour, int minute, int second) {
+        HOUR_OF_DAY.checkValidValue(hour);
+        if ((minute | second) == 0) {
+            return HOURS[hour];  // for performance
+        }
+        MINUTE_OF_HOUR.checkValidValue(minute);
+        SECOND_OF_MINUTE.checkValidValue(second);
+        return new LocalTime(hour, minute, second);
+    }
+
+    /**
+     * Obtains an instance of {@code LocalTime} from a second-of-day value.
+     * <p>
+     * This factory may return a cached value, but applications must not rely on this.
+     *
+     * @param secondOfDay  the second-of-day, from {@code 0} to {@code 24 * 60 * 60 - 1}
+     * @return the local time, not null
+     * @throws DateTimeException if the second-of-day value is invalid
+     */
+    public static LocalTime ofSecondOfDay(int secondOfDay) {
+        SECOND_OF_DAY.checkValidValue(secondOfDay);
+        int hours = secondOfDay / SECONDS_PER_HOUR;
+        secondOfDay -= hours * SECONDS_PER_HOUR;
+        int minutes = secondOfDay / SECONDS_PER_MINUTE;
+        secondOfDay -= minutes * SECONDS_PER_MINUTE;
+        return create(hours, minutes, secondOfDay);
+    }
+
+
+    /**
+     * Creates a local time from the hour, minute, second and nanosecond fields.
+     * <p>
+     * This factory may return a cached value, but applications must not rely on this.
+     *
+     * @param hour  the hour-of-day to represent, validated from 0 to 23
+     * @param minute  the minute-of-hour to represent, validated from 0 to 59
+     * @param second  the second-of-minute to represent, validated from 0 to 59
+     * @return the local time, not null
+     */
+    private static LocalTime create(int hour, int minute, int second) {
+        if ((minute | second) == 0) {
+            return HOURS[hour];
+        }
+        return new LocalTime(hour, minute, second);
+    }
+
+    /**
+     * Constructor, previously validated.
+     *
+     * @param hour  the hour-of-day to represent, validated from 0 to 23
+     * @param minute  the minute-of-hour to represent, validated from 0 to 59
+     * @param second  the second-of-minute to represent, validated from 0 to 59
+     */
+    private LocalTime(int hour, int minute, int second) {
+        this.hour = (byte) hour;
+        this.minute = (byte) minute;
+        this.second = (byte) second;
+    }
+
+    /**
+     * Gets the hour-of-day field.
+     *
+     * @return the hour-of-day, from 0 to 23
+     */
+    public int getHour() {
+        return hour;
+    }
+
+    /**
+     * Gets the minute-of-hour field.
+     *
+     * @return the minute-of-hour, from 0 to 59
+     */
+    public int getMinute() {
+        return minute;
+    }
+
+    /**
+     * Gets the second-of-minute field.
+     *
+     * @return the second-of-minute, from 0 to 59
+     */
+    public int getSecond() {
+        return second;
+    }
+
+    /**
+     * Returns a copy of this {@code LocalTime} with the specified period in seconds added.
+     * <p>
+     * This adds the specified number of seconds to this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param secondstoAdd  the seconds to add, may be negative
+     * @return a {@code LocalTime} based on this time with the seconds added, not null
+     */
+    public LocalTime plusSeconds(long secondstoAdd) {
+        if (secondstoAdd == 0) {
+            return this;
+        }
+        int sofd = hour * SECONDS_PER_HOUR +
+                    minute * SECONDS_PER_MINUTE + second;
+        int newSofd = ((int) (secondstoAdd % SECONDS_PER_DAY) + sofd + SECONDS_PER_DAY) % SECONDS_PER_DAY;
+        if (sofd == newSofd) {
+            return this;
+        }
+        int newHour = newSofd / SECONDS_PER_HOUR;
+        int newMinute = (newSofd / SECONDS_PER_MINUTE) % MINUTES_PER_HOUR;
+        int newSecond = newSofd % SECONDS_PER_MINUTE;
+        return create(newHour, newMinute, newSecond);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalTime} with the specified period in seconds subtracted.
+     * <p>
+     * This subtracts the specified number of seconds from this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param secondsToSubtract  the seconds to subtract, may be negative
+     * @return a {@code LocalTime} based on this time with the seconds subtracted, not null
+     */
+    public LocalTime minusSeconds(long secondsToSubtract) {
+        return plusSeconds(-(secondsToSubtract % SECONDS_PER_DAY));
+    }
+
+    /**
+     * Extracts the time as seconds of day,
+     * from {@code 0} to {@code 24 * 60 * 60 - 1}.
+     *
+     * @return the second-of-day equivalent to this time
+     */
+    public int toSecondOfDay() {
+        int total = hour * SECONDS_PER_HOUR;
+        total += minute * SECONDS_PER_MINUTE;
+        total += second;
+        return total;
+    }
+
+     /**
+     * Compares this {@code LocalTime} to another time.
+     * <p>
+     * The comparison is based on the time-line position of the local times within a day.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     *
+     * @param other  the other time to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     * @throws NullPointerException if {@code other} is null
+     */
+    public int compareTo(LocalTime other) {
+        int cmp = Integer.compare(hour, other.hour);
+        if (cmp == 0) {
+            cmp = Integer.compare(minute, other.minute);
+            if (cmp == 0) {
+                cmp = Integer.compare(second, other.second);
+             }
+        }
+        return cmp;
+    }
+
+    /**
+     * Checks if this time is equal to another time.
+     * <p>
+     * The comparison is based on the time-line position of the time within a day.
+     * <p>
+     * Only objects of type {@code LocalTime} are compared, other types return false.
+     * To compare the date of two {@code TemporalAccessor} instances, use
+     * {@link ChronoField#NANO_OF_DAY} as a comparator.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other time
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof LocalTime) {
+            LocalTime other = (LocalTime) obj;
+            return hour == other.hour && minute == other.minute &&
+                    second == other.second;
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this time.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        long sod = toSecondOfDay();
+        return (int) (sod ^ (sod >>> 32));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/tools/src/build/tools/tzdb/TimeDefinition.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package build.tools.tzdb;
+
+import java.util.Objects;
+
+/**
+ * A definition of the way a local time can be converted to the actual
+ * transition date-time.
+ * <p>
+ * Time zone rules are expressed in one of three ways:
+ * <p><ul>
+ * <li>Relative to UTC</li>
+ * <li>Relative to the standard offset in force</li>
+ * <li>Relative to the wall offset (what you would see on a clock on the wall)</li>
+ * </ul><p>
+ */
+public enum TimeDefinition {
+    /** The local date-time is expressed in terms of the UTC offset. */
+    UTC,
+    /** The local date-time is expressed in terms of the wall offset. */
+    WALL,
+    /** The local date-time is expressed in terms of the standard offset. */
+    STANDARD;
+
+    /**
+     * Converts the specified local date-time to the local date-time actually
+     * seen on a wall clock.
+     * <p>
+     * This method converts using the type of this enum.
+     * The output is defined relative to the 'before' offset of the transition.
+     * <p>
+     * The UTC type uses the UTC offset.
+     * The STANDARD type uses the standard offset.
+     * The WALL type returns the input date-time.
+     * The result is intended for use with the wall-offset.
+     *
+     * @param dateTime  the local date-time, not null
+     * @param standardOffset  the standard offset, not null
+     * @param wallOffset  the wall offset, not null
+     * @return the date-time relative to the wall/before offset, not null
+     */
+    public LocalDateTime createDateTime(LocalDateTime dateTime, ZoneOffset standardOffset, ZoneOffset wallOffset) {
+        switch (this) {
+            case UTC: {
+                int difference = wallOffset.getTotalSeconds() - ZoneOffset.UTC.getTotalSeconds();
+                return dateTime.plusSeconds(difference);
+            }
+            case STANDARD: {
+                int difference = wallOffset.getTotalSeconds() - standardOffset.getTotalSeconds();
+                return dateTime.plusSeconds(difference);
+            }
+            default:  // WALL
+                return dateTime;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/tools/src/build/tools/tzdb/TzdbZoneRulesCompiler.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,876 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package build.tools.tzdb;
+
+import static build.tools.tzdb.Utils.*;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.text.ParsePosition;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.StringTokenizer;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.jar.JarOutputStream;
+import java.util.zip.ZipEntry;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A builder that can read the TZDB time-zone files and build {@code ZoneRules} instances.
+ *
+ * @since 1.8
+ */
+public final class TzdbZoneRulesCompiler {
+
+    private static final Matcher YEAR = Pattern.compile("(?i)(?<min>min)|(?<max>max)|(?<only>only)|(?<year>[0-9]+)").matcher("");
+    private static final Matcher MONTH = Pattern.compile("(?i)(jan)|(feb)|(mar)|(apr)|(may)|(jun)|(jul)|(aug)|(sep)|(oct)|(nov)|(dec)").matcher("");
+    private static final Matcher DOW = Pattern.compile("(?i)(mon)|(tue)|(wed)|(thu)|(fri)|(sat)|(sun)").matcher("");
+    private static final Matcher TIME = Pattern.compile("(?<neg>-)?+(?<hour>[0-9]{1,2})(:(?<minute>[0-5][0-9]))?+(:(?<second>[0-5][0-9]))?+").matcher("");
+
+    /**
+     * Constant for MJD 1972-01-01.
+     */
+    private static final long MJD_1972_01_01 = 41317L;
+
+    /**
+     * Reads a set of TZDB files and builds a single combined data file.
+     *
+     * @param args  the arguments
+     */
+    public static void main(String[] args) {
+        if (args.length < 2) {
+            outputHelp();
+            return;
+        }
+
+        // parse args
+        String version = null;
+        File baseSrcDir = null;
+        File dstDir = null;
+        boolean verbose = false;
+
+        // parse options
+        int i;
+        for (i = 0; i < args.length; i++) {
+            String arg = args[i];
+            if (arg.startsWith("-") == false) {
+                break;
+            }
+            if ("-srcdir".equals(arg)) {
+                if (baseSrcDir == null && ++i < args.length) {
+                    baseSrcDir = new File(args[i]);
+                    continue;
+                }
+            } else if ("-dstdir".equals(arg)) {
+                if (dstDir == null && ++i < args.length) {
+                    dstDir = new File(args[i]);
+                    continue;
+                }
+            } else if ("-version".equals(arg)) {
+                if (version == null && ++i < args.length) {
+                    version = args[i];
+                    continue;
+                }
+            } else if ("-verbose".equals(arg)) {
+                if (verbose == false) {
+                    verbose = true;
+                    continue;
+                }
+            } else if ("-help".equals(arg) == false) {
+                System.out.println("Unrecognised option: " + arg);
+            }
+            outputHelp();
+            return;
+        }
+
+        // check source directory
+        if (baseSrcDir == null) {
+            System.out.println("Source directory must be specified using -srcdir: " + baseSrcDir);
+            return;
+        }
+        if (baseSrcDir.isDirectory() == false) {
+            System.out.println("Source does not exist or is not a directory: " + baseSrcDir);
+            return;
+        }
+        dstDir = (dstDir != null ? dstDir : baseSrcDir);
+
+        // parse source file names
+        List<String> srcFileNames = Arrays.asList(Arrays.copyOfRange(args, i, args.length));
+        if (srcFileNames.isEmpty()) {
+            System.out.println("Source filenames not specified, using default set");
+            System.out.println("(africa antarctica asia australasia backward etcetera europe northamerica southamerica)");
+            srcFileNames = Arrays.asList("africa", "antarctica", "asia", "australasia", "backward",
+                    "etcetera", "europe", "northamerica", "southamerica");
+        }
+
+        // find source directories to process
+        List<File> srcDirs = new ArrayList<>();
+        if (version != null) {
+            //  if the "version" specified, as in jdk repo, the "baseSrcDir" is
+            //  the "srcDir" that contains the tzdb data.
+            srcDirs.add(baseSrcDir);
+        } else {
+            File[] dirs = baseSrcDir.listFiles();
+            for (File dir : dirs) {
+                if (dir.isDirectory() && dir.getName().matches("[12][0-9]{3}[A-Za-z0-9._-]+")) {
+                    srcDirs.add(dir);
+                }
+            }
+        }
+        if (srcDirs.isEmpty()) {
+            System.out.println("Source directory contains no valid source folders: " + baseSrcDir);
+            return;
+        }
+        // check destination directory
+        if (dstDir.exists() == false && dstDir.mkdirs() == false) {
+            System.out.println("Destination directory could not be created: " + dstDir);
+            return;
+        }
+        if (dstDir.isDirectory() == false) {
+            System.out.println("Destination is not a directory: " + dstDir);
+            return;
+        }
+        process(srcDirs, srcFileNames, dstDir, version, verbose);
+        System.exit(0);
+    }
+
+    /**
+     * Output usage text for the command line.
+     */
+    private static void outputHelp() {
+        System.out.println("Usage: TzdbZoneRulesCompiler <options> <tzdb source filenames>");
+        System.out.println("where options include:");
+        System.out.println("   -srcdir <directory>   Where to find source directories (required)");
+        System.out.println("   -dstdir <directory>   Where to output generated files (default srcdir)");
+        System.out.println("   -version <version>    Specify the version, such as 2009a (optional)");
+        System.out.println("   -help                 Print this usage message");
+        System.out.println("   -verbose              Output verbose information during compilation");
+        System.out.println(" There must be one directory for each version in srcdir");
+        System.out.println(" Each directory must have the name of the version, such as 2009a");
+        System.out.println(" Each directory must contain the unpacked tzdb files, such as asia or europe");
+        System.out.println(" Directories must match the regex [12][0-9][0-9][0-9][A-Za-z0-9._-]+");
+        System.out.println(" There will be one jar file for each version and one combined jar in dstdir");
+        System.out.println(" If the version is specified, only that version is processed");
+    }
+
+    /**
+     * Process to create the jar files.
+     */
+    private static void process(List<File> srcDirs, List<String> srcFileNames, File dstDir, String version, boolean verbose) {
+        // build actual jar files
+        Map<String, SortedMap<String, ZoneRules>> allBuiltZones = new TreeMap<>();
+        Set<String> allRegionIds = new TreeSet<String>();
+        Set<ZoneRules> allRules = new HashSet<ZoneRules>();
+
+        for (File srcDir : srcDirs) {
+            // source files in this directory
+            List<File> srcFiles = new ArrayList<>();
+            for (String srcFileName : srcFileNames) {
+                File file = new File(srcDir, srcFileName);
+                if (file.exists()) {
+                    srcFiles.add(file);
+                }
+            }
+            if (srcFiles.isEmpty()) {
+                continue;  // nothing to process
+            }
+
+            // compile
+            String loopVersion = srcDir.getName();
+            TzdbZoneRulesCompiler compiler = new TzdbZoneRulesCompiler(loopVersion, srcFiles, verbose);
+            try {
+                // compile
+                compiler.compile();
+                SortedMap<String, ZoneRules> builtZones = compiler.getZones();
+
+                // output version-specific file
+                File dstFile = version == null ? new File(dstDir, "tzdb" + loopVersion + ".jar")
+                                               : new File(dstDir, "tzdb.jar");
+                if (verbose) {
+                    System.out.println("Outputting file: " + dstFile);
+                }
+                outputFile(dstFile, loopVersion, builtZones);
+
+                // create totals
+                allBuiltZones.put(loopVersion, builtZones);
+                allRegionIds.addAll(builtZones.keySet());
+                allRules.addAll(builtZones.values());
+            } catch (Exception ex) {
+                System.out.println("Failed: " + ex.toString());
+                ex.printStackTrace();
+                System.exit(1);
+            }
+        }
+
+        // output merged file
+        if (version == null) {
+            File dstFile = new File(dstDir, "tzdb-all.jar");
+            if (verbose) {
+                System.out.println("Outputting combined file: " + dstFile);
+            }
+            outputFile(dstFile, allBuiltZones, allRegionIds, allRules);
+        }
+    }
+
+    /**
+     * Outputs the file.
+     */
+    private static void outputFile(File dstFile,
+                                   String version,
+                                   SortedMap<String, ZoneRules> builtZones) {
+        Map<String, SortedMap<String, ZoneRules>> loopAllBuiltZones = new TreeMap<>();
+        loopAllBuiltZones.put(version, builtZones);
+        Set<String> loopAllRegionIds = new TreeSet<String>(builtZones.keySet());
+        Set<ZoneRules> loopAllRules = new HashSet<ZoneRules>(builtZones.values());
+        outputFile(dstFile, loopAllBuiltZones, loopAllRegionIds, loopAllRules);
+    }
+
+    /**
+     * Outputs the file.
+     */
+    private static void outputFile(File dstFile,
+                                   Map<String, SortedMap<String, ZoneRules>> allBuiltZones,
+                                   Set<String> allRegionIds,
+                                   Set<ZoneRules> allRules)
+    {
+        try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(dstFile))) {
+            outputTZEntry(jos, allBuiltZones, allRegionIds, allRules);
+        } catch (Exception ex) {
+            System.out.println("Failed: " + ex.toString());
+            ex.printStackTrace();
+            System.exit(1);
+        }
+    }
+
+    /**
+     * Outputs the timezone entry in the JAR file.
+     */
+    private static void outputTZEntry(JarOutputStream jos,
+                                      Map<String, SortedMap<String, ZoneRules>> allBuiltZones,
+                                      Set<String> allRegionIds,
+                                      Set<ZoneRules> allRules) {
+        // this format is not publicly specified
+        try {
+            jos.putNextEntry(new ZipEntry("TZDB.dat"));
+            DataOutputStream out = new DataOutputStream(jos);
+
+            // file version
+            out.writeByte(1);
+            // group
+            out.writeUTF("TZDB");
+            // versions
+            String[] versionArray = allBuiltZones.keySet().toArray(new String[allBuiltZones.size()]);
+            out.writeShort(versionArray.length);
+            for (String version : versionArray) {
+                out.writeUTF(version);
+            }
+            // regions
+            String[] regionArray = allRegionIds.toArray(new String[allRegionIds.size()]);
+            out.writeShort(regionArray.length);
+            for (String regionId : regionArray) {
+                out.writeUTF(regionId);
+            }
+            // rules
+            List<ZoneRules> rulesList = new ArrayList<>(allRules);
+            out.writeShort(rulesList.size());
+            ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
+            for (ZoneRules rules : rulesList) {
+                baos.reset();
+                DataOutputStream dataos = new DataOutputStream(baos);
+                rules.writeExternal(dataos);
+                dataos.close();
+                byte[] bytes = baos.toByteArray();
+                out.writeShort(bytes.length);
+                out.write(bytes);
+            }
+            // link version-region-rules
+            for (String version : allBuiltZones.keySet()) {
+                out.writeShort(allBuiltZones.get(version).size());
+                for (Map.Entry<String, ZoneRules> entry : allBuiltZones.get(version).entrySet()) {
+                     int regionIndex = Arrays.binarySearch(regionArray, entry.getKey());
+                     int rulesIndex = rulesList.indexOf(entry.getValue());
+                     out.writeShort(regionIndex);
+                     out.writeShort(rulesIndex);
+                }
+            }
+            out.flush();
+            jos.closeEntry();
+        } catch (Exception ex) {
+            System.out.println("Failed: " + ex.toString());
+            ex.printStackTrace();
+            System.exit(1);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /** The TZDB rules. */
+    private final Map<String, List<TZDBRule>> rules = new HashMap<>();
+
+    /** The TZDB zones. */
+    private final Map<String, List<TZDBZone>> zones = new HashMap<>();
+    /** The TZDB links. */
+
+    private final Map<String, String> links = new HashMap<>();
+
+    /** The built zones. */
+    private final SortedMap<String, ZoneRules> builtZones = new TreeMap<>();
+
+
+    /** The version to produce. */
+    private final String version;
+
+    /** The source files. */
+
+    private final List<File> sourceFiles;
+
+    /** The version to produce. */
+    private final boolean verbose;
+
+    /**
+     * Creates an instance if you want to invoke the compiler manually.
+     *
+     * @param version  the version, such as 2009a, not null
+     * @param sourceFiles  the list of source files, not empty, not null
+     * @param verbose  whether to output verbose messages
+     */
+    public TzdbZoneRulesCompiler(String version, List<File> sourceFiles, boolean verbose) {
+        this.version = version;
+        this.sourceFiles = sourceFiles;
+        this.verbose = verbose;
+    }
+
+    /**
+     * Compile the rules file.
+     * <p>
+     * Use {@link #getZones()} to retrieve the parsed data.
+     *
+     * @throws Exception if an error occurs
+     */
+    public void compile() throws Exception {
+        printVerbose("Compiling TZDB version " + version);
+        parseFiles();
+        buildZoneRules();
+        printVerbose("Compiled TZDB version " + version);
+    }
+
+    /**
+     * Gets the parsed zone rules.
+     *
+     * @return the parsed zone rules, not null
+     */
+    public SortedMap<String, ZoneRules> getZones() {
+        return builtZones;
+    }
+
+    /**
+     * Parses the source files.
+     *
+     * @throws Exception if an error occurs
+     */
+    private void parseFiles() throws Exception {
+        for (File file : sourceFiles) {
+            printVerbose("Parsing file: " + file);
+            parseFile(file);
+        }
+    }
+
+    /**
+     * Parses a source file.
+     *
+     * @param file  the file being read, not null
+     * @throws Exception if an error occurs
+     */
+    private void parseFile(File file) throws Exception {
+        int lineNumber = 1;
+        String line = null;
+        BufferedReader in = null;
+        try {
+            in = new BufferedReader(new FileReader(file));
+            List<TZDBZone> openZone = null;
+            for ( ; (line = in.readLine()) != null; lineNumber++) {
+                int index = line.indexOf('#');  // remove comments (doesn't handle # in quotes)
+                if (index >= 0) {
+                    line = line.substring(0, index);
+                }
+                if (line.trim().length() == 0) {  // ignore blank lines
+                    continue;
+                }
+                StringTokenizer st = new StringTokenizer(line, " \t");
+                if (openZone != null && Character.isWhitespace(line.charAt(0)) && st.hasMoreTokens()) {
+                    if (parseZoneLine(st, openZone)) {
+                        openZone = null;
+                    }
+                } else {
+                    if (st.hasMoreTokens()) {
+                        String first = st.nextToken();
+                        if (first.equals("Zone")) {
+                            if (st.countTokens() < 3) {
+                                printVerbose("Invalid Zone line in file: " + file + ", line: " + line);
+                                throw new IllegalArgumentException("Invalid Zone line");
+                            }
+                            openZone = new ArrayList<>();
+                            zones.put(st.nextToken(), openZone);
+                            if (parseZoneLine(st, openZone)) {
+                                openZone = null;
+                            }
+                        } else {
+                            openZone = null;
+                            if (first.equals("Rule")) {
+                                if (st.countTokens() < 9) {
+                                    printVerbose("Invalid Rule line in file: " + file + ", line: " + line);
+                                    throw new IllegalArgumentException("Invalid Rule line");
+                                }
+                                parseRuleLine(st);
+
+                            } else if (first.equals("Link")) {
+                                if (st.countTokens() < 2) {
+                                    printVerbose("Invalid Link line in file: " + file + ", line: " + line);
+                                    throw new IllegalArgumentException("Invalid Link line");
+                                }
+                                String realId = st.nextToken();
+                                String aliasId = st.nextToken();
+                                links.put(aliasId, realId);
+
+                            } else {
+                                throw new IllegalArgumentException("Unknown line");
+                            }
+                        }
+                    }
+                }
+            }
+        } catch (Exception ex) {
+            throw new Exception("Failed while processing file '" + file + "' on line " + lineNumber + " '" + line + "'", ex);
+        } finally {
+            try {
+                if (in != null) {
+                    in.close();
+                }
+            } catch (Exception ex) {
+                // ignore NPE and IOE
+            }
+        }
+    }
+
+    /**
+     * Parses a Rule line.
+     *
+     * @param st  the tokenizer, not null
+     */
+    private void parseRuleLine(StringTokenizer st) {
+        TZDBRule rule = new TZDBRule();
+        String name = st.nextToken();
+        if (rules.containsKey(name) == false) {
+            rules.put(name, new ArrayList<TZDBRule>());
+        }
+        rules.get(name).add(rule);
+        rule.startYear = parseYear(st.nextToken(), 0);
+        rule.endYear = parseYear(st.nextToken(), rule.startYear);
+        if (rule.startYear > rule.endYear) {
+            throw new IllegalArgumentException("Year order invalid: " + rule.startYear + " > " + rule.endYear);
+        }
+        parseOptional(st.nextToken());  // type is unused
+        parseMonthDayTime(st, rule);
+        rule.savingsAmount = parsePeriod(st.nextToken());
+        rule.text = parseOptional(st.nextToken());
+    }
+
+    /**
+     * Parses a Zone line.
+     *
+     * @param st  the tokenizer, not null
+     * @return true if the zone is complete
+     */
+    private boolean parseZoneLine(StringTokenizer st, List<TZDBZone> zoneList) {
+        TZDBZone zone = new TZDBZone();
+        zoneList.add(zone);
+        zone.standardOffset = parseOffset(st.nextToken());
+        String savingsRule = parseOptional(st.nextToken());
+        if (savingsRule == null) {
+            zone.fixedSavingsSecs = 0;
+            zone.savingsRule = null;
+        } else {
+            try {
+                zone.fixedSavingsSecs = parsePeriod(savingsRule);
+                zone.savingsRule = null;
+            } catch (Exception ex) {
+                zone.fixedSavingsSecs = null;
+                zone.savingsRule = savingsRule;
+            }
+        }
+        zone.text = st.nextToken();
+        if (st.hasMoreTokens()) {
+            zone.year = Integer.parseInt(st.nextToken());
+            if (st.hasMoreTokens()) {
+                parseMonthDayTime(st, zone);
+            }
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    /**
+     * Parses a Rule line.
+     *
+     * @param st  the tokenizer, not null
+     * @param mdt  the object to parse into, not null
+     */
+    private void parseMonthDayTime(StringTokenizer st, TZDBMonthDayTime mdt) {
+        mdt.month = parseMonth(st.nextToken());
+        if (st.hasMoreTokens()) {
+            String dayRule = st.nextToken();
+            if (dayRule.startsWith("last")) {
+                mdt.dayOfMonth = -1;
+                mdt.dayOfWeek = parseDayOfWeek(dayRule.substring(4));
+                mdt.adjustForwards = false;
+            } else {
+                int index = dayRule.indexOf(">=");
+                if (index > 0) {
+                    mdt.dayOfWeek = parseDayOfWeek(dayRule.substring(0, index));
+                    dayRule = dayRule.substring(index + 2);
+                } else {
+                    index = dayRule.indexOf("<=");
+                    if (index > 0) {
+                        mdt.dayOfWeek = parseDayOfWeek(dayRule.substring(0, index));
+                        mdt.adjustForwards = false;
+                        dayRule = dayRule.substring(index + 2);
+                    }
+                }
+                mdt.dayOfMonth = Integer.parseInt(dayRule);
+            }
+            if (st.hasMoreTokens()) {
+                String timeStr = st.nextToken();
+                int secsOfDay = parseSecs(timeStr);
+                if (secsOfDay == 86400) {
+                    mdt.endOfDay = true;
+                    secsOfDay = 0;
+                }
+                LocalTime time = LocalTime.ofSecondOfDay(secsOfDay);
+                mdt.time = time;
+                mdt.timeDefinition = parseTimeDefinition(timeStr.charAt(timeStr.length() - 1));
+            }
+        }
+    }
+
+    private int parseYear(String str, int defaultYear) {
+        if (YEAR.reset(str).matches()) {
+            if (YEAR.group("min") != null) {
+                return YEAR_MIN_VALUE;
+            } else if (YEAR.group("max") != null) {
+                return YEAR_MAX_VALUE;
+            } else if (YEAR.group("only") != null) {
+                return defaultYear;
+            }
+            return Integer.parseInt(YEAR.group("year"));
+        }
+        throw new IllegalArgumentException("Unknown year: " + str);
+    }
+
+    private int parseMonth(String str) {
+        if (MONTH.reset(str).matches()) {
+            for (int moy = 1; moy < 13; moy++) {
+                if (MONTH.group(moy) != null) {
+                    return moy;
+                }
+            }
+        }
+        throw new IllegalArgumentException("Unknown month: " + str);
+    }
+
+    private int parseDayOfWeek(String str) {
+        if (DOW.reset(str).matches()) {
+            for (int dow = 1; dow < 8; dow++) {
+                if (DOW.group(dow) != null) {
+                    return dow;
+                }
+            }
+        }
+        throw new IllegalArgumentException("Unknown day-of-week: " + str);
+    }
+
+    private String parseOptional(String str) {
+        return str.equals("-") ? null : str;
+    }
+
+    private int parseSecs(String str) {
+        if (str.equals("-")) {
+            return 0;
+        }
+        try {
+            if (TIME.reset(str).find()) {
+                int secs = Integer.parseInt(TIME.group("hour")) * 60 * 60;
+                if (TIME.group("minute") != null) {
+                    secs += Integer.parseInt(TIME.group("minute")) * 60;
+                }
+                if (TIME.group("second") != null) {
+                    secs += Integer.parseInt(TIME.group("second"));
+                }
+                if (TIME.group("neg") != null) {
+                    secs = -secs;
+                }
+                return secs;
+            }
+        } catch (NumberFormatException x) {}
+        throw new IllegalArgumentException(str);
+    }
+
+    private ZoneOffset parseOffset(String str) {
+        int secs = parseSecs(str);
+        return ZoneOffset.ofTotalSeconds(secs);
+    }
+
+    private int parsePeriod(String str) {
+        return parseSecs(str);
+    }
+
+    private TimeDefinition parseTimeDefinition(char c) {
+        switch (c) {
+            case 's':
+            case 'S':
+                // standard time
+                return TimeDefinition.STANDARD;
+            case 'u':
+            case 'U':
+            case 'g':
+            case 'G':
+            case 'z':
+            case 'Z':
+                // UTC
+                return TimeDefinition.UTC;
+            case 'w':
+            case 'W':
+            default:
+                // wall time
+                return TimeDefinition.WALL;
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Build the rules, zones and links into real zones.
+     *
+     * @throws Exception if an error occurs
+     */
+    private void buildZoneRules() throws Exception {
+        // build zones
+        for (String zoneId : zones.keySet()) {
+            printVerbose("Building zone " + zoneId);
+            List<TZDBZone> tzdbZones = zones.get(zoneId);
+            ZoneRulesBuilder bld = new ZoneRulesBuilder();
+            for (TZDBZone tzdbZone : tzdbZones) {
+                bld = tzdbZone.addToBuilder(bld, rules);
+            }
+            ZoneRules buildRules = bld.toRules(zoneId);
+            builtZones.put(zoneId, buildRules);
+        }
+
+        // build aliases
+        for (String aliasId : links.keySet()) {
+            String realId = links.get(aliasId);
+            printVerbose("Linking alias " + aliasId + " to " + realId);
+            ZoneRules realRules = builtZones.get(realId);
+            if (realRules == null) {
+                realId = links.get(realId);  // try again (handle alias liked to alias)
+                printVerbose("Relinking alias " + aliasId + " to " + realId);
+                realRules = builtZones.get(realId);
+                if (realRules == null) {
+                    throw new IllegalArgumentException("Alias '" + aliasId + "' links to invalid zone '" + realId + "' for '" + version + "'");
+                }
+            }
+            builtZones.put(aliasId, realRules);
+        }
+
+        // remove UTC and GMT
+        builtZones.remove("UTC");
+        builtZones.remove("GMT");
+        builtZones.remove("GMT0");
+        builtZones.remove("GMT+0");
+        builtZones.remove("GMT-0");
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Prints a verbose message.
+     *
+     * @param message  the message, not null
+     */
+    private void printVerbose(String message) {
+        if (verbose) {
+            System.out.println(message);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Class representing a month-day-time in the TZDB file.
+     */
+    abstract class TZDBMonthDayTime {
+        /** The month of the cutover. */
+        int month = 1;
+        /** The day-of-month of the cutover. */
+        int dayOfMonth = 1;
+        /** Whether to adjust forwards. */
+        boolean adjustForwards = true;
+        /** The day-of-week of the cutover. */
+        int dayOfWeek = -1;
+        /** The time of the cutover. */
+        LocalTime time = LocalTime.MIDNIGHT;
+        /** Whether this is midnight end of day. */
+        boolean endOfDay;
+        /** The time of the cutover. */
+        TimeDefinition timeDefinition = TimeDefinition.WALL;
+
+        void adjustToFowards(int year) {
+            if (adjustForwards == false && dayOfMonth > 0) {
+                LocalDate adjustedDate = LocalDate.of(year, month, dayOfMonth).minusDays(6);
+                dayOfMonth = adjustedDate.getDayOfMonth();
+                month = adjustedDate.getMonth();
+                adjustForwards = true;
+            }
+        }
+    }
+
+    /**
+     * Class representing a rule line in the TZDB file.
+     */
+    final class TZDBRule extends TZDBMonthDayTime {
+        /** The start year. */
+        int startYear;
+        /** The end year. */
+        int endYear;
+        /** The amount of savings. */
+        int savingsAmount;
+        /** The text name of the zone. */
+        String text;
+
+        void addToBuilder(ZoneRulesBuilder bld) {
+            adjustToFowards(2004);  // irrelevant, treat as leap year
+            bld.addRuleToWindow(startYear, endYear, month, dayOfMonth, dayOfWeek, time, endOfDay, timeDefinition, savingsAmount);
+        }
+    }
+
+    /**
+     * Class representing a linked set of zone lines in the TZDB file.
+     */
+    final class TZDBZone extends TZDBMonthDayTime {
+        /** The standard offset. */
+        ZoneOffset standardOffset;
+        /** The fixed savings amount. */
+        Integer fixedSavingsSecs;
+        /** The savings rule. */
+        String savingsRule;
+        /** The text name of the zone. */
+        String text;
+        /** The year of the cutover. */
+        int year = YEAR_MAX_VALUE;
+
+        ZoneRulesBuilder addToBuilder(ZoneRulesBuilder bld, Map<String, List<TZDBRule>> rules) {
+            if (year != YEAR_MAX_VALUE) {
+                bld.addWindow(standardOffset, toDateTime(year), timeDefinition);
+            } else {
+                bld.addWindowForever(standardOffset);
+            }
+            if (fixedSavingsSecs != null) {
+                bld.setFixedSavingsToWindow(fixedSavingsSecs);
+            } else {
+                List<TZDBRule> tzdbRules = rules.get(savingsRule);
+                if (tzdbRules == null) {
+                    throw new IllegalArgumentException("Rule not found: " + savingsRule);
+                }
+                for (TZDBRule tzdbRule : tzdbRules) {
+                    tzdbRule.addToBuilder(bld);
+                }
+            }
+            return bld;
+        }
+
+        private LocalDateTime toDateTime(int year) {
+            adjustToFowards(year);
+            LocalDate date;
+            if (dayOfMonth == -1) {
+                dayOfMonth = lengthOfMonth(month, isLeapYear(year));
+                date = LocalDate.of(year, month, dayOfMonth);
+                if (dayOfWeek != -1) {
+                    date = previousOrSame(date, dayOfWeek);
+                }
+            } else {
+                date = LocalDate.of(year, month, dayOfMonth);
+                if (dayOfWeek != -1) {
+                    date = nextOrSame(date, dayOfWeek);
+                }
+            }
+            LocalDateTime ldt = LocalDateTime.of(date, time);
+            if (endOfDay) {
+                ldt = ldt.plusDays(1);
+            }
+            return ldt;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/tools/src/build/tools/tzdb/Utils.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,176 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package build.tools.tzdb;
+
+import java.util.Objects;
+
+class Utils {
+
+    // Returns the largest (closest to positive infinity)
+    public static long floorDiv(long x, long y) {
+        long r = x / y;
+        // if the signs are different and modulo not zero, round down
+        if ((x ^ y) < 0 && (r * y != x)) {
+            r--;
+        }
+        return r;
+    }
+
+    // Returns the floor modulus of the {@code long} arguments.
+    public static long floorMod(long x, long y) {
+        return x - floorDiv(x, y) * y;
+    }
+
+    // Returns the sum of its arguments,
+    public static long addExact(long x, long y) {
+        long r = x + y;
+        // HD 2-12 Overflow iff both arguments have the opposite sign of the result
+        if (((x ^ r) & (y ^ r)) < 0) {
+            throw new ArithmeticException("long overflow");
+        }
+        return r;
+    }
+
+    // Year
+
+    // Returns true if the specified year is a leap year.
+    public static boolean isLeapYear(int year) {
+        return ((year & 3) == 0) && ((year % 100) != 0 || (year % 400) == 0);
+    }
+
+    // The minimum supported year, '-999,999,999'.
+    public static final int YEAR_MIN_VALUE = -999_999_999;
+
+    // The maximum supported year, '+999,999,999'.
+    public static final int YEAR_MAX_VALUE = 999_999_999;
+
+
+    // Gets the length of the specified month in days.
+    public static int lengthOfMonth(int month, boolean leapYear) {
+        switch (month) {
+            case 2:        //FEBRUARY:
+                return (leapYear ? 29 : 28);
+            case 4:        //APRIL:
+            case 6:        //JUNE:
+            case 9:        //SEPTEMBER:
+            case 11:       //NOVEMBER:
+                return 30;
+            default:
+                return 31;
+        }
+    }
+
+    // Gets the maximum length of the specified month in days.
+    public static int maxLengthOfMonth(int month) {
+        switch (month) {
+            case 2:           //FEBRUARY:
+                return 29;
+            case 4:           //APRIL:
+            case 6:           //JUNE:
+            case 9:           //SEPTEMBER:
+            case 11:          //NOVEMBER:
+                return 30;
+            default:
+                return 31;
+        }
+    }
+
+    // DayOfWeek
+
+    // Returns the day-of-week that is the specified number of days after
+    // this one, from 1 to 7 for Monday to Sunday.
+    public static int plusDayOfWeek(int dow, long days) {
+        int amount = (int) (days % 7);
+        return (dow - 1 + (amount + 7)) % 7 + 1;
+    }
+
+    // Returns the day-of-week that is the specified number of days before
+    // this one, from 1 to 7 for Monday to Sunday.
+    public static int minusDayOfWeek(int dow, long days) {
+        return plusDayOfWeek(dow, -(days % 7));
+    }
+
+    // Adjusts the date to the first occurrence of the specified day-of-week
+    // before the date being adjusted unless it is already on that day in
+    // which case the same object is returned.
+    public static LocalDate previousOrSame(LocalDate date, int dayOfWeek) {
+        return adjust(date, dayOfWeek, 1);
+    }
+
+    // Adjusts the date to the first occurrence of the specified day-of-week
+    // after the date being adjusted unless it is already on that day in
+    // which case the same object is returned.
+    public static LocalDate nextOrSame(LocalDate date, int dayOfWeek) {
+        return adjust(date, dayOfWeek, 0);
+    }
+
+    // Implementation of next, previous or current day-of-week.
+    // @param relative  whether the current date is a valid answer
+    private static final LocalDate adjust(LocalDate date, int dow, int relative) {
+        int calDow = date.getDayOfWeek();
+        if (relative < 2 && calDow == dow) {
+            return date;
+        }
+        if ((relative & 1) == 0) {
+            int daysDiff = calDow - dow;
+            return date.plusDays(daysDiff >= 0 ? 7 - daysDiff : -daysDiff);
+        } else {
+            int daysDiff = dow - calDow;
+            return date.minusDays(daysDiff >= 0 ? 7 - daysDiff : -daysDiff);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/tools/src/build/tools/tzdb/ZoneOffset.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,474 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package build.tools.tzdb;
+
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * A time-zone offset from Greenwich/UTC, such as {@code +02:00}.
+ * <p>
+ * A time-zone offset is the period of time that a time-zone differs from Greenwich/UTC.
+ * This is usually a fixed number of hours and minutes.
+ *
+ * @since 1.8
+ */
+final class ZoneOffset implements Comparable<ZoneOffset> {
+
+    /** Cache of time-zone offset by offset in seconds. */
+    private static final ConcurrentMap<Integer, ZoneOffset> SECONDS_CACHE = new ConcurrentHashMap<>(16, 0.75f, 4);
+    /** Cache of time-zone offset by ID. */
+    private static final ConcurrentMap<String, ZoneOffset> ID_CACHE = new ConcurrentHashMap<>(16, 0.75f, 4);
+
+    /**
+     * The number of seconds per hour.
+     */
+    private static final int SECONDS_PER_HOUR = 60 * 60;
+    /**
+     * The number of seconds per minute.
+     */
+    private static final int SECONDS_PER_MINUTE = 60;
+    /**
+     * The number of minutes per hour.
+     */
+    private static final int MINUTES_PER_HOUR = 60;
+    /**
+     * The abs maximum seconds.
+     */
+    private static final int MAX_SECONDS = 18 * SECONDS_PER_HOUR;
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 2357656521762053153L;
+
+    /**
+     * The time-zone offset for UTC, with an ID of 'Z'.
+     */
+    public static final ZoneOffset UTC = ZoneOffset.ofTotalSeconds(0);
+    /**
+     * Constant for the maximum supported offset.
+     */
+    public static final ZoneOffset MIN = ZoneOffset.ofTotalSeconds(-MAX_SECONDS);
+    /**
+     * Constant for the maximum supported offset.
+     */
+    public static final ZoneOffset MAX = ZoneOffset.ofTotalSeconds(MAX_SECONDS);
+
+    /**
+     * The total offset in seconds.
+     */
+    private final int totalSeconds;
+    /**
+     * The string form of the time-zone offset.
+     */
+    private final transient String id;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ZoneOffset} using the ID.
+     * <p>
+     * This method parses the string ID of a {@code ZoneOffset} to
+     * return an instance. The parsing accepts all the formats generated by
+     * {@link #getId()}, plus some additional formats:
+     * <p><ul>
+     * <li>{@code Z} - for UTC
+     * <li>{@code +h}
+     * <li>{@code +hh}
+     * <li>{@code +hh:mm}
+     * <li>{@code -hh:mm}
+     * <li>{@code +hhmm}
+     * <li>{@code -hhmm}
+     * <li>{@code +hh:mm:ss}
+     * <li>{@code -hh:mm:ss}
+     * <li>{@code +hhmmss}
+     * <li>{@code -hhmmss}
+     * </ul><p>
+     * Note that &plusmn; means either the plus or minus symbol.
+     * <p>
+     * The ID of the returned offset will be normalized to one of the formats
+     * described by {@link #getId()}.
+     * <p>
+     * The maximum supported range is from +18:00 to -18:00 inclusive.
+     *
+     * @param offsetId  the offset ID, not null
+     * @return the zone-offset, not null
+     * @throws DateTimeException if the offset ID is invalid
+     */
+    @SuppressWarnings("fallthrough")
+    public static ZoneOffset of(String offsetId) {
+        Objects.requireNonNull(offsetId, "offsetId");
+        // "Z" is always in the cache
+        ZoneOffset offset = ID_CACHE.get(offsetId);
+        if (offset != null) {
+            return offset;
+        }
+
+        // parse - +h, +hh, +hhmm, +hh:mm, +hhmmss, +hh:mm:ss
+        final int hours, minutes, seconds;
+        switch (offsetId.length()) {
+            case 2:
+                offsetId = offsetId.charAt(0) + "0" + offsetId.charAt(1);  // fallthru
+            case 3:
+                hours = parseNumber(offsetId, 1, false);
+                minutes = 0;
+                seconds = 0;
+                break;
+            case 5:
+                hours = parseNumber(offsetId, 1, false);
+                minutes = parseNumber(offsetId, 3, false);
+                seconds = 0;
+                break;
+            case 6:
+                hours = parseNumber(offsetId, 1, false);
+                minutes = parseNumber(offsetId, 4, true);
+                seconds = 0;
+                break;
+            case 7:
+                hours = parseNumber(offsetId, 1, false);
+                minutes = parseNumber(offsetId, 3, false);
+                seconds = parseNumber(offsetId, 5, false);
+                break;
+            case 9:
+                hours = parseNumber(offsetId, 1, false);
+                minutes = parseNumber(offsetId, 4, true);
+                seconds = parseNumber(offsetId, 7, true);
+                break;
+            default:
+                throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid");
+        }
+        char first = offsetId.charAt(0);
+        if (first != '+' && first != '-') {
+            throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid: Plus/minus not found when expected");
+        }
+        if (first == '-') {
+            return ofHoursMinutesSeconds(-hours, -minutes, -seconds);
+        } else {
+            return ofHoursMinutesSeconds(hours, minutes, seconds);
+        }
+    }
+
+    /**
+     * Parse a two digit zero-prefixed number.
+     *
+     * @param offsetId  the offset ID, not null
+     * @param pos  the position to parse, valid
+     * @param precededByColon  should this number be prefixed by a precededByColon
+     * @return the parsed number, from 0 to 99
+     */
+    private static int parseNumber(CharSequence offsetId, int pos, boolean precededByColon) {
+        if (precededByColon && offsetId.charAt(pos - 1) != ':') {
+            throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid: Colon not found when expected");
+        }
+        char ch1 = offsetId.charAt(pos);
+        char ch2 = offsetId.charAt(pos + 1);
+        if (ch1 < '0' || ch1 > '9' || ch2 < '0' || ch2 > '9') {
+            throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid: Non numeric characters found");
+        }
+        return (ch1 - 48) * 10 + (ch2 - 48);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ZoneOffset} using an offset in hours.
+     *
+     * @param hours  the time-zone offset in hours, from -18 to +18
+     * @return the zone-offset, not null
+     * @throws DateTimeException if the offset is not in the required range
+     */
+    public static ZoneOffset ofHours(int hours) {
+        return ofHoursMinutesSeconds(hours, 0, 0);
+    }
+
+    /**
+     * Obtains an instance of {@code ZoneOffset} using an offset in
+     * hours and minutes.
+     * <p>
+     * The sign of the hours and minutes components must match.
+     * Thus, if the hours is negative, the minutes must be negative or zero.
+     * If the hours is zero, the minutes may be positive, negative or zero.
+     *
+     * @param hours  the time-zone offset in hours, from -18 to +18
+     * @param minutes  the time-zone offset in minutes, from 0 to &plusmn;59, sign matches hours
+     * @return the zone-offset, not null
+     * @throws DateTimeException if the offset is not in the required range
+     */
+    public static ZoneOffset ofHoursMinutes(int hours, int minutes) {
+        return ofHoursMinutesSeconds(hours, minutes, 0);
+    }
+
+    /**
+     * Obtains an instance of {@code ZoneOffset} using an offset in
+     * hours, minutes and seconds.
+     * <p>
+     * The sign of the hours, minutes and seconds components must match.
+     * Thus, if the hours is negative, the minutes and seconds must be negative or zero.
+     *
+     * @param hours  the time-zone offset in hours, from -18 to +18
+     * @param minutes  the time-zone offset in minutes, from 0 to &plusmn;59, sign matches hours and seconds
+     * @param seconds  the time-zone offset in seconds, from 0 to &plusmn;59, sign matches hours and minutes
+     * @return the zone-offset, not null
+     * @throws DateTimeException if the offset is not in the required range
+     */
+    public static ZoneOffset ofHoursMinutesSeconds(int hours, int minutes, int seconds) {
+        validate(hours, minutes, seconds);
+        int totalSeconds = totalSeconds(hours, minutes, seconds);
+        return ofTotalSeconds(totalSeconds);
+    }
+
+    /**
+     * Validates the offset fields.
+     *
+     * @param hours  the time-zone offset in hours, from -18 to +18
+     * @param minutes  the time-zone offset in minutes, from 0 to &plusmn;59
+     * @param seconds  the time-zone offset in seconds, from 0 to &plusmn;59
+     * @throws DateTimeException if the offset is not in the required range
+     */
+    private static void validate(int hours, int minutes, int seconds) {
+        if (hours < -18 || hours > 18) {
+            throw new DateTimeException("Zone offset hours not in valid range: value " + hours +
+                    " is not in the range -18 to 18");
+        }
+        if (hours > 0) {
+            if (minutes < 0 || seconds < 0) {
+                throw new DateTimeException("Zone offset minutes and seconds must be positive because hours is positive");
+            }
+        } else if (hours < 0) {
+            if (minutes > 0 || seconds > 0) {
+                throw new DateTimeException("Zone offset minutes and seconds must be negative because hours is negative");
+            }
+        } else if ((minutes > 0 && seconds < 0) || (minutes < 0 && seconds > 0)) {
+            throw new DateTimeException("Zone offset minutes and seconds must have the same sign");
+        }
+        if (Math.abs(minutes) > 59) {
+            throw new DateTimeException("Zone offset minutes not in valid range: abs(value) " +
+                    Math.abs(minutes) + " is not in the range 0 to 59");
+        }
+        if (Math.abs(seconds) > 59) {
+            throw new DateTimeException("Zone offset seconds not in valid range: abs(value) " +
+                    Math.abs(seconds) + " is not in the range 0 to 59");
+        }
+        if (Math.abs(hours) == 18 && (Math.abs(minutes) > 0 || Math.abs(seconds) > 0)) {
+            throw new DateTimeException("Zone offset not in valid range: -18:00 to +18:00");
+        }
+    }
+
+    /**
+     * Calculates the total offset in seconds.
+     *
+     * @param hours  the time-zone offset in hours, from -18 to +18
+     * @param minutes  the time-zone offset in minutes, from 0 to &plusmn;59, sign matches hours and seconds
+     * @param seconds  the time-zone offset in seconds, from 0 to &plusmn;59, sign matches hours and minutes
+     * @return the total in seconds
+     */
+    private static int totalSeconds(int hours, int minutes, int seconds) {
+        return hours * SECONDS_PER_HOUR + minutes * SECONDS_PER_MINUTE + seconds;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ZoneOffset} specifying the total offset in seconds
+     * <p>
+     * The offset must be in the range {@code -18:00} to {@code +18:00}, which corresponds to -64800 to +64800.
+     *
+     * @param totalSeconds  the total time-zone offset in seconds, from -64800 to +64800
+     * @return the ZoneOffset, not null
+     * @throws DateTimeException if the offset is not in the required range
+     */
+    public static ZoneOffset ofTotalSeconds(int totalSeconds) {
+        if (Math.abs(totalSeconds) > MAX_SECONDS) {
+            throw new DateTimeException("Zone offset not in valid range: -18:00 to +18:00");
+        }
+        if (totalSeconds % (15 * SECONDS_PER_MINUTE) == 0) {
+            Integer totalSecs = totalSeconds;
+            ZoneOffset result = SECONDS_CACHE.get(totalSecs);
+            if (result == null) {
+                result = new ZoneOffset(totalSeconds);
+                SECONDS_CACHE.putIfAbsent(totalSecs, result);
+                result = SECONDS_CACHE.get(totalSecs);
+                ID_CACHE.putIfAbsent(result.getId(), result);
+            }
+            return result;
+        } else {
+            return new ZoneOffset(totalSeconds);
+        }
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param totalSeconds  the total time-zone offset in seconds, from -64800 to +64800
+     */
+    private ZoneOffset(int totalSeconds) {
+        super();
+        this.totalSeconds = totalSeconds;
+        id = buildId(totalSeconds);
+    }
+
+    private static String buildId(int totalSeconds) {
+        if (totalSeconds == 0) {
+            return "Z";
+        } else {
+            int absTotalSeconds = Math.abs(totalSeconds);
+            StringBuilder buf = new StringBuilder();
+            int absHours = absTotalSeconds / SECONDS_PER_HOUR;
+            int absMinutes = (absTotalSeconds / SECONDS_PER_MINUTE) % MINUTES_PER_HOUR;
+            buf.append(totalSeconds < 0 ? "-" : "+")
+                .append(absHours < 10 ? "0" : "").append(absHours)
+                .append(absMinutes < 10 ? ":0" : ":").append(absMinutes);
+            int absSeconds = absTotalSeconds % SECONDS_PER_MINUTE;
+            if (absSeconds != 0) {
+                buf.append(absSeconds < 10 ? ":0" : ":").append(absSeconds);
+            }
+            return buf.toString();
+        }
+    }
+
+    /**
+     * Gets the total zone offset in seconds.
+     * <p>
+     * This is the primary way to access the offset amount.
+     * It returns the total of the hours, minutes and seconds fields as a
+     * single offset that can be added to a time.
+     *
+     * @return the total zone offset amount in seconds
+     */
+    public int getTotalSeconds() {
+        return totalSeconds;
+    }
+
+    /**
+     * Gets the normalized zone offset ID.
+     * <p>
+     * The ID is minor variation to the standard ISO-8601 formatted string
+     * for the offset. There are three formats:
+     * <p><ul>
+     * <li>{@code Z} - for UTC (ISO-8601)
+     * <li>{@code +hh:mm} or {@code -hh:mm} - if the seconds are zero (ISO-8601)
+     * <li>{@code +hh:mm:ss} or {@code -hh:mm:ss} - if the seconds are non-zero (not ISO-8601)
+     * </ul><p>
+     *
+     * @return the zone offset ID, not null
+     */
+    public String getId() {
+        return id;
+    }
+
+    /**
+     * Compares this offset to another offset in descending order.
+     * <p>
+     * The offsets are compared in the order that they occur for the same time
+     * of day around the world. Thus, an offset of {@code +10:00} comes before an
+     * offset of {@code +09:00} and so on down to {@code -18:00}.
+     * <p>
+     * The comparison is "consistent with equals", as defined by {@link Comparable}.
+     *
+     * @param other  the other date to compare to, not null
+     * @return the comparator value, negative if less, postive if greater
+     * @throws NullPointerException if {@code other} is null
+     */
+    @Override
+    public int compareTo(ZoneOffset other) {
+        return other.totalSeconds - totalSeconds;
+    }
+
+    /**
+     * Checks if this offset is equal to another offset.
+     * <p>
+     * The comparison is based on the amount of the offset in seconds.
+     * This is equivalent to a comparison by ID.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other offset
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+           return true;
+        }
+        if (obj instanceof ZoneOffset) {
+            return totalSeconds == ((ZoneOffset) obj).totalSeconds;
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this offset.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return totalSeconds;
+    }
+
+    /**
+     * Outputs this offset as a {@code String}, using the normalized ID.
+     *
+     * @return a string representation of this offset, not null
+     */
+    @Override
+    public String toString() {
+        return id;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/tools/src/build/tools/tzdb/ZoneOffsetTransition.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package build.tools.tzdb;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A transition between two offsets caused by a discontinuity in the local time-line.
+ *
+ * @since 1.8
+ */
+final class ZoneOffsetTransition implements Comparable<ZoneOffsetTransition> {
+
+    /**
+     * The local transition date-time at the transition.
+     */
+    private final LocalDateTime transition;
+    /**
+     * The offset before transition.
+     */
+    private final ZoneOffset offsetBefore;
+    /**
+     * The offset after transition.
+     */
+    private final ZoneOffset offsetAfter;
+
+    /**
+     * Creates an instance defining a transition between two offsets.
+     *
+     * @param transition  the transition date-time with the offset before the transition, not null
+     * @param offsetBefore  the offset before the transition, not null
+     * @param offsetAfter  the offset at and after the transition, not null
+     */
+    ZoneOffsetTransition(LocalDateTime transition, ZoneOffset offsetBefore, ZoneOffset offsetAfter) {
+        Objects.requireNonNull(transition, "transition");
+        Objects.requireNonNull(offsetBefore, "offsetBefore");
+        Objects.requireNonNull(offsetAfter, "offsetAfter");
+        if (offsetBefore.equals(offsetAfter)) {
+            throw new IllegalArgumentException("Offsets must not be equal");
+        }
+        this.transition = transition;
+        this.offsetBefore = offsetBefore;
+        this.offsetAfter = offsetAfter;
+    }
+
+    /**
+     * Creates an instance from epoch-second and offsets.
+     *
+     * @param epochSecond  the transition epoch-second
+     * @param offsetBefore  the offset before the transition, not null
+     * @param offsetAfter  the offset at and after the transition, not null
+     */
+    ZoneOffsetTransition(long epochSecond, ZoneOffset offsetBefore, ZoneOffset offsetAfter) {
+        this.transition = LocalDateTime.ofEpochSecond(epochSecond, 0, offsetBefore);
+        this.offsetBefore = offsetBefore;
+        this.offsetAfter = offsetAfter;
+    }
+
+    /**
+     * Gets the transition instant as an epoch second.
+     *
+     * @return the transition epoch second
+     */
+    public long toEpochSecond() {
+        return transition.toEpochSecond(offsetBefore);
+    }
+
+    /**
+     * Gets the local transition date-time, as would be expressed with the 'before' offset.
+     * <p>
+     * This is the date-time where the discontinuity begins expressed with the 'before' offset.
+     * At this instant, the 'after' offset is actually used, therefore the combination of this
+     * date-time and the 'before' offset will never occur.
+     * <p>
+     * The combination of the 'before' date-time and offset represents the same instant
+     * as the 'after' date-time and offset.
+     *
+     * @return the transition date-time expressed with the before offset, not null
+     */
+    public LocalDateTime getDateTimeBefore() {
+        return transition;
+    }
+
+    /**
+     * Gets the local transition date-time, as would be expressed with the 'after' offset.
+     * <p>
+     * This is the first date-time after the discontinuity, when the new offset applies.
+     * <p>
+     * The combination of the 'before' date-time and offset represents the same instant
+     * as the 'after' date-time and offset.
+     *
+     * @return the transition date-time expressed with the after offset, not null
+     */
+    public LocalDateTime getDateTimeAfter() {
+        return transition.plusSeconds(getDurationSeconds());
+    }
+
+    /**
+     * Gets the offset before the transition.
+     * <p>
+     * This is the offset in use before the instant of the transition.
+     *
+     * @return the offset before the transition, not null
+     */
+    public ZoneOffset getOffsetBefore() {
+        return offsetBefore;
+    }
+
+    /**
+     * Gets the offset after the transition.
+     * <p>
+     * This is the offset in use on and after the instant of the transition.
+     *
+     * @return the offset after the transition, not null
+     */
+    public ZoneOffset getOffsetAfter() {
+        return offsetAfter;
+    }
+
+    /**
+     * Gets the duration of the transition in seconds.
+     *
+     * @return the duration in seconds
+     */
+    private int getDurationSeconds() {
+        return getOffsetAfter().getTotalSeconds() - getOffsetBefore().getTotalSeconds();
+    }
+
+    /**
+     * Does this transition represent a gap in the local time-line.
+     * <p>
+     * Gaps occur where there are local date-times that simply do not not exist.
+     * An example would be when the offset changes from {@code +01:00} to {@code +02:00}.
+     * This might be described as 'the clocks will move forward one hour tonight at 1am'.
+     *
+     * @return true if this transition is a gap, false if it is an overlap
+     */
+    public boolean isGap() {
+        return getOffsetAfter().getTotalSeconds() > getOffsetBefore().getTotalSeconds();
+    }
+
+    /**
+     * Does this transition represent a gap in the local time-line.
+     * <p>
+     * Overlaps occur where there are local date-times that exist twice.
+     * An example would be when the offset changes from {@code +02:00} to {@code +01:00}.
+     * This might be described as 'the clocks will move back one hour tonight at 2am'.
+     *
+     * @return true if this transition is an overlap, false if it is a gap
+     */
+    public boolean isOverlap() {
+        return getOffsetAfter().getTotalSeconds() < getOffsetBefore().getTotalSeconds();
+    }
+
+    /**
+     * Checks if the specified offset is valid during this transition.
+     * <p>
+     * This checks to see if the given offset will be valid at some point in the transition.
+     * A gap will always return false.
+     * An overlap will return true if the offset is either the before or after offset.
+     *
+     * @param offset  the offset to check, null returns false
+     * @return true if the offset is valid during the transition
+     */
+    public boolean isValidOffset(ZoneOffset offset) {
+        return isGap() ? false : (getOffsetBefore().equals(offset) || getOffsetAfter().equals(offset));
+    }
+
+    /**
+     * Gets the valid offsets during this transition.
+     * <p>
+     * A gap will return an empty list, while an overlap will return both offsets.
+     *
+     * @return the list of valid offsets
+     */
+    List<ZoneOffset> getValidOffsets() {
+        if (isGap()) {
+            return Collections.emptyList();
+        }
+        return Arrays.asList(getOffsetBefore(), getOffsetAfter());
+    }
+
+    /**
+     * Compares this transition to another based on the transition instant.
+     * <p>
+     * This compares the instants of each transition.
+     * The offsets are ignored, making this order inconsistent with equals.
+     *
+     * @param transition  the transition to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     */
+    @Override
+    public int compareTo(ZoneOffsetTransition transition) {
+        return Long.compare(this.toEpochSecond(), transition.toEpochSecond());
+    }
+
+    /**
+     * Checks if this object equals another.
+     * <p>
+     * The entire state of the object is compared.
+     *
+     * @param other  the other object to compare to, null returns false
+     * @return true if equal
+     */
+    @Override
+    public boolean equals(Object other) {
+        if (other == this) {
+            return true;
+        }
+        if (other instanceof ZoneOffsetTransition) {
+            ZoneOffsetTransition d = (ZoneOffsetTransition) other;
+            return transition.equals(d.transition) &&
+                offsetBefore.equals(d.offsetBefore) && offsetAfter.equals(d.offsetAfter);
+        }
+        return false;
+    }
+
+    /**
+     * Returns a suitable hash code.
+     *
+     * @return the hash code
+     */
+    @Override
+    public int hashCode() {
+        return transition.hashCode() ^ offsetBefore.hashCode() ^ Integer.rotateLeft(offsetAfter.hashCode(), 16);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/tools/src/build/tools/tzdb/ZoneOffsetTransitionRule.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package build.tools.tzdb;
+
+import static build.tools.tzdb.Utils.*;
+import java.util.Objects;
+
+/**
+ * A rule expressing how to create a transition.
+ * <p>
+ * This class allows rules for identifying future transitions to be expressed.
+ * A rule might be written in many forms:
+ * <p><ul>
+ * <li>the 16th March
+ * <li>the Sunday on or after the 16th March
+ * <li>the Sunday on or before the 16th March
+ * <li>the last Sunday in February
+ * </ul><p>
+ * These different rule types can be expressed and queried.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+final class ZoneOffsetTransitionRule {
+
+    /**
+     * The month of the month-day of the first day of the cutover week.
+     * The actual date will be adjusted by the dowChange field.
+     */
+    final int month;
+    /**
+     * The day-of-month of the month-day of the cutover week.
+     * If positive, it is the start of the week where the cutover can occur.
+     * If negative, it represents the end of the week where cutover can occur.
+     * The value is the number of days from the end of the month, such that
+     * {@code -1} is the last day of the month, {@code -2} is the second
+     * to last day, and so on.
+     */
+    final byte dom;
+    /**
+     * The cutover day-of-week, -1 to retain the day-of-month.
+     */
+    final int dow;
+    /**
+     * The cutover time in the 'before' offset.
+     */
+    final LocalTime time;
+    /**
+     * Whether the cutover time is midnight at the end of day.
+     */
+    final boolean timeEndOfDay;
+    /**
+     * The definition of how the local time should be interpreted.
+     */
+    final TimeDefinition timeDefinition;
+    /**
+     * The standard offset at the cutover.
+     */
+    final ZoneOffset standardOffset;
+    /**
+     * The offset before the cutover.
+     */
+    final ZoneOffset offsetBefore;
+    /**
+     * The offset after the cutover.
+     */
+    final ZoneOffset offsetAfter;
+
+    /**
+     * Creates an instance defining the yearly rule to create transitions between two offsets.
+     *
+     * @param month  the month of the month-day of the first day of the cutover week, from 1 to 12
+     * @param dayOfMonthIndicator  the day of the month-day of the cutover week, positive if the week is that
+     *  day or later, negative if the week is that day or earlier, counting from the last day of the month,
+     *  from -28 to 31 excluding 0
+     * @param dayOfWeek  the required day-of-week, -1 if the month-day should not be changed
+     * @param time  the cutover time in the 'before' offset, not null
+     * @param timeEndOfDay  whether the time is midnight at the end of day
+     * @param timeDefnition  how to interpret the cutover
+     * @param standardOffset  the standard offset in force at the cutover, not null
+     * @param offsetBefore  the offset before the cutover, not null
+     * @param offsetAfter  the offset after the cutover, not null
+     * @throws IllegalArgumentException if the day of month indicator is invalid
+     * @throws IllegalArgumentException if the end of day flag is true when the time is not midnight
+     */
+    ZoneOffsetTransitionRule(
+            int month,
+            int dayOfMonthIndicator,
+            int dayOfWeek,
+            LocalTime time,
+            boolean timeEndOfDay,
+            TimeDefinition timeDefnition,
+            ZoneOffset standardOffset,
+            ZoneOffset offsetBefore,
+            ZoneOffset offsetAfter) {
+        Objects.requireNonNull(time, "time");
+        Objects.requireNonNull(timeDefnition, "timeDefnition");
+        Objects.requireNonNull(standardOffset, "standardOffset");
+        Objects.requireNonNull(offsetBefore, "offsetBefore");
+        Objects.requireNonNull(offsetAfter, "offsetAfter");
+        if (month < 1 || month > 12) {
+            throw new IllegalArgumentException("month must be between 1 and 12");
+        }
+        if (dayOfMonthIndicator < -28 || dayOfMonthIndicator > 31 || dayOfMonthIndicator == 0) {
+            throw new IllegalArgumentException("Day of month indicator must be between -28 and 31 inclusive excluding zero");
+        }
+        if (timeEndOfDay && time.equals(LocalTime.MIDNIGHT) == false) {
+            throw new IllegalArgumentException("Time must be midnight when end of day flag is true");
+        }
+        this.month = month;
+        this.dom = (byte) dayOfMonthIndicator;
+        this.dow = dayOfWeek;
+        this.time = time;
+        this.timeEndOfDay = timeEndOfDay;
+        this.timeDefinition = timeDefnition;
+        this.standardOffset = standardOffset;
+        this.offsetBefore = offsetBefore;
+        this.offsetAfter = offsetAfter;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this object equals another.
+     * <p>
+     * The entire state of the object is compared.
+     *
+     * @param otherRule  the other object to compare to, null returns false
+     * @return true if equal
+     */
+    @Override
+    public boolean equals(Object otherRule) {
+        if (otherRule == this) {
+            return true;
+        }
+        if (otherRule instanceof ZoneOffsetTransitionRule) {
+            ZoneOffsetTransitionRule other = (ZoneOffsetTransitionRule) otherRule;
+            return month == other.month && dom == other.dom && dow == other.dow &&
+                timeDefinition == other.timeDefinition &&
+                time.equals(other.time) &&
+                timeEndOfDay == other.timeEndOfDay &&
+                standardOffset.equals(other.standardOffset) &&
+                offsetBefore.equals(other.offsetBefore) &&
+                offsetAfter.equals(other.offsetAfter);
+        }
+        return false;
+    }
+
+    /**
+     * Returns a suitable hash code.
+     *
+     * @return the hash code
+     */
+    @Override
+    public int hashCode() {
+        int hash = ((time.toSecondOfDay() + (timeEndOfDay ? 1 : 0)) << 15) +
+                (month << 11) + ((dom + 32) << 5) +
+                ((dow == -1 ? 8 : dow) << 2) + (timeDefinition.ordinal());
+        return hash ^ standardOffset.hashCode() ^
+                offsetBefore.hashCode() ^ offsetAfter.hashCode();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/tools/src/build/tools/tzdb/ZoneRules.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package build.tools.tzdb;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.ObjectOutput;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Duplicated code of javax.time.zone.ZoneRules, ZoneOffsetTransitionRule
+ * and Ser to generate the serialization form output of ZoneRules for
+ * tzdb.jar.
+ *
+ * Implementation here is the copy/paste of ZoneRules, ZoneOffsetTransitionRule
+ * and Ser in javax.time.zone package. Make sure the code here is synchrionozed
+ * with the serialization implementation there.
+ *
+ * @since 1.8
+ */
+
+final class ZoneRules {
+
+    /**
+     * The transitions between standard offsets (epoch seconds), sorted.
+     */
+    private final long[] standardTransitions;
+    /**
+     * The standard offsets.
+     */
+    private final ZoneOffset[] standardOffsets;
+    /**
+     * The transitions between instants (epoch seconds), sorted.
+     */
+    private final long[] savingsInstantTransitions;
+
+    /**
+     * The wall offsets.
+     */
+    private final ZoneOffset[] wallOffsets;
+    /**
+     * The last rule.
+     */
+    private final ZoneOffsetTransitionRule[] lastRules;
+
+    /**
+     * Creates an instance.
+     *
+     * @param baseStandardOffset  the standard offset to use before legal rules were set, not null
+     * @param baseWallOffset  the wall offset to use before legal rules were set, not null
+     * @param standardOffsetTransitionList  the list of changes to the standard offset, not null
+     * @param transitionList  the list of transitions, not null
+     * @param lastRules  the recurring last rules, size 16 or less, not null
+     */
+    ZoneRules(ZoneOffset baseStandardOffset,
+              ZoneOffset baseWallOffset,
+              List<ZoneOffsetTransition> standardOffsetTransitionList,
+              List<ZoneOffsetTransition> transitionList,
+              List<ZoneOffsetTransitionRule> lastRules) {
+
+        this.standardTransitions = new long[standardOffsetTransitionList.size()];
+
+        this.standardOffsets = new ZoneOffset[standardOffsetTransitionList.size() + 1];
+        this.standardOffsets[0] = baseStandardOffset;
+        for (int i = 0; i < standardOffsetTransitionList.size(); i++) {
+            this.standardTransitions[i] = standardOffsetTransitionList.get(i).toEpochSecond();
+            this.standardOffsets[i + 1] = standardOffsetTransitionList.get(i).getOffsetAfter();
+        }
+
+        // convert savings transitions to locals
+        List<ZoneOffset> localTransitionOffsetList = new ArrayList<>();
+        localTransitionOffsetList.add(baseWallOffset);
+        for (ZoneOffsetTransition trans : transitionList) {
+            localTransitionOffsetList.add(trans.getOffsetAfter());
+        }
+
+        this.wallOffsets = localTransitionOffsetList.toArray(new ZoneOffset[localTransitionOffsetList.size()]);
+
+        // convert savings transitions to instants
+        this.savingsInstantTransitions = new long[transitionList.size()];
+        for (int i = 0; i < transitionList.size(); i++) {
+            this.savingsInstantTransitions[i] = transitionList.get(i).toEpochSecond();
+        }
+
+        // last rules
+        if (lastRules.size() > 16) {
+            throw new IllegalArgumentException("Too many transition rules");
+        }
+        this.lastRules = lastRules.toArray(new ZoneOffsetTransitionRule[lastRules.size()]);
+    }
+
+    /** Type for ZoneRules. */
+    static final byte ZRULES = 1;
+
+    /**
+     * Writes the state to the stream.
+     *
+     * @param out  the output stream, not null
+     * @throws IOException if an error occurs
+     */
+    void writeExternal(DataOutput out) throws IOException {
+        out.writeByte(ZRULES);
+        out.writeInt(standardTransitions.length);
+        for (long trans : standardTransitions) {
+            writeEpochSec(trans, out);
+        }
+        for (ZoneOffset offset : standardOffsets) {
+            writeOffset(offset, out);
+        }
+        out.writeInt(savingsInstantTransitions.length);
+        for (long trans : savingsInstantTransitions) {
+            writeEpochSec(trans, out);
+        }
+        for (ZoneOffset offset : wallOffsets) {
+            writeOffset(offset, out);
+        }
+        out.writeByte(lastRules.length);
+        for (ZoneOffsetTransitionRule rule : lastRules) {
+            writeRule(rule, out);
+        }
+    }
+
+    /**
+     * Writes the state the ZoneOffset to the stream.
+     *
+     * @param offset  the offset, not null
+     * @param out  the output stream, not null
+     * @throws IOException if an error occurs
+     */
+    static void writeOffset(ZoneOffset offset, DataOutput out) throws IOException {
+        final int offsetSecs = offset.getTotalSeconds();
+        int offsetByte = offsetSecs % 900 == 0 ? offsetSecs / 900 : 127;  // compress to -72 to +72
+        out.writeByte(offsetByte);
+        if (offsetByte == 127) {
+            out.writeInt(offsetSecs);
+        }
+    }
+
+    /**
+     * Writes the epoch seconds to the stream.
+     *
+     * @param epochSec  the epoch seconds, not null
+     * @param out  the output stream, not null
+     * @throws IOException if an error occurs
+     */
+    static void writeEpochSec(long epochSec, DataOutput out) throws IOException {
+        if (epochSec >= -4575744000L && epochSec < 10413792000L && epochSec % 900 == 0) {  // quarter hours between 1825 and 2300
+            int store = (int) ((epochSec + 4575744000L) / 900);
+            out.writeByte((store >>> 16) & 255);
+            out.writeByte((store >>> 8) & 255);
+            out.writeByte(store & 255);
+        } else {
+            out.writeByte(255);
+            out.writeLong(epochSec);
+        }
+    }
+
+    /**
+     * Writes the state of the transition rule to the stream.
+     *
+     * @param rule  the transition rule, not null
+     * @param out  the output stream, not null
+     * @throws IOException if an error occurs
+     */
+    static void writeRule(ZoneOffsetTransitionRule rule, DataOutput out) throws IOException {
+        int month = rule.month;
+        byte dom = rule.dom;
+        int dow = rule.dow;
+        LocalTime time = rule.time;
+        boolean timeEndOfDay = rule.timeEndOfDay;
+        TimeDefinition timeDefinition = rule.timeDefinition;
+        ZoneOffset standardOffset = rule.standardOffset;
+        ZoneOffset offsetBefore = rule.offsetBefore;
+        ZoneOffset offsetAfter = rule.offsetAfter;
+
+        int timeSecs = (timeEndOfDay ? 86400 : time.toSecondOfDay());
+        int stdOffset = standardOffset.getTotalSeconds();
+        int beforeDiff = offsetBefore.getTotalSeconds() - stdOffset;
+        int afterDiff = offsetAfter.getTotalSeconds() - stdOffset;
+        int timeByte = (timeSecs % 3600 == 0 ? (timeEndOfDay ? 24 : time.getHour()) : 31);
+        int stdOffsetByte = (stdOffset % 900 == 0 ? stdOffset / 900 + 128 : 255);
+        int beforeByte = (beforeDiff == 0 || beforeDiff == 1800 || beforeDiff == 3600 ? beforeDiff / 1800 : 3);
+        int afterByte = (afterDiff == 0 || afterDiff == 1800 || afterDiff == 3600 ? afterDiff / 1800 : 3);
+        int dowByte = (dow == -1 ? 0 : dow);
+        int b = (month << 28) +                     // 4 bytes
+                ((dom + 32) << 22) +                // 6 bytes
+                (dowByte << 19) +                   // 3 bytes
+                (timeByte << 14) +                  // 5 bytes
+                (timeDefinition.ordinal() << 12) +  // 2 bytes
+                (stdOffsetByte << 4) +              // 8 bytes
+                (beforeByte << 2) +                 // 2 bytes
+                afterByte;                          // 2 bytes
+        out.writeInt(b);
+        if (timeByte == 31) {
+            out.writeInt(timeSecs);
+        }
+        if (stdOffsetByte == 255) {
+            out.writeInt(stdOffset);
+        }
+        if (beforeByte == 3) {
+            out.writeInt(offsetBefore.getTotalSeconds());
+        }
+        if (afterByte == 3) {
+            out.writeInt(offsetAfter.getTotalSeconds());
+        }
+    }
+
+    /**
+     * Checks if this set of rules equals another.
+     * <p>
+     * Two rule sets are equal if they will always result in the same output
+     * for any given input instant or local date-time.
+     * Rules from two different groups may return false even if they are in fact the same.
+     * <p>
+     * This definition should result in implementations comparing their entire state.
+     *
+     * @param otherRules  the other rules, null returns false
+     * @return true if this rules is the same as that specified
+     */
+    @Override
+    public boolean equals(Object otherRules) {
+        if (this == otherRules) {
+           return true;
+        }
+        if (otherRules instanceof ZoneRules) {
+            ZoneRules other = (ZoneRules) otherRules;
+            return Arrays.equals(standardTransitions, other.standardTransitions) &&
+                    Arrays.equals(standardOffsets, other.standardOffsets) &&
+                    Arrays.equals(savingsInstantTransitions, other.savingsInstantTransitions) &&
+                    Arrays.equals(wallOffsets, other.wallOffsets) &&
+                    Arrays.equals(lastRules, other.lastRules);
+        }
+        return false;
+    }
+
+    /**
+     * Returns a suitable hash code given the definition of {@code #equals}.
+     *
+     * @return the hash code
+     */
+    @Override
+    public int hashCode() {
+        return Arrays.hashCode(standardTransitions) ^
+                Arrays.hashCode(standardOffsets) ^
+                Arrays.hashCode(savingsInstantTransitions) ^
+                Arrays.hashCode(wallOffsets) ^
+                Arrays.hashCode(lastRules);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/tools/src/build/tools/tzdb/ZoneRulesBuilder.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,743 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package build.tools.tzdb;
+
+import static build.tools.tzdb.Utils.*;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * A mutable builder used to create all the rules for a historic time-zone.
+ * <p>
+ * The rules of a time-zone describe how the offset changes over time.
+ * The rules are created by building windows on the time-line within which
+ * the different rules apply. The rules may be one of two kinds:
+ * <p><ul>
+ * <li>Fixed savings - A single fixed amount of savings from the standard offset will apply.</li>
+ * <li>Rules - A set of one or more rules describe how daylight savings changes during the window.</li>
+ * </ul><p>
+ *
+ * <h4>Implementation notes</h4>
+ * This class is a mutable builder used to create zone instances.
+ * It must only be used from a single thread.
+ * The created instances are immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public class ZoneRulesBuilder {
+
+    /**
+     * The list of windows.
+     */
+    private List<TZWindow> windowList = new ArrayList<>();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructs an instance of the builder that can be used to create zone rules.
+     * <p>
+     * The builder is used by adding one or more windows representing portions
+     * of the time-line. The standard offset from UTC/Greenwich will be constant
+     * within a window, although two adjacent windows can have the same standard offset.
+     * <p>
+     * Within each window, there can either be a
+     * {@link #setFixedSavingsToWindow fixed savings amount} or a
+     * {@link #addRuleToWindow list of rules}.
+     */
+    public ZoneRulesBuilder() {
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Adds a window to the builder that can be used to filter a set of rules.
+     * <p>
+     * This method defines and adds a window to the zone where the standard offset is specified.
+     * The window limits the effect of subsequent additions of transition rules
+     * or fixed savings. If neither rules or fixed savings are added to the window
+     * then the window will default to no savings.
+     * <p>
+     * Each window must be added sequentially, as the start instant of the window
+     * is derived from the until instant of the previous window.
+     *
+     * @param standardOffset  the standard offset, not null
+     * @param until  the date-time that the offset applies until, not null
+     * @param untilDefinition  the time type for the until date-time, not null
+     * @return this, for chaining
+     * @throws IllegalStateException if the window order is invalid
+     */
+    public ZoneRulesBuilder addWindow(
+            ZoneOffset standardOffset,
+            LocalDateTime until,
+            TimeDefinition untilDefinition) {
+        Objects.requireNonNull(standardOffset, "standardOffset");
+        Objects.requireNonNull(until, "until");
+        Objects.requireNonNull(untilDefinition, "untilDefinition");
+        TZWindow window = new TZWindow(standardOffset, until, untilDefinition);
+        if (windowList.size() > 0) {
+            TZWindow previous = windowList.get(windowList.size() - 1);
+            window.validateWindowOrder(previous);
+        }
+        windowList.add(window);
+        return this;
+    }
+
+    /**
+     * Adds a window that applies until the end of time to the builder that can be
+     * used to filter a set of rules.
+     * <p>
+     * This method defines and adds a window to the zone where the standard offset is specified.
+     * The window limits the effect of subsequent additions of transition rules
+     * or fixed savings. If neither rules or fixed savings are added to the window
+     * then the window will default to no savings.
+     * <p>
+     * This must be added after all other windows.
+     * No more windows can be added after this one.
+     *
+     * @param standardOffset  the standard offset, not null
+     * @return this, for chaining
+     * @throws IllegalStateException if a forever window has already been added
+     */
+    public ZoneRulesBuilder addWindowForever(ZoneOffset standardOffset) {
+        return addWindow(standardOffset, LocalDateTime.MAX, TimeDefinition.WALL);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Sets the previously added window to have fixed savings.
+     * <p>
+     * Setting a window to have fixed savings simply means that a single daylight
+     * savings amount applies throughout the window. The window could be small,
+     * such as a single summer, or large, such as a multi-year daylight savings.
+     * <p>
+     * A window can either have fixed savings or rules but not both.
+     *
+     * @param fixedSavingAmountSecs  the amount of saving to use for the whole window, not null
+     * @return this, for chaining
+     * @throws IllegalStateException if no window has yet been added
+     * @throws IllegalStateException if the window already has rules
+     */
+    public ZoneRulesBuilder setFixedSavingsToWindow(int fixedSavingAmountSecs) {
+        if (windowList.isEmpty()) {
+            throw new IllegalStateException("Must add a window before setting the fixed savings");
+        }
+        TZWindow window = windowList.get(windowList.size() - 1);
+        window.setFixedSavings(fixedSavingAmountSecs);
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Adds a single transition rule to the current window.
+     * <p>
+     * This adds a rule such that the offset, expressed as a daylight savings amount,
+     * changes at the specified date-time.
+     *
+     * @param transitionDateTime  the date-time that the transition occurs as defined by timeDefintion, not null
+     * @param timeDefinition  the definition of how to convert local to actual time, not null
+     * @param savingAmountSecs  the amount of saving from the standard offset after the transition in seconds
+     * @return this, for chaining
+     * @throws IllegalStateException if no window has yet been added
+     * @throws IllegalStateException if the window already has fixed savings
+     * @throws IllegalStateException if the window has reached the maximum capacity of 2000 rules
+     */
+    public ZoneRulesBuilder addRuleToWindow(
+            LocalDateTime transitionDateTime,
+            TimeDefinition timeDefinition,
+            int savingAmountSecs) {
+        Objects.requireNonNull(transitionDateTime, "transitionDateTime");
+        return addRuleToWindow(
+                transitionDateTime.getYear(), transitionDateTime.getYear(),
+                transitionDateTime.getMonth(), transitionDateTime.getDayOfMonth(),
+                -1, transitionDateTime.getTime(), false, timeDefinition, savingAmountSecs);
+    }
+
+    /**
+     * Adds a single transition rule to the current window.
+     * <p>
+     * This adds a rule such that the offset, expressed as a daylight savings amount,
+     * changes at the specified date-time.
+     *
+     * @param year  the year of the transition, from MIN_YEAR to MAX_YEAR
+     * @param month  the month of the transition, not null
+     * @param dayOfMonthIndicator  the day-of-month of the transition, adjusted by dayOfWeek,
+     *   from 1 to 31 adjusted later, or -1 to -28 adjusted earlier from the last day of the month
+     * @param time  the time that the transition occurs as defined by timeDefintion, not null
+     * @param timeEndOfDay  whether midnight is at the end of day
+     * @param timeDefinition  the definition of how to convert local to actual time, not null
+     * @param savingAmountSecs  the amount of saving from the standard offset after the transition in seconds
+     * @return this, for chaining
+     * @throws DateTimeException if a date-time field is out of range
+     * @throws IllegalStateException if no window has yet been added
+     * @throws IllegalStateException if the window already has fixed savings
+     * @throws IllegalStateException if the window has reached the maximum capacity of 2000 rules
+     */
+    public ZoneRulesBuilder addRuleToWindow(
+            int year,
+            int month,
+            int dayOfMonthIndicator,
+            LocalTime time,
+            boolean timeEndOfDay,
+            TimeDefinition timeDefinition,
+            int savingAmountSecs) {
+        return addRuleToWindow(year, year, month, dayOfMonthIndicator, -1, time, timeEndOfDay, timeDefinition, savingAmountSecs);
+    }
+
+    /**
+     * Adds a multi-year transition rule to the current window.
+     * <p>
+     * This adds a rule such that the offset, expressed as a daylight savings amount,
+     * changes at the specified date-time for each year in the range.
+     *
+     * @param startYear  the start year of the rule, from MIN_YEAR to MAX_YEAR
+     * @param endYear  the end year of the rule, from MIN_YEAR to MAX_YEAR
+     * @param month  the month of the transition, from 1 to 12
+     * @param dayOfMonthIndicator  the day-of-month of the transition, adjusted by dayOfWeek,
+     *   from 1 to 31 adjusted later, or -1 to -28 adjusted earlier from the last day of the month
+     * @param dayOfWeek  the day-of-week to adjust to, -1 if day-of-month should not be adjusted
+     * @param time  the time that the transition occurs as defined by timeDefintion, not null
+     * @param timeEndOfDay  whether midnight is at the end of day
+     * @param timeDefinition  the definition of how to convert local to actual time, not null
+     * @param savingAmountSecs  the amount of saving from the standard offset after the transition in seconds
+     * @return this, for chaining
+     * @throws DateTimeException if a date-time field is out of range
+     * @throws IllegalArgumentException if the day of month indicator is invalid
+     * @throws IllegalArgumentException if the end of day midnight flag does not match the time
+     * @throws IllegalStateException if no window has yet been added
+     * @throws IllegalStateException if the window already has fixed savings
+     * @throws IllegalStateException if the window has reached the maximum capacity of 2000 rules
+     */
+    public ZoneRulesBuilder addRuleToWindow(
+            int startYear,
+            int endYear,
+            int month,
+            int dayOfMonthIndicator,
+            int dayOfWeek,
+            LocalTime time,
+            boolean timeEndOfDay,
+            TimeDefinition timeDefinition,
+            int savingAmountSecs) {
+        Objects.requireNonNull(time, "time");
+        Objects.requireNonNull(timeDefinition, "timeDefinition");
+        if (dayOfMonthIndicator < -28 || dayOfMonthIndicator > 31 || dayOfMonthIndicator == 0) {
+            throw new IllegalArgumentException("Day of month indicator must be between -28 and 31 inclusive excluding zero");
+        }
+        if (timeEndOfDay && time.equals(LocalTime.MIDNIGHT) == false) {
+            throw new IllegalArgumentException("Time must be midnight when end of day flag is true");
+        }
+        if (windowList.isEmpty()) {
+            throw new IllegalStateException("Must add a window before adding a rule");
+        }
+        TZWindow window = windowList.get(windowList.size() - 1);
+        window.addRule(startYear, endYear, month, dayOfMonthIndicator, dayOfWeek, time, timeEndOfDay, timeDefinition, savingAmountSecs);
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Completes the build converting the builder to a set of time-zone rules.
+     * <p>
+     * Calling this method alters the state of the builder.
+     * Further rules should not be added to this builder once this method is called.
+     *
+     * @param zoneId  the time-zone ID, not null
+     * @return the zone rules, not null
+     * @throws IllegalStateException if no windows have been added
+     * @throws IllegalStateException if there is only one rule defined as being forever for any given window
+     */
+    public ZoneRules toRules(String zoneId) {
+        Objects.requireNonNull(zoneId, "zoneId");
+        if (windowList.isEmpty()) {
+            throw new IllegalStateException("No windows have been added to the builder");
+        }
+
+        final List<ZoneOffsetTransition> standardTransitionList = new ArrayList<>(4);
+        final List<ZoneOffsetTransition> transitionList = new ArrayList<>(256);
+        final List<ZoneOffsetTransitionRule> lastTransitionRuleList = new ArrayList<>(2);
+
+        // initialize the standard offset calculation
+        final TZWindow firstWindow = windowList.get(0);
+        ZoneOffset loopStandardOffset = firstWindow.standardOffset;
+        int loopSavings = 0;
+        if (firstWindow.fixedSavingAmountSecs != null) {
+            loopSavings = firstWindow.fixedSavingAmountSecs;
+        }
+        final ZoneOffset firstWallOffset = ZoneOffset.ofTotalSeconds(loopStandardOffset.getTotalSeconds() + loopSavings);
+        LocalDateTime loopWindowStart = LocalDateTime.of(YEAR_MIN_VALUE, 1, 1, 0, 0);
+        ZoneOffset loopWindowOffset = firstWallOffset;
+
+        // build the windows and rules to interesting data
+        for (TZWindow window : windowList) {
+            // tidy the state
+            window.tidy(loopWindowStart.getYear());
+
+            // calculate effective savings at the start of the window
+            Integer effectiveSavings = window.fixedSavingAmountSecs;
+            if (effectiveSavings == null) {
+                // apply rules from this window together with the standard offset and
+                // savings from the last window to find the savings amount applicable
+                // at start of this window
+                effectiveSavings = 0;
+                for (TZRule rule : window.ruleList) {
+                    if (rule.toEpochSecond(loopStandardOffset, loopSavings) > loopWindowStart.toEpochSecond(loopWindowOffset)) {
+                        // previous savings amount found, which could be the savings amount at
+                        // the instant that the window starts (hence isAfter)
+                        break;
+                    }
+                    effectiveSavings = rule.savingAmountSecs;
+                }
+            }
+
+            // check if standard offset changed, and update it
+            if (loopStandardOffset.equals(window.standardOffset) == false) {
+                standardTransitionList.add(
+                    new ZoneOffsetTransition(
+                        LocalDateTime.ofEpochSecond(loopWindowStart.toEpochSecond(loopWindowOffset), 0, loopStandardOffset),
+                        loopStandardOffset, window.standardOffset));
+                loopStandardOffset = window.standardOffset;
+            }
+
+            // check if the start of the window represents a transition
+            ZoneOffset effectiveWallOffset = ZoneOffset.ofTotalSeconds(loopStandardOffset.getTotalSeconds() + effectiveSavings);
+            if (loopWindowOffset.equals(effectiveWallOffset) == false) {
+                transitionList.add(new ZoneOffsetTransition(loopWindowStart, loopWindowOffset, effectiveWallOffset));
+            }
+            loopSavings = effectiveSavings;
+
+            // apply rules within the window
+            for (TZRule rule : window.ruleList) {
+                if (rule.isTransition(loopSavings)) {
+                    ZoneOffsetTransition trans = rule.toTransition(loopStandardOffset, loopSavings);
+                    if (trans.toEpochSecond() < loopWindowStart.toEpochSecond(loopWindowOffset) == false &&
+                        trans.toEpochSecond() < window.createDateTimeEpochSecond(loopSavings)) {
+                        transitionList.add(trans);
+                        loopSavings = rule.savingAmountSecs;
+                    }
+                }
+            }
+
+            // calculate last rules
+            for (TZRule lastRule : window.lastRuleList) {
+                lastTransitionRuleList.add(lastRule.toTransitionRule(loopStandardOffset, loopSavings));
+                loopSavings = lastRule.savingAmountSecs;
+            }
+
+            // finally we can calculate the true end of the window, passing it to the next window
+            loopWindowOffset = window.createWallOffset(loopSavings);
+            loopWindowStart = LocalDateTime.ofEpochSecond(
+                    window.createDateTimeEpochSecond(loopSavings), 0, loopWindowOffset);
+        }
+
+        return new ZoneRules(
+                firstWindow.standardOffset, firstWallOffset, standardTransitionList,
+                transitionList, lastTransitionRuleList);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * A definition of a window in the time-line.
+     * The window will have one standard offset and will either have a
+     * fixed DST savings or a set of rules.
+     */
+    class TZWindow {
+        /** The standard offset during the window, not null. */
+        private final ZoneOffset standardOffset;
+        /** The end local time, not null. */
+        private final LocalDateTime windowEnd;
+        /** The type of the end time, not null. */
+        private final TimeDefinition timeDefinition;
+
+        /** The fixed amount of the saving to be applied during this window. */
+        private Integer fixedSavingAmountSecs;
+        /** The rules for the current window. */
+        private List<TZRule> ruleList = new ArrayList<>();
+        /** The latest year that the last year starts at. */
+        private int maxLastRuleStartYear = YEAR_MIN_VALUE;
+        /** The last rules. */
+        private List<TZRule> lastRuleList = new ArrayList<>();
+
+        /**
+         * Constructor.
+         *
+         * @param standardOffset  the standard offset applicable during the window, not null
+         * @param windowEnd  the end of the window, relative to the time definition, null if forever
+         * @param timeDefinition  the time definition for calculating the true end, not null
+         */
+        TZWindow(
+                ZoneOffset standardOffset,
+                LocalDateTime windowEnd,
+                TimeDefinition timeDefinition) {
+            super();
+            this.windowEnd = windowEnd;
+            this.timeDefinition = timeDefinition;
+            this.standardOffset = standardOffset;
+        }
+
+        /**
+         * Sets the fixed savings amount for the window.
+         *
+         * @param fixedSavingAmount  the amount of daylight saving to apply throughout the window, may be null
+         * @throws IllegalStateException if the window already has rules
+         */
+        void setFixedSavings(int fixedSavingAmount) {
+            if (ruleList.size() > 0 || lastRuleList.size() > 0) {
+                throw new IllegalStateException("Window has DST rules, so cannot have fixed savings");
+            }
+            this.fixedSavingAmountSecs = fixedSavingAmount;
+        }
+
+        /**
+         * Adds a rule to the current window.
+         *
+         * @param startYear  the start year of the rule, from MIN_YEAR to MAX_YEAR
+         * @param endYear  the end year of the rule, from MIN_YEAR to MAX_YEAR
+         * @param month  the month of the transition, not null
+         * @param dayOfMonthIndicator  the day-of-month of the transition, adjusted by dayOfWeek,
+         *   from 1 to 31 adjusted later, or -1 to -28 adjusted earlier from the last day of the month
+         * @param dayOfWeek  the day-of-week to adjust to, null if day-of-month should not be adjusted
+         * @param time  the time that the transition occurs as defined by timeDefintion, not null
+         * @param timeEndOfDay  whether midnight is at the end of day
+         * @param timeDefinition  the definition of how to convert local to actual time, not null
+         * @param savingAmountSecs  the amount of saving from the standard offset in seconds
+         * @throws IllegalStateException if the window already has fixed savings
+         * @throws IllegalStateException if the window has reached the maximum capacity of 2000 rules
+         */
+        void addRule(
+                int startYear,
+                int endYear,
+                int month,
+                int dayOfMonthIndicator,
+                int dayOfWeek,
+                LocalTime time,
+                boolean timeEndOfDay,
+                TimeDefinition timeDefinition,
+                int savingAmountSecs) {
+
+            if (fixedSavingAmountSecs != null) {
+                throw new IllegalStateException("Window has a fixed DST saving, so cannot have DST rules");
+            }
+            if (ruleList.size() >= 2000) {
+                throw new IllegalStateException("Window has reached the maximum number of allowed rules");
+            }
+            boolean lastRule = false;
+            if (endYear == YEAR_MAX_VALUE) {
+                lastRule = true;
+                endYear = startYear;
+            }
+            int year = startYear;
+            while (year <= endYear) {
+                TZRule rule = new TZRule(year, month, dayOfMonthIndicator, dayOfWeek, time, timeEndOfDay, timeDefinition, savingAmountSecs);
+                if (lastRule) {
+                    lastRuleList.add(rule);
+                    maxLastRuleStartYear = Math.max(startYear, maxLastRuleStartYear);
+                } else {
+                    ruleList.add(rule);
+                }
+                year++;
+            }
+        }
+
+        /**
+         * Validates that this window is after the previous one.
+         *
+         * @param previous  the previous window, not null
+         * @throws IllegalStateException if the window order is invalid
+         */
+        void validateWindowOrder(TZWindow previous) {
+            if (windowEnd.compareTo(previous.windowEnd) < 0) {
+                throw new IllegalStateException("Windows must be added in date-time order: " +
+                        windowEnd + " < " + previous.windowEnd);
+            }
+        }
+
+        /**
+         * Adds rules to make the last rules all start from the same year.
+         * Also add one more year to avoid weird case where penultimate year has odd offset.
+         *
+         * @param windowStartYear  the window start year
+         * @throws IllegalStateException if there is only one rule defined as being forever
+         */
+        void tidy(int windowStartYear) {
+            if (lastRuleList.size() == 1) {
+                throw new IllegalStateException("Cannot have only one rule defined as being forever");
+            }
+
+            // handle last rules
+            if (windowEnd.equals(LocalDateTime.MAX)) {
+                // setup at least one real rule, which closes off other windows nicely
+                maxLastRuleStartYear = Math.max(maxLastRuleStartYear, windowStartYear) + 1;
+                for (TZRule lastRule : lastRuleList) {
+                    addRule(lastRule.year, maxLastRuleStartYear, lastRule.month, lastRule.dayOfMonthIndicator,
+                        lastRule.dayOfWeek, lastRule.time, lastRule.timeEndOfDay, lastRule.timeDefinition, lastRule.savingAmountSecs);
+                    lastRule.year = maxLastRuleStartYear + 1;
+                }
+                if (maxLastRuleStartYear == YEAR_MAX_VALUE) {
+                    lastRuleList.clear();
+                } else {
+                    maxLastRuleStartYear++;
+                }
+            } else {
+                // convert all within the endYear limit
+                int endYear = windowEnd.getYear();
+                for (TZRule lastRule : lastRuleList) {
+                    addRule(lastRule.year, endYear + 1, lastRule.month, lastRule.dayOfMonthIndicator,
+                        lastRule.dayOfWeek, lastRule.time, lastRule.timeEndOfDay, lastRule.timeDefinition, lastRule.savingAmountSecs);
+                }
+                lastRuleList.clear();
+                maxLastRuleStartYear = YEAR_MAX_VALUE;
+            }
+
+            // ensure lists are sorted
+            Collections.sort(ruleList);
+            Collections.sort(lastRuleList);
+
+            // default fixed savings to zero
+            if (ruleList.size() == 0 && fixedSavingAmountSecs == null) {
+                fixedSavingAmountSecs = 0;
+            }
+        }
+
+        /**
+         * Checks if the window is empty.
+         *
+         * @return true if the window is only a standard offset
+         */
+        boolean isSingleWindowStandardOffset() {
+            return windowEnd.equals(LocalDateTime.MAX) && timeDefinition == TimeDefinition.WALL &&
+                    fixedSavingAmountSecs == null && lastRuleList.isEmpty() && ruleList.isEmpty();
+        }
+
+        /**
+         * Creates the wall offset for the local date-time at the end of the window.
+         *
+         * @param savingsSecs  the amount of savings in use in seconds
+         * @return the created date-time epoch second in the wall offset, not null
+         */
+        ZoneOffset createWallOffset(int savingsSecs) {
+            return ZoneOffset.ofTotalSeconds(standardOffset.getTotalSeconds() + savingsSecs);
+        }
+
+        /**
+         * Creates the offset date-time for the local date-time at the end of the window.
+         *
+         * @param savingsSecs  the amount of savings in use in seconds
+         * @return the created date-time epoch second in the wall offset, not null
+         */
+        long createDateTimeEpochSecond(int savingsSecs) {
+            ZoneOffset wallOffset = createWallOffset(savingsSecs);
+            LocalDateTime ldt = timeDefinition.createDateTime(windowEnd, standardOffset, wallOffset);
+            return ldt.toEpochSecond(wallOffset);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * A definition of the way a local time can be converted to an offset time.
+     */
+    class TZRule implements Comparable<TZRule> {
+        private int year;
+        private int month;
+        private int dayOfMonthIndicator;
+        private int dayOfWeek;
+        private LocalTime time;
+        private boolean timeEndOfDay; // Whether the local time is end of day.
+        private TimeDefinition timeDefinition; // The type of the time.
+        private int savingAmountSecs; // The amount of the saving to be applied after this point.
+
+        /**
+         * Constructor.
+         *
+         * @param year  the year
+         * @param month  the month, value from 1 to 12
+         * @param dayOfMonthIndicator  the day-of-month of the transition, adjusted by dayOfWeek,
+         *   from 1 to 31 adjusted later, or -1 to -28 adjusted earlier from the last day of the month
+         * @param dayOfWeek  the day-of-week, -1 if day-of-month is exact
+         * @param time  the time, not null
+         * @param timeEndOfDay  whether midnight is at the end of day
+         * @param timeDefinition  the time definition, not null
+         * @param savingAfterSecs  the savings amount in seconds
+         */
+        TZRule(int year, int month, int dayOfMonthIndicator,
+                int dayOfWeek, LocalTime time, boolean timeEndOfDay,
+                TimeDefinition timeDefinition, int savingAfterSecs) {
+            this.year = year;
+            this.month = month;
+            this.dayOfMonthIndicator = dayOfMonthIndicator;
+            this.dayOfWeek = dayOfWeek;
+            this.time = time;
+            this.timeEndOfDay = timeEndOfDay;
+            this.timeDefinition = timeDefinition;
+            this.savingAmountSecs = savingAfterSecs;
+        }
+
+        /**
+         * Converts this to a transition.
+         *
+         * @param standardOffset  the active standard offset, not null
+         * @param savingsBeforeSecs  the active savings in seconds
+         * @return the transition, not null
+         */
+        ZoneOffsetTransition toTransition(ZoneOffset standardOffset, int savingsBeforeSecs) {
+            // copy of code in ZoneOffsetTransitionRule to avoid infinite loop
+            LocalDate date = toLocalDate();
+            LocalDateTime ldt = LocalDateTime.of(date, time);
+            ZoneOffset wallOffset = ZoneOffset.ofTotalSeconds(standardOffset.getTotalSeconds() + savingsBeforeSecs);
+            LocalDateTime dt = timeDefinition.createDateTime(ldt, standardOffset, wallOffset);
+            ZoneOffset offsetAfter = ZoneOffset.ofTotalSeconds(standardOffset.getTotalSeconds() + savingAmountSecs);
+            return new ZoneOffsetTransition(dt, wallOffset, offsetAfter);
+        }
+
+        /**
+         * Returns the apoch second of this rules with the specified
+         * active standard offset and active savings
+         *
+         * @param standardOffset  the active standard offset, not null
+         * @param savingsBeforeSecs  the active savings in seconds
+         * @return the transition epoch second
+         */
+        long toEpochSecond(ZoneOffset standardOffset, int savingsBeforeSecs) {
+            LocalDateTime ldt = LocalDateTime.of(toLocalDate(), time);
+            ZoneOffset wallOffset = ZoneOffset.ofTotalSeconds(standardOffset.getTotalSeconds() + savingsBeforeSecs);
+            return timeDefinition.createDateTime(ldt, standardOffset, wallOffset)
+                                 .toEpochSecond(wallOffset);
+        }
+
+        /**
+         * Tests if this a real transition with the active savings in seconds
+         *
+         * @param savingsBeforeSecs  the active savings in seconds
+         * @return true, if savings in seconds changes
+         */
+        boolean isTransition(int savingsBeforeSecs) {
+            return savingAmountSecs != savingsBeforeSecs;
+        }
+
+        /**
+         * Converts this to a transition rule.
+         *
+         * @param standardOffset  the active standard offset, not null
+         * @param savingsBeforeSecs  the active savings before the transition in seconds
+         * @return the transition, not null
+         */
+        ZoneOffsetTransitionRule toTransitionRule(ZoneOffset standardOffset, int savingsBeforeSecs) {
+            // optimize stored format
+            if (dayOfMonthIndicator < 0) {
+                if (month != 2) {    // not Month.FEBRUARY
+                    dayOfMonthIndicator = maxLengthOfMonth(month) - 6;
+                }
+            }
+            if (timeEndOfDay && dayOfMonthIndicator > 0 &&
+                (dayOfMonthIndicator == 28 && month == 2) == false) {
+                LocalDate date = LocalDate.of(2004, month, dayOfMonthIndicator).plusDays(1);  // leap-year
+                month = date.getMonth();
+                dayOfMonthIndicator = date.getDayOfMonth();
+                if (dayOfWeek != -1) {
+                    dayOfWeek = plusDayOfWeek(dayOfWeek, 1);
+                }
+                timeEndOfDay = false;
+            }
+            // build rule
+            return new ZoneOffsetTransitionRule(
+                    month, dayOfMonthIndicator, dayOfWeek, time, timeEndOfDay, timeDefinition,
+                    standardOffset,
+                    ZoneOffset.ofTotalSeconds(standardOffset.getTotalSeconds() + savingsBeforeSecs),
+                    ZoneOffset.ofTotalSeconds(standardOffset.getTotalSeconds() + savingAmountSecs));
+        }
+
+        public int compareTo(TZRule other) {
+            int cmp = year - other.year;
+            cmp = (cmp == 0 ? month - other.month : cmp);
+            if (cmp == 0) {
+                // convert to date to handle dow/domIndicator/timeEndOfDay
+                LocalDate thisDate = toLocalDate();
+                LocalDate otherDate = other.toLocalDate();
+                cmp = thisDate.compareTo(otherDate);
+            }
+            cmp = (cmp == 0 ? time.compareTo(other.time) : cmp);
+            return cmp;
+        }
+
+        private LocalDate toLocalDate() {
+            LocalDate date;
+            if (dayOfMonthIndicator < 0) {
+                int monthLen = lengthOfMonth(month, isLeapYear(year));
+                date = LocalDate.of(year, month, monthLen + 1 + dayOfMonthIndicator);
+                if (dayOfWeek != -1) {
+                    date = previousOrSame(date, dayOfWeek);
+                }
+            } else {
+                date = LocalDate.of(year, month, dayOfMonthIndicator);
+                if (dayOfWeek != -1) {
+                    date = nextOrSame(date, dayOfWeek);
+                }
+            }
+            if (timeEndOfDay) {
+                date = date.plusDays(1);
+            }
+            return date;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/tools/tzdb/Makefile	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,43 @@
+#
+# Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+#
+# Makefile for building the tzdb compiler tool
+#
+
+BUILDDIR = ../..
+PACKAGE = build.tools.tzdb
+PRODUCT = tzdb
+PROGRAM = tzdb
+include $(BUILDDIR)/common/Defs.gmk
+
+BUILDTOOL_SOURCE_ROOT = $(BUILDDIR)/tools/src
+BUILDTOOL_MAIN        = $(PKGDIR)/TzdbZoneRulesCompiler.java
+
+#
+# Build tool jar rules.
+#
+include $(BUILDDIR)/common/BuildToolJar.gmk
+
--- a/jdk/makefiles/CreateJars.gmk	Tue Jan 22 18:30:49 2013 -0800
+++ b/jdk/makefiles/CreateJars.gmk	Tue Jan 22 20:59:21 2013 -0800
@@ -72,6 +72,13 @@
 
 ##########################################################################################
 
+$(IMAGES_OUTPUTDIR)/lib/tzdb.jar: $(JDK_OUTPUTDIR)/lib/tzdb.jar
+	$(install-file)
+
+JARS += $(IMAGES_OUTPUTDIR)/lib/tzdb.jar 
+
+##########################################################################################
+
 LOCALEDATA_INCLUDE_LOCALES := ar be bg ca cs da de el es et fi fr ga hi hr hu in is it \
                               iw ja ko lt lv mk ms mt nl no pl pt ro ru sk sl sq sr sv \
                               th tr uk vi zh
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/makefiles/GendataTZDB.gmk	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,44 @@
+#
+# Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+GENDATA_TZDB :=
+
+#
+# Time zone data file creation
+#
+TZDATA_DIR := $(JDK_TOPDIR)/make/sun/javazic/tzdata
+TZDATA_VER := $(subst tzdata,,$(shell $(GREP) '^tzdata' $(TZDATA_DIR)/VERSION))
+TZDATA_TZFILE := africa antarctica asia australasia europe northamerica southamerica backward etcetera
+TZDATA_TZFILES := $(addprefix $(TZDATA_DIR)/,$(TZDATA_TZFILE))
+
+GENDATA_TZDB_DST := $(JDK_OUTPUTDIR)/lib
+GENDATA_TZDB_JAR := tzdb.jar
+
+$(GENDATA_TZDB_DST)/$(GENDATA_TZDB_JAR) : $(TZDATA_TZFILES)
+	$(RM) $(GENDATA_TZDB_DST)/$(GENDATA_TZDB_JAR)
+	echo building tzdb from version $(TZDATA_VER)
+	$(TOOL_TZDB) -verbose -version $(TZDATA_VER) -srcdir $(TZDATA_DIR) -dstdir $(GENDATA_TZDB_DST) $(TZDATA_TZFILE)
+
+GENDATA_TZDB += $(GENDATA_TZDB_DST)/$(GENDATA_TZDB_JAR)
--- a/jdk/makefiles/GenerateData.gmk	Tue Jan 22 18:30:49 2013 -0800
+++ b/jdk/makefiles/GenerateData.gmk	Tue Jan 22 20:59:21 2013 -0800
@@ -47,6 +47,9 @@
 include GendataTimeZone.gmk
 GENDATA += $(GENDATA_TIMEZONE)
 
+include GendataTZDB.gmk
+GENDATA += $(GENDATA_TZDB)
+
 include GendataHtml32dtd.gmk
 GENDATA += $(GENDATA_HTML32DTD)
 
--- a/jdk/makefiles/Tools.gmk	Tue Jan 22 18:30:49 2013 -0800
+++ b/jdk/makefiles/Tools.gmk	Tue Jan 22 20:59:21 2013 -0800
@@ -106,6 +106,10 @@
 TOOL_JAVAZIC=$(JAVA) -cp $(JDK_OUTPUTDIR)/btclasses \
 	build.tools.javazic.Main
 
+TOOL_TZDB=$(JAVA) -cp $(JDK_OUTPUTDIR)/btclasses \
+	build.tools.tzdb.TzdbZoneRulesCompiler
+
+
 # TODO: There are references to the jdwpgen.jar in jdk/make/netbeans/jdwpgen/build.xml 
 # and nbproject/project.properties in the same dir. Needs to be looked at.
 TOOL_JDWPGEN=$(JAVA) -cp $(JDK_OUTPUTDIR)/btclasses build.tools.jdwpgen.Main
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/Clock.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,638 @@
+/*
+ * 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;
+
+import static java.time.LocalTime.NANOS_PER_MINUTE;
+import static java.time.LocalTime.NANOS_PER_SECOND;
+
+import java.io.Serializable;
+import java.util.Objects;
+import java.util.TimeZone;
+
+/**
+ * A clock providing access to the current instant, date and time using a time-zone.
+ * <p>
+ * Instances of this class are used to find the current instant, which can be
+ * interpreted using the stored time-zone to find the current date and time.
+ * As such, a clock can be used instead of {@link System#currentTimeMillis()}
+ * and {@link TimeZone#getDefault()}.
+ * <p>
+ * Use of a {@code Clock} is optional. All key date-time classes also have a
+ * {@code now()} factory method that uses the system clock in the default time zone.
+ * The primary purpose of this abstraction is to allow alternate clocks to be
+ * plugged in as and when required. Applications use an object to obtain the
+ * current time rather than a static method. This can simplify testing.
+ * <p>
+ * Best practice for applications is to pass a {@code Clock} into any method
+ * that requires the current instant. A dependency injection framework is one
+ * way to achieve this:
+ * <pre>
+ *  public class MyBean {
+ *    private Clock clock;  // dependency inject
+ *    ...
+ *    public void process(LocalDate eventDate) {
+ *      if (eventDate.isBefore(LocalDate.now(clock)) {
+ *        ...
+ *      }
+ *    }
+ *  }
+ * </pre>
+ * This approach allows an alternate clock, such as {@link #fixed(Instant, ZoneId) fixed}
+ * or {@link #offset(Clock, Duration) offset} to be used during testing.
+ * <p>
+ * The {@code system} factory methods provide clocks based on the best available
+ * system clock This may use {@link System#currentTimeMillis()}, or a higher
+ * resolution clock if one is available.
+ *
+ * <h3>Specification for implementors</h3>
+ * This abstract class must be implemented with care to ensure other operate correctly.
+ * All implementations that can be instantiated must be final, immutable and thread-safe.
+ * <p>
+ * The principal methods are defined to allow the throwing of an exception.
+ * In normal use, no exceptions will be thrown, however one possible implementation would be to
+ * obtain the time from a central time server across the network. Obviously, in this case the
+ * lookup could fail, and so the method is permitted to throw an exception.
+ * <p>
+ * The returned instants from {@code Clock} work on a time-scale that ignores leap seconds.
+ * If the implementation wraps a source that provides leap second information, then a mechanism
+ * should be used to "smooth" the leap second, such as UTC-SLS.
+ * <p>
+ * Implementations should implement {@code Serializable} wherever possible and must
+ * document whether or not they do support serialization.
+ *
+ * @since 1.8
+ */
+public abstract class Clock {
+
+    /**
+     * Obtains a clock that returns the current instant using the best available
+     * system clock, converting to date and time using the UTC time-zone.
+     * <p>
+     * This clock, rather than {@link #systemDefaultZone()}, should be used when
+     * you need the current instant without the date or time.
+     * <p>
+     * This clock is based on the best available system clock.
+     * This may use {@link System#currentTimeMillis()}, or a higher resolution
+     * clock if one is available.
+     * <p>
+     * Conversion from instant to date or time uses the {@linkplain ZoneOffset#UTC UTC time-zone}.
+     * <p>
+     * The returned implementation is immutable, thread-safe and {@code Serializable}.
+     * It is equivalent to {@code system(ZoneOffset.UTC)}.
+     *
+     * @return a clock that uses the best available system clock in the UTC zone, not null
+     */
+    public static Clock systemUTC() {
+        return new SystemClock(ZoneOffset.UTC);
+    }
+
+    /**
+     * Obtains a clock that returns the current instant using the best available
+     * system clock, converting to date and time using the default time-zone.
+     * <p>
+     * This clock is based on the best available system clock.
+     * This may use {@link System#currentTimeMillis()}, or a higher resolution
+     * clock if one is available.
+     * <p>
+     * Using this method hard codes a dependency to the default time-zone into your application.
+     * It is recommended to avoid this and use a specific time-zone whenever possible.
+     * The {@link #systemUTC() UTC clock} should be used when you need the current instant
+     * without the date or time.
+     * <p>
+     * The returned implementation is immutable, thread-safe and {@code Serializable}.
+     * It is equivalent to {@code system(ZoneId.systemDefault())}.
+     *
+     * @return a clock that uses the best available system clock in the default zone, not null
+     * @see ZoneId#systemDefault()
+     */
+    public static Clock systemDefaultZone() {
+        return new SystemClock(ZoneId.systemDefault());
+    }
+
+    /**
+     * Obtains a clock that returns the current instant using best available
+     * system clock.
+     * <p>
+     * This clock is based on the best available system clock.
+     * This may use {@link System#currentTimeMillis()}, or a higher resolution
+     * clock if one is available.
+     * <p>
+     * Conversion from instant to date or time uses the specified time-zone.
+     * <p>
+     * The returned implementation is immutable, thread-safe and {@code Serializable}.
+     *
+     * @param zone  the time-zone to use to convert the instant to date-time, not null
+     * @return a clock that uses the best available system clock in the specified zone, not null
+     */
+    public static Clock system(ZoneId zone) {
+        Objects.requireNonNull(zone, "zone");
+        return new SystemClock(zone);
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Obtains a clock that returns the current instant ticking in whole seconds
+     * using best available system clock.
+     * <p>
+     * This clock will always have the nano-of-second field set to zero.
+     * This ensures that the visible time ticks in whole seconds.
+     * The underlying clock is the best available system clock, equivalent to
+     * using {@link #system(ZoneId)}.
+     * <p>
+     * Implementations may use a caching strategy for performance reasons.
+     * As such, it is possible that the start of the second observed via this
+     * clock will be later than that observed directly via the underlying clock.
+     * <p>
+     * The returned implementation is immutable, thread-safe and {@code Serializable}.
+     * It is equivalent to {@code tick(system(zone), Duration.ofSeconds(1))}.
+     *
+     * @param zone  the time-zone to use to convert the instant to date-time, not null
+     * @return a clock that ticks in whole seconds using the specified zone, not null
+     */
+    public static Clock tickSeconds(ZoneId zone) {
+        return new TickClock(system(zone), NANOS_PER_SECOND);
+    }
+
+    /**
+     * Obtains a clock that returns the current instant ticking in whole minutes
+     * using best available system clock.
+     * <p>
+     * This clock will always have the nano-of-second and second-of-minute fields set to zero.
+     * This ensures that the visible time ticks in whole minutes.
+     * The underlying clock is the best available system clock, equivalent to
+     * using {@link #system(ZoneId)}.
+     * <p>
+     * Implementations may use a caching strategy for performance reasons.
+     * As such, it is possible that the start of the minute observed via this
+     * clock will be later than that observed directly via the underlying clock.
+     * <p>
+     * The returned implementation is immutable, thread-safe and {@code Serializable}.
+     * It is equivalent to {@code tick(system(zone), Duration.ofMinutes(1))}.
+     *
+     * @param zone  the time-zone to use to convert the instant to date-time, not null
+     * @return a clock that ticks in whole minutes using the specified zone, not null
+     */
+    public static Clock tickMinutes(ZoneId zone) {
+        return new TickClock(system(zone), NANOS_PER_MINUTE);
+    }
+
+    /**
+     * Obtains a clock that returns instants from the specified clock truncated
+     * to the nearest occurrence of the specified duration.
+     * <p>
+     * This clock will only tick as per the specified duration. Thus, if the duration
+     * is half a second, the clock will return instants truncated to the half second.
+     * <p>
+     * The tick duration must be positive. If it has a part smaller than a whole
+     * millisecond, then the whole duration must divide into one second without
+     * leaving a remainder. All normal tick durations will match these criteria,
+     * including any multiple of hours, minutes, seconds and milliseconds, and
+     * sensible nanosecond durations, such as 20ns, 250,000ns and 500,000ns.
+     * <p>
+     * A duration of zero or one nanosecond would have no truncation effect.
+     * Passing one of these will return the underlying clock.
+     * <p>
+     * Implementations may use a caching strategy for performance reasons.
+     * As such, it is possible that the start of the requested duration observed
+     * via this clock will be later than that observed directly via the underlying clock.
+     * <p>
+     * The returned implementation is immutable, thread-safe and {@code Serializable}
+     * providing that the base clock is.
+     *
+     * @param baseClock  the base clock to base the ticking clock on, not null
+     * @param tickDuration  the duration of each visible tick, not negative, not null
+     * @return a clock that ticks in whole units of the duration, not null
+     * @throws IllegalArgumentException if the duration is negative, or has a
+     *  part smaller than a whole millisecond such that the whole duration is not
+     *  divisible into one second
+     * @throws ArithmeticException if the duration is too large to be represented as nanos
+     */
+    public static Clock tick(Clock baseClock, Duration tickDuration) {
+        Objects.requireNonNull(baseClock, "baseClock");
+        Objects.requireNonNull(tickDuration, "tickDuration");
+        if (tickDuration.isNegative()) {
+            throw new IllegalArgumentException("Tick duration must not be negative");
+        }
+        long tickNanos = tickDuration.toNanos();
+        if (tickNanos % 1000_000 == 0) {
+            // ok, no fraction of millisecond
+        } else if (1000_000_000 % tickNanos == 0) {
+            // ok, divides into one second without remainder
+        } else {
+            throw new IllegalArgumentException("Invalid tick duration");
+        }
+        if (tickNanos <= 1) {
+            return baseClock;
+        }
+        return new TickClock(baseClock, tickNanos);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a clock that always returns the same instant.
+     * <p>
+     * This clock simply returns the specified instant.
+     * As such, it is not a clock in the conventional sense.
+     * The main use case for this is in testing, where the fixed clock ensures
+     * tests are not dependent on the current clock.
+     * <p>
+     * The returned implementation is immutable, thread-safe and {@code Serializable}.
+     *
+     * @param fixedInstant  the instant to use as the clock, not null
+     * @param zone  the time-zone to use to convert the instant to date-time, not null
+     * @return a clock that always returns the same instant, not null
+     */
+    public static Clock fixed(Instant fixedInstant, ZoneId zone) {
+        Objects.requireNonNull(fixedInstant, "fixedInstant");
+        Objects.requireNonNull(zone, "zone");
+        return new FixedClock(fixedInstant, zone);
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Obtains a clock that returns instants from the specified clock with the
+     * specified duration added
+     * <p>
+     * This clock wraps another clock, returning instants that are later by the
+     * specified duration. If the duration is negative, the instants will be
+     * earlier than the current date and time.
+     * The main use case for this is to simulate running in the future or in the past.
+     * <p>
+     * A duration of zero would have no offsetting effect.
+     * Passing zero will return the underlying clock.
+     * <p>
+     * The returned implementation is immutable, thread-safe and {@code Serializable}
+     * providing that the base clock is.
+     *
+     * @param baseClock  the base clock to add the duration to, not null
+     * @param offsetDuration  the duration to add, not null
+     * @return a clock based on the base clock with the duration added, not null
+     */
+    public static Clock offset(Clock baseClock, Duration offsetDuration) {
+        Objects.requireNonNull(baseClock, "baseClock");
+        Objects.requireNonNull(offsetDuration, "offsetDuration");
+        if (offsetDuration.equals(Duration.ZERO)) {
+            return baseClock;
+        }
+        return new OffsetClock(baseClock, offsetDuration);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructor accessible by subclasses.
+     */
+    protected Clock() {
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the time-zone being used to create dates and times.
+     * <p>
+     * A clock will typically obtain the current instant and then convert that
+     * to a date or time using a time-zone. This method returns the time-zone used.
+     *
+     * @return the time-zone being used to interpret instants, not null
+     */
+    public abstract ZoneId getZone();
+
+    /**
+     * Returns a copy of this clock with a different time-zone.
+     * <p>
+     * A clock will typically obtain the current instant and then convert that
+     * to a date or time using a time-zone. This method returns a clock with
+     * similar properties but using a different time-zone.
+     *
+     * @param zone  the time-zone to change to, not null
+     * @return a clock based on this clock with the specified time-zone, not null
+     */
+    public abstract Clock withZone(ZoneId zone);
+
+    //-------------------------------------------------------------------------
+    /**
+     * Gets the current millisecond instant of the clock.
+     * <p>
+     * This returns the millisecond-based instant, measured from 1970-01-01T00:00 UTC.
+     * This is equivalent to the definition of {@link System#currentTimeMillis()}.
+     * <p>
+     * Most applications should avoid this method and use {@link Instant} to represent
+     * 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.
+     *
+     * @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();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the current instant of the clock.
+     * <p>
+     * This returns an instant representing the current instant as defined by the clock.
+     * <p>
+     * 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());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this clock is equal to another clock.
+     * <p>
+     * Clocks must compare equal based on their state and behavior.
+     *
+     * @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);
+
+    /**
+     * A hash code for this clock.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public abstract int hashCode();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a string describing this clock.
+     * <p>
+     * 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();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Implementation of a clock that always returns the latest time from
+     * {@link System#currentTimeMillis()}.
+     */
+    static final class SystemClock extends Clock implements Serializable {
+        private static final long serialVersionUID = 6740630888130243051L;
+        private final ZoneId zone;
+
+        SystemClock(ZoneId zone) {
+            this.zone = zone;
+        }
+        @Override
+        public ZoneId getZone() {
+            return zone;
+        }
+        @Override
+        public Clock withZone(ZoneId zone) {
+            if (zone.equals(this.zone)) {  // intentional NPE
+                return this;
+            }
+            return new SystemClock(zone);
+        }
+        @Override
+        public long millis() {
+            return System.currentTimeMillis();
+        }
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof SystemClock) {
+                return zone.equals(((SystemClock) obj).zone);
+            }
+            return false;
+        }
+        @Override
+        public int hashCode() {
+            return zone.hashCode() + 1;
+        }
+        @Override
+        public String toString() {
+            return "SystemClock[" + zone + "]";
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Implementation of a clock that always returns the same instant.
+     * This is typically used for testing.
+     */
+    static final class FixedClock extends Clock implements Serializable {
+       private static final long serialVersionUID = 7430389292664866958L;
+        private final Instant instant;
+        private final ZoneId zone;
+
+        FixedClock(Instant fixedInstant, ZoneId zone) {
+            this.instant = fixedInstant;
+            this.zone = zone;
+        }
+        @Override
+        public ZoneId getZone() {
+            return zone;
+        }
+        @Override
+        public Clock withZone(ZoneId zone) {
+            if (zone.equals(this.zone)) {  // intentional NPE
+                return this;
+            }
+            return new FixedClock(instant, zone);
+        }
+        @Override
+        public long millis() {
+            return instant.toEpochMilli();
+        }
+        @Override
+        public Instant instant() {
+            return instant;
+        }
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof FixedClock) {
+                FixedClock other = (FixedClock) obj;
+                return instant.equals(other.instant) && zone.equals(other.zone);
+            }
+            return false;
+        }
+        @Override
+        public int hashCode() {
+            return instant.hashCode() ^ zone.hashCode();
+        }
+        @Override
+        public String toString() {
+            return "FixedClock[" + instant + "," + zone + "]";
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Implementation of a clock that adds an offset to an underlying clock.
+     */
+    static final class OffsetClock extends Clock implements Serializable {
+       private static final long serialVersionUID = 2007484719125426256L;
+        private final Clock baseClock;
+        private final Duration offset;
+
+        OffsetClock(Clock baseClock, Duration offset) {
+            this.baseClock = baseClock;
+            this.offset = offset;
+        }
+        @Override
+        public ZoneId getZone() {
+            return baseClock.getZone();
+        }
+        @Override
+        public Clock withZone(ZoneId zone) {
+            if (zone.equals(baseClock.getZone())) {  // intentional NPE
+                return this;
+            }
+            return new OffsetClock(baseClock.withZone(zone), offset);
+        }
+        @Override
+        public long millis() {
+            return Math.addExact(baseClock.millis(), offset.toMillis());
+        }
+        @Override
+        public Instant instant() {
+            return baseClock.instant().plus(offset);
+        }
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof OffsetClock) {
+                OffsetClock other = (OffsetClock) obj;
+                return baseClock.equals(other.baseClock) && offset.equals(other.offset);
+            }
+            return false;
+        }
+        @Override
+        public int hashCode() {
+            return baseClock.hashCode() ^ offset.hashCode();
+        }
+        @Override
+        public String toString() {
+            return "OffsetClock[" + baseClock + "," + offset + "]";
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Implementation of a clock that adds an offset to an underlying clock.
+     */
+    static final class TickClock extends Clock implements Serializable {
+        private static final long serialVersionUID = 6504659149906368850L;
+        private final Clock baseClock;
+        private final long tickNanos;
+
+        TickClock(Clock baseClock, long tickNanos) {
+            this.baseClock = baseClock;
+            this.tickNanos = tickNanos;
+        }
+        @Override
+        public ZoneId getZone() {
+            return baseClock.getZone();
+        }
+        @Override
+        public Clock withZone(ZoneId zone) {
+            if (zone.equals(baseClock.getZone())) {  // intentional NPE
+                return this;
+            }
+            return new TickClock(baseClock.withZone(zone), tickNanos);
+        }
+        @Override
+        public long millis() {
+            long millis = baseClock.millis();
+            return millis - Math.floorMod(millis, tickNanos / 1000_000L);
+        }
+        @Override
+        public Instant instant() {
+            if ((tickNanos % 1000_000) == 0) {
+                long millis = baseClock.millis();
+                return Instant.ofEpochMilli(millis - Math.floorMod(millis, tickNanos / 1000_000L));
+            }
+            Instant instant = baseClock.instant();
+            long nanos = instant.getNano();
+            long adjust = Math.floorMod(nanos, tickNanos);
+            return instant.minusNanos(adjust);
+        }
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof TickClock) {
+                TickClock other = (TickClock) obj;
+                return baseClock.equals(other.baseClock) && tickNanos == other.tickNanos;
+            }
+            return false;
+        }
+        @Override
+        public int hashCode() {
+            return baseClock.hashCode() ^ ((int) (tickNanos ^ (tickNanos >>> 32)));
+        }
+        @Override
+        public String toString() {
+            return "TickClock[" + baseClock + "," + Duration.ofNanos(tickNanos) + "]";
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/DateTimeException.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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;
+
+/**
+ * Exception used to indicate a problem while calculating a date-time.
+ * <p>
+ * This exception is used to indicate problems with creating, querying
+ * and manipulating date-time objects.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is intended for use in a single thread.
+ *
+ * @since 1.8
+ */
+public class DateTimeException extends RuntimeException {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -1632418723876261839L;
+
+    /**
+     * Constructs a new date-time exception with the specified message.
+     *
+     * @param message  the message to use for this exception, may be null
+     */
+    public DateTimeException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new date-time exception with the specified message and cause.
+     *
+     * @param message  the message to use for this exception, may be null
+     * @param cause  the cause of the exception, may be null
+     */
+    public DateTimeException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/DayOfWeek.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,446 @@
+/*
+ * 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;
+
+import static java.time.temporal.ChronoField.DAY_OF_WEEK;
+import static java.time.temporal.ChronoUnit.DAYS;
+
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.TextStyle;
+import java.time.temporal.ChronoField;
+import java.time.temporal.Queries;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.ValueRange;
+import java.time.temporal.WeekFields;
+import java.util.Locale;
+
+/**
+ * A day-of-week, such as 'Tuesday'.
+ * <p>
+ * {@code DayOfWeek} is an enum representing the 7 days of the week -
+ * Monday, Tuesday, Wednesday, Thursday, Friday, Saturday and Sunday.
+ * <p>
+ * In addition to the textual enum name, each day-of-week has an {@code int} value.
+ * The {@code int} value follows the ISO-8601 standard, from 1 (Monday) to 7 (Sunday).
+ * It is recommended that applications use the enum rather than the {@code int} value
+ * to ensure code clarity.
+ * <p>
+ * This enum provides access to the localized textual form of the day-of-week.
+ * Some locales also assign different numeric values to the days, declaring
+ * Sunday to have the value 1, however this class provides no support for this.
+ * See {@link WeekFields} for localized week-numbering.
+ * <p>
+ * <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code DayOfWeek}.
+ * Use {@code getValue()} instead.</b>
+ * <p>
+ * This enum represents a common concept that is found in many calendar systems.
+ * As such, this enum may be used by any calendar system that has the day-of-week
+ * concept defined exactly equivalent to the ISO calendar system.
+ *
+ * <h3>Specification for implementors</h3>
+ * This is an immutable and thread-safe enum.
+ *
+ * @since 1.8
+ */
+public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
+
+    /**
+     * The singleton instance for the day-of-week of Monday.
+     * This has the numeric value of {@code 1}.
+     */
+    MONDAY,
+    /**
+     * The singleton instance for the day-of-week of Tuesday.
+     * This has the numeric value of {@code 2}.
+     */
+    TUESDAY,
+    /**
+     * The singleton instance for the day-of-week of Wednesday.
+     * This has the numeric value of {@code 3}.
+     */
+    WEDNESDAY,
+    /**
+     * The singleton instance for the day-of-week of Thursday.
+     * This has the numeric value of {@code 4}.
+     */
+    THURSDAY,
+    /**
+     * The singleton instance for the day-of-week of Friday.
+     * This has the numeric value of {@code 5}.
+     */
+    FRIDAY,
+    /**
+     * The singleton instance for the day-of-week of Saturday.
+     * This has the numeric value of {@code 6}.
+     */
+    SATURDAY,
+    /**
+     * The singleton instance for the day-of-week of Sunday.
+     * This has the numeric value of {@code 7}.
+     */
+    SUNDAY;
+    /**
+     * Private cache of all the constants.
+     */
+    private static final DayOfWeek[] ENUMS = DayOfWeek.values();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code DayOfWeek} from an {@code int} value.
+     * <p>
+     * {@code DayOfWeek} is an enum representing the 7 days of the week.
+     * This factory allows the enum to be obtained from the {@code int} value.
+     * The {@code int} value follows the ISO-8601 standard, from 1 (Monday) to 7 (Sunday).
+     *
+     * @param dayOfWeek  the day-of-week to represent, from 1 (Monday) to 7 (Sunday)
+     * @return the day-of-week singleton, not null
+     * @throws DateTimeException if the day-of-week is invalid
+     */
+    public static DayOfWeek of(int dayOfWeek) {
+        if (dayOfWeek < 1 || dayOfWeek > 7) {
+            throw new DateTimeException("Invalid value for DayOfWeek: " + dayOfWeek);
+        }
+        return ENUMS[dayOfWeek - 1];
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code DayOfWeek} from a temporal object.
+     * <p>
+     * A {@code TemporalAccessor} represents some form of date and time information.
+     * This factory converts the arbitrary temporal object to an instance of {@code DayOfWeek}.
+     * <p>
+     * The conversion extracts the {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} field.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used as a query via method reference, {@code DayOfWeek::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the day-of-week, not null
+     * @throws DateTimeException if unable to convert to a {@code DayOfWeek}
+     */
+    public static DayOfWeek from(TemporalAccessor temporal) {
+        if (temporal instanceof DayOfWeek) {
+            return (DayOfWeek) temporal;
+        }
+        return of(temporal.get(DAY_OF_WEEK));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the day-of-week {@code int} value.
+     * <p>
+     * The values are numbered following the ISO-8601 standard, from 1 (Monday) to 7 (Sunday).
+     * See {@link WeekFields#dayOfWeek} for localized week-numbering.
+     *
+     * @return the day-of-week, from 1 (Monday) to 7 (Sunday)
+     */
+    public int getValue() {
+        return ordinal() + 1;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the textual representation, such as 'Mon' or 'Friday'.
+     * <p>
+     * This returns the textual name used to identify the day-of-week.
+     * The parameters control the length of the returned text and the locale.
+     * <p>
+     * If no textual mapping is found then the {@link #getValue() numeric value} is returned.
+     *
+     * @param style  the length of the text required, not null
+     * @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);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if this day-of-week 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.
+     * <p>
+     * If the field is {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} then
+     * this method returns true.
+     * All other {@code ChronoField} instances will return false.
+     * <p>
+     * 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 day-of-week, false if not
+     */
+    @Override
+    public boolean isSupported(TemporalField field) {
+        if (field instanceof ChronoField) {
+            return field == DAY_OF_WEEK;
+        }
+        return field != null && field.doIsSupported(this);
+    }
+
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * The range object expresses the minimum and maximum valid values for a field.
+     * This day-of-week 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.
+     * <p>
+     * If the field is {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} then the
+     * range of the day-of-week, from 1 to 7, will be returned.
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * 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 == DAY_OF_WEEK) {
+            return field.range();
+        }
+        return TemporalAccessor.super.range(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this day-of-week as an {@code int}.
+     * <p>
+     * This queries this day-of-week 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.
+     * <p>
+     * If the field is {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} then the
+     * value of the day-of-week, from 1 to 7, will be returned.
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * 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, 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
+    public int get(TemporalField field) {
+        if (field == DAY_OF_WEEK) {
+            return getValue();
+        }
+        return TemporalAccessor.super.get(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this day-of-week as a {@code long}.
+     * <p>
+     * This queries this day-of-week 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.
+     * <p>
+     * If the field is {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} then the
+     * value of the day-of-week, from 1 to 7, will be returned.
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * 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 == DAY_OF_WEEK) {
+            return getValue();
+        } else if (field instanceof ChronoField) {
+            throw new DateTimeException("Unsupported field: " + field.getName());
+        }
+        return field.doGet(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns the day-of-week that is the specified number of days after this one.
+     * <p>
+     * The calculation rolls around the end of the week from Sunday to Monday.
+     * The specified period may be negative.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param days  the days to add, positive or negative
+     * @return the resulting day-of-week, not null
+     */
+    public DayOfWeek plus(long days) {
+        int amount = (int) (days % 7);
+        return ENUMS[(ordinal() + (amount + 7)) % 7];
+    }
+
+    /**
+     * Returns the day-of-week that is the specified number of days before this one.
+     * <p>
+     * The calculation rolls around the start of the year from Monday to Sunday.
+     * The specified period may be negative.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param days  the days to subtract, positive or negative
+     * @return the resulting day-of-week, not null
+     */
+    public DayOfWeek minus(long days) {
+        return plus(-(days % 7));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this day-of-week using the specified query.
+     * <p>
+     * This queries this day-of-week 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.
+     * <p>
+     * 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 <R> 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> R query(TemporalQuery<R> query) {
+        if (query == Queries.precision()) {
+            return (R) DAYS;
+        }
+        return TemporalAccessor.super.query(query);
+    }
+
+    /**
+     * Adjusts the specified temporal object to have this day-of-week.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with the day-of-week changed to be the same as this.
+     * <p>
+     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+     * passing {@link ChronoField#DAY_OF_WEEK} as the field.
+     * Note that this adjusts forwards or backwards within a Monday to Sunday week.
+     * See {@link WeekFields#dayOfWeek} for localized week start days.
+     * See {@link java.time.temporal.Adjusters Adjusters} for other adjusters
+     * with more control, such as {@code next(MONDAY)}.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisDayOfWeek.adjustInto(temporal);
+     *   temporal = temporal.with(thisDayOfWeek);
+     * </pre>
+     * <p>
+     * For example, given a date that is a Wednesday, the following are output:
+     * <pre>
+     *   dateOnWed.with(MONDAY);     // two days earlier
+     *   dateOnWed.with(TUESDAY);    // one day earlier
+     *   dateOnWed.with(WEDNESDAY);  // same date
+     *   dateOnWed.with(THURSDAY);   // one day later
+     *   dateOnWed.with(FRIDAY);     // two days later
+     *   dateOnWed.with(SATURDAY);   // three days later
+     *   dateOnWed.with(SUNDAY);     // four days later
+     * </pre>
+     * <p>
+     * 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(DAY_OF_WEEK, getValue());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/Duration.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,1045 @@
+/*
+ * 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;
+
+import static java.time.LocalTime.SECONDS_PER_DAY;
+import static java.time.temporal.ChronoField.INSTANT_SECONDS;
+import static java.time.temporal.ChronoField.NANO_OF_SECOND;
+import static java.time.temporal.ChronoUnit.DAYS;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.RoundingMode;
+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.TemporalUnit;
+import java.util.Objects;
+
+/**
+ * A duration between two instants on the time-line.
+ * <p>
+ * 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.
+ * <p>
+ * A physical duration could be of infinite length.
+ * For practicality, the duration is stored with constraints similar to {@link Instant}.
+ * The duration uses nanosecond resolution with a maximum value of the seconds that can
+ * be held in a {@code long}. This is greater than the current estimated age of the universe.
+ * <p>
+ * 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.
+ * <p>
+ * The duration is measured in "seconds", but these are not necessarily identical to
+ * the scientific "SI second" definition based on atomic clocks.
+ * This difference only impacts durations measured near a leap-second and should not affect
+ * most applications.
+ * See {@link Instant} for a discussion as to the meaning of the second and time-scales.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class Duration
+        implements TemporalAdder, TemporalSubtractor, Comparable<Duration>, Serializable {
+
+    /**
+     * Constant for a duration of zero.
+     */
+    public static final Duration ZERO = new Duration(0, 0);
+    /**
+     * 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 number of seconds in the duration.
+     */
+    private final long seconds;
+    /**
+     * The number of nanoseconds in the duration, expressed as a fraction of the
+     * number of seconds. This is always positive, and never exceeds 999,999,999.
+     */
+    private final int nanos;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Duration} from a number of seconds.
+     * <p>
+     * The nanosecond in second field is set to zero.
+     *
+     * @param seconds  the number of seconds, positive or negative
+     * @return a {@code Duration}, not null
+     */
+    public static Duration ofSeconds(long seconds) {
+        return create(seconds, 0);
+    }
+
+    /**
+     * Obtains an instance of {@code Duration} from a number of seconds
+     * and an adjustment in nanoseconds.
+     * <p>
+     * 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
+     * to ensure that the stored nanosecond is in the range 0 to 999,999,999.
+     * For example, the following will result in the exactly the same duration:
+     * <pre>
+     *  Duration.ofSeconds(3, 1);
+     *  Duration.ofSeconds(4, -999_999_999);
+     *  Duration.ofSeconds(2, 1000_000_001);
+     * </pre>
+     *
+     * @param seconds  the number of seconds, positive or negative
+     * @param nanoAdjustment  the nanosecond adjustment to the number of seconds, positive or negative
+     * @return a {@code Duration}, not null
+     * @throws ArithmeticException if the adjustment causes the seconds to exceed the capacity of {@code 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);
+        return create(secs, nos);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Duration} from a number of milliseconds.
+     * <p>
+     * The seconds and nanoseconds are extracted from the specified milliseconds.
+     *
+     * @param millis  the number of milliseconds, positive or negative
+     * @return a {@code Duration}, not null
+     */
+    public static Duration ofMillis(long millis) {
+        long secs = millis / 1000;
+        int mos = (int) (millis % 1000);
+        if (mos < 0) {
+            mos += 1000;
+            secs--;
+        }
+        return create(secs, mos * 1000_000);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Duration} from a number of nanoseconds.
+     * <p>
+     * The seconds and nanoseconds are extracted from the specified nanoseconds.
+     *
+     * @param nanos  the number of nanoseconds, positive or negative
+     * @return a {@code Duration}, not null
+     */
+    public static Duration ofNanos(long nanos) {
+        long secs = nanos / NANOS_PER_SECOND;
+        int nos = (int) (nanos % NANOS_PER_SECOND);
+        if (nos < 0) {
+            nos += NANOS_PER_SECOND;
+            secs--;
+        }
+        return create(secs, nos);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Duration} from a number of standard length minutes.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * The parameters represent the two parts of a phrase like '6 Hours'. For example:
+     * <pre>
+     *  Duration.of(3, SECONDS);
+     *  Duration.of(465, HOURS);
+     * </pre>
+     * Only a subset of units are accepted by this method.
+     * The unit must either have an {@linkplain TemporalUnit#isDurationEstimated() exact duration} or
+     * be {@link ChronoUnit#DAYS} which is treated as 24 hours. Other units throw an exception.
+     *
+     * @param amount  the amount of the duration, measured in terms of the unit, positive or negative
+     * @param unit  the unit that the duration is measured in, must have an exact duration, not null
+     * @return a {@code Duration}, not null
+     * @throws DateTimeException if the period unit has an estimated duration
+     * @throws ArithmeticException if a numeric overflow occurs
+     */
+    public static Duration of(long amount, TemporalUnit unit) {
+        return ZERO.plus(amount, unit);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Duration} representing the duration between two instants.
+     * <p>
+     * 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.
+     *
+     * @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
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Duration} by parsing a text string.
+     * <p>
+     * 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.
+     * The decimal point may be either a dot or a comma.
+     *
+     * @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}
+     */
+    public static Duration parse(final 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);
+                }
+                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);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Duration} using seconds and nanoseconds.
+     *
+     * @param seconds  the length of the duration in seconds, positive or negative
+     * @param nanoAdjustment  the nanosecond adjustment within the second, from 0 to 999,999,999
+     */
+    private static Duration create(long seconds, int nanoAdjustment) {
+        if ((seconds | nanoAdjustment) == 0) {
+            return ZERO;
+        }
+        return new Duration(seconds, nanoAdjustment);
+    }
+
+    /**
+     * Constructs an instance of {@code Duration} using seconds and nanoseconds.
+     *
+     * @param seconds  the length of the duration in seconds, positive or negative
+     * @param nanos  the nanoseconds within the second, from 0 to 999,999,999
+     */
+    private Duration(long seconds, int nanos) {
+        super();
+        this.seconds = seconds;
+        this.nanos = nanos;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this duration is zero length.
+     * <p>
+     * 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 zero.
+     *
+     * @return true if this duration has a total length equal to zero
+     */
+    public boolean isZero() {
+        return (seconds | nanos) == 0;
+    }
+
+    /**
+     * Checks if this duration is positive, excluding zero.
+     * <p>
+     * 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.
+     * <p>
+     * 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 less than zero.
+     *
+     * @return true if this duration has a total length less than zero
+     */
+    public boolean isNegative() {
+        return seconds < 0;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the number of seconds in this duration.
+     * <p>
+     * The length of the duration is stored using two fields - seconds and nanoseconds.
+     * The nanoseconds part is a value from 0 to 999,999,999 that is an adjustment to
+     * the length in seconds.
+     * The total duration is defined by calling this method and {@link #getNano()}.
+     * <p>
+     * A {@code Duration} represents a directed distance between two points on the time-line.
+     * A negative duration is expressed by the negative sign of the seconds part.
+     * A duration of -1 nanosecond is stored as -1 seconds plus 999,999,999 nanoseconds.
+     *
+     * @return the whole seconds part of the length of the duration, positive or negative
+     */
+    public long getSeconds() {
+        return seconds;
+    }
+
+    /**
+     * Gets the number of nanoseconds within the second in this duration.
+     * <p>
+     * The length of the duration is stored using two fields - seconds and nanoseconds.
+     * The nanoseconds part is a value from 0 to 999,999,999 that is an adjustment to
+     * the length in seconds.
+     * The total duration is defined by calling this method and {@link #getSeconds()}.
+     * <p>
+     * A {@code Duration} represents a directed distance between two points on the time-line.
+     * A negative duration is expressed by the negative sign of the seconds part.
+     * A duration of -1 nanosecond is stored as -1 seconds plus 999,999,999 nanoseconds.
+     *
+     * @return the nanoseconds within the second part of the length of the duration, from 0 to 999,999,999
+     */
+    public int getNano() {
+        return nanos;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this duration with the specified duration added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param duration  the duration to add, positive or negative, not null
+     * @return a {@code Duration} based on this duration with the specified duration added, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration plus(Duration duration) {
+        return plus(duration.getSeconds(), duration.getNano());
+     }
+
+    /**
+     * Returns a copy of this duration with the specified duration added.
+     * <p>
+     * The duration amount is measured in terms of the specified unit.
+     * Only a subset of units are accepted by this method.
+     * The unit must either have an {@linkplain TemporalUnit#isDurationEstimated() exact duration} or
+     * be {@link ChronoUnit#DAYS} which is treated as 24 hours. Other units throw an exception.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToAdd  the amount of the period, measured in terms of the unit, positive or negative
+     * @param unit  the unit that the period is measured in, must have an exact duration, not null
+     * @return a {@code Duration} based on this duration with the specified duration added, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration plus(long amountToAdd, TemporalUnit unit) {
+        Objects.requireNonNull(unit, "unit");
+        if (unit == DAYS) {
+            return plus(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY), 0);
+        }
+        if (unit.isDurationEstimated()) {
+            throw new DateTimeException("Unit must not have an estimated duration");
+        }
+        if (amountToAdd == 0) {
+            return this;
+        }
+        if (unit instanceof ChronoUnit) {
+            switch ((ChronoUnit) unit) {
+                case NANOS: return plusNanos(amountToAdd);
+                case MICROS: return plusSeconds((amountToAdd / (1000_000L * 1000)) * 1000).plusNanos((amountToAdd % (1000_000L * 1000)) * 1000);
+                case MILLIS: return plusMillis(amountToAdd);
+                case SECONDS: return plusSeconds(amountToAdd);
+            }
+            return plusSeconds(Math.multiplyExact(unit.getDuration().seconds, amountToAdd));
+        }
+        Duration duration = unit.getDuration().multipliedBy(amountToAdd);
+        return plusSeconds(duration.getSeconds()).plusNanos(duration.getNano());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this duration with the specified duration in seconds added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param secondsToAdd  the seconds to add, positive or negative
+     * @return a {@code Duration} based on this duration with the specified seconds added, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration plusSeconds(long secondsToAdd) {
+        return plus(secondsToAdd, 0);
+    }
+
+    /**
+     * Returns a copy of this duration with the specified duration in milliseconds added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param millisToAdd  the milliseconds to add, positive or negative
+     * @return a {@code Duration} based on this duration with the specified milliseconds added, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration plusMillis(long millisToAdd) {
+        return plus(millisToAdd / 1000, (millisToAdd % 1000) * 1000_000);
+    }
+
+    /**
+     * Returns a copy of this duration with the specified duration in nanoseconds added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanosToAdd  the nanoseconds to add, positive or negative
+     * @return a {@code Duration} based on this duration with the specified nanoseconds added, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration plusNanos(long nanosToAdd) {
+        return plus(0, nanosToAdd);
+    }
+
+    /**
+     * Returns a copy of this duration with the specified duration added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param secondsToAdd  the seconds to add, positive or negative
+     * @param nanosToAdd  the nanos to add, positive or negative
+     * @return a {@code Duration} based on this duration with the specified seconds added, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    private Duration plus(long secondsToAdd, long nanosToAdd) {
+        if ((secondsToAdd | nanosToAdd) == 0) {
+            return this;
+        }
+        long epochSec = Math.addExact(seconds, secondsToAdd);
+        epochSec = Math.addExact(epochSec, nanosToAdd / NANOS_PER_SECOND);
+        nanosToAdd = nanosToAdd % NANOS_PER_SECOND;
+        long nanoAdjustment = nanos + nanosToAdd;  // safe int+NANOS_PER_SECOND
+        return ofSeconds(epochSec, nanoAdjustment);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this duration with the specified duration subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param duration  the duration to subtract, positive or negative, not null
+     * @return a {@code Duration} based on this duration with the specified duration subtracted, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration minus(Duration duration) {
+        long secsToSubtract = duration.getSeconds();
+        int nanosToSubtract = duration.getNano();
+        if (secsToSubtract == Long.MIN_VALUE) {
+            return plus(Long.MAX_VALUE, -nanosToSubtract).plus(1, 0);
+        }
+        return plus(-secsToSubtract, -nanosToSubtract);
+     }
+
+    /**
+     * Returns a copy of this duration with the specified duration subtracted.
+     * <p>
+     * The duration amount is measured in terms of the specified unit.
+     * Only a subset of units are accepted by this method.
+     * The unit must either have an {@linkplain TemporalUnit#isDurationEstimated() exact duration} or
+     * be {@link ChronoUnit#DAYS} which is treated as 24 hours. Other units throw an exception.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToSubtract  the amount of the period, measured in terms of the unit, positive or negative
+     * @param unit  the unit that the period is measured in, must have an exact duration, not null
+     * @return a {@code Duration} based on this duration with the specified duration subtracted, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration 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 duration with the specified duration in seconds subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param secondsToSubtract  the seconds to subtract, positive or negative
+     * @return a {@code Duration} based on this duration with the specified seconds subtracted, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration minusSeconds(long secondsToSubtract) {
+        return (secondsToSubtract == Long.MIN_VALUE ? plusSeconds(Long.MAX_VALUE).plusSeconds(1) : plusSeconds(-secondsToSubtract));
+    }
+
+    /**
+     * Returns a copy of this duration with the specified duration in milliseconds subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param millisToSubtract  the milliseconds to subtract, positive or negative
+     * @return a {@code Duration} based on this duration with the specified milliseconds subtracted, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration minusMillis(long millisToSubtract) {
+        return (millisToSubtract == Long.MIN_VALUE ? plusMillis(Long.MAX_VALUE).plusMillis(1) : plusMillis(-millisToSubtract));
+    }
+
+    /**
+     * Returns a copy of this duration with the specified duration in nanoseconds subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanosToSubtract  the nanoseconds to subtract, positive or negative
+     * @return a {@code Duration} based on this duration with the specified nanoseconds subtracted, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration minusNanos(long nanosToSubtract) {
+        return (nanosToSubtract == Long.MIN_VALUE ? plusNanos(Long.MAX_VALUE).plusNanos(1) : plusNanos(-nanosToSubtract));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this duration multiplied by the scalar.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param multiplicand  the value to multiply the duration by, positive or negative
+     * @return a {@code Duration} based on this duration multiplied by the specified scalar, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration multipliedBy(long multiplicand) {
+        if (multiplicand == 0) {
+            return ZERO;
+        }
+        if (multiplicand == 1) {
+            return this;
+        }
+        return create(toSeconds().multiply(BigDecimal.valueOf(multiplicand)));
+     }
+
+    /**
+     * Returns a copy of this duration divided by the specified value.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @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
+     */
+    public Duration dividedBy(long divisor) {
+        if (divisor == 0) {
+            throw new ArithmeticException("Cannot divide by zero");
+        }
+        if (divisor == 1) {
+            return this;
+        }
+        return create(toSeconds().divide(BigDecimal.valueOf(divisor), RoundingMode.DOWN));
+     }
+
+    /**
+     * Converts this duration to the total length in seconds and
+     * fractional nanoseconds expressed as a {@code BigDecimal}.
+     *
+     * @return the total length of the duration in seconds, with a scale of 9, not null
+     */
+    private BigDecimal toSeconds() {
+        return BigDecimal.valueOf(seconds).add(BigDecimal.valueOf(nanos, 9));
+    }
+
+    /**
+     * Creates an instance of {@code Duration} from a number of seconds.
+     *
+     * @param seconds  the number of seconds, up to scale 9, positive or negative
+     * @return a {@code Duration}, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    private static Duration create(BigDecimal seconds) {
+        BigInteger nanos = seconds.movePointRight(9).toBigIntegerExact();
+        BigInteger[] divRem = nanos.divideAndRemainder(BI_NANOS_PER_SECOND);
+        if (divRem[0].bitLength() > 63) {
+            throw new ArithmeticException("Exceeds capacity of Duration: " + nanos);
+        }
+        return ofSeconds(divRem[0].longValue(), divRem[1].intValue());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this duration with the length negated.
+     * <p>
+     * This method swaps the sign of the total length of this duration.
+     * For example, {@code PT1.3S} will be returned as {@code PT-1.3S}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @return a {@code Duration} based on this duration with the amount negated, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration negated() {
+        return multipliedBy(-1);
+    }
+
+    /**
+     * Returns a copy of this duration with a positive length.
+     * <p>
+     * This method returns a positive duration by effectively removing the sign from any negative total length.
+     * For example, {@code PT-1.3S} will be returned as {@code PT1.3S}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @return a {@code Duration} based on this duration with an absolute length, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration abs() {
+        return isNegative() ? negated() : this;
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Adds this duration to the specified temporal object.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with this duration added.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#plus(TemporalAdder)}.
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   dateTime = thisDuration.addTo(dateTime);
+     *   dateTime = dateTime.plus(thisDuration);
+     * </pre>
+     * <p>
+     * A {@code Duration} can only be added to a {@code Temporal} that
+     * represents an instant and can supply {@link ChronoField#INSTANT_SECONDS}.
+     * <p>
+     * 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) {
+        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);
+    }
+
+    /**
+     * Subtracts this duration from the specified temporal object.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with this duration subtracted.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#minus(TemporalSubtractor)}.
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   dateTime = thisDuration.subtractFrom(dateTime);
+     *   dateTime = dateTime.minus(thisDuration);
+     * </pre>
+     * <p>
+     * A {@code Duration} can only be subtracted from a {@code Temporal} that
+     * represents an instant and can supply {@link ChronoField#INSTANT_SECONDS}.
+     * <p>
+     * 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) {
+        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);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Converts this duration to the total length in milliseconds.
+     * <p>
+     * If this duration is too large to fit in a {@code long} milliseconds, then an
+     * exception is thrown.
+     * <p>
+     * If this duration has greater than millisecond precision, then the conversion
+     * will drop any excess precision information as though the amount in nanoseconds
+     * was subject to integer division by one million.
+     *
+     * @return the total length of the duration in milliseconds
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public long toMillis() {
+        long millis = Math.multiplyExact(seconds, 1000);
+        millis = Math.addExact(millis, nanos / 1000_000);
+        return millis;
+    }
+
+    /**
+     * Converts this duration to the total length in nanoseconds expressed as a {@code long}.
+     * <p>
+     * If this duration is too large to fit in a {@code long} nanoseconds, then an
+     * exception is thrown.
+     *
+     * @return the total length of the duration in nanoseconds
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public long toNanos() {
+        long millis = Math.multiplyExact(seconds, 1000_000_000);
+        millis = Math.addExact(millis, nanos);
+        return millis;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this duration to the specified {@code Duration}.
+     * <p>
+     * The comparison is based on the total length of the durations.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     *
+     * @param otherDuration  the other duration to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     */
+    @Override
+    public int compareTo(Duration otherDuration) {
+        int cmp = Long.compare(seconds, otherDuration.seconds);
+        if (cmp != 0) {
+            return cmp;
+        }
+        return nanos - otherDuration.nanos;
+    }
+
+    /**
+     * Checks if this duration is greater than the specified {@code Duration}.
+     * <p>
+     * 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}.
+     * <p>
+     * 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}.
+     * <p>
+     * The comparison is based on the total length of the durations.
+     *
+     * @param otherDuration  the other duration, null returns false
+     * @return true if the other duration is equal to this one
+     */
+    @Override
+    public boolean equals(Object otherDuration) {
+        if (this == otherDuration) {
+            return true;
+        }
+        if (otherDuration instanceof Duration) {
+            Duration other = (Duration) otherDuration;
+            return this.seconds == other.seconds &&
+                   this.nanos == other.nanos;
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this duration.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return ((int) (seconds ^ (seconds >>> 32))) + (51 * nanos);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * A string representation of this duration using ISO-8601 seconds
+     * based representation, such as {@code PT12.345S}.
+     * <p>
+     * The format of the returned string will be {@code PTnS} where n is
+     * the seconds and fractional seconds of the duration.
+     *
+     * @return an ISO-8601 representation of this duration, not null
+     */
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder(24);
+        buf.append("PT");
+        if (seconds < 0 && nanos > 0) {
+            if (seconds == -1) {
+                buf.append("-0");
+            } else {
+                buf.append(seconds + 1);
+            }
+        } else {
+            buf.append(seconds);
+        }
+        if (nanos > 0) {
+            int pos = buf.length();
+            if (seconds < 0) {
+                buf.append(2 * NANOS_PER_SECOND - nanos);
+            } else {
+                buf.append(nanos + NANOS_PER_SECOND);
+            }
+            while (buf.charAt(buf.length() - 1) == '0') {
+                buf.setLength(buf.length() - 1);
+            }
+            buf.setCharAt(pos, '.');
+        }
+        buf.append('S');
+        return buf.toString();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * <pre>
+     *  out.writeByte(1);  // identifies this as a Duration
+     *  out.writeLong(seconds);
+     *  out.writeInt(nanos);
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.DURATION_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     * @return never
+     * @throws InvalidObjectException always
+     */
+    private Object readResolve() throws ObjectStreamException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        out.writeLong(seconds);
+        out.writeInt(nanos);
+    }
+
+    static Duration readExternal(DataInput in) throws IOException {
+        long seconds = in.readLong();
+        int nanos = in.readInt();
+        return Duration.ofSeconds(seconds, nanos);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/Instant.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,1107 @@
+/*
+ * 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;
+
+import static java.time.LocalTime.SECONDS_PER_DAY;
+import static java.time.LocalTime.SECONDS_PER_HOUR;
+import static java.time.LocalTime.SECONDS_PER_MINUTE;
+import static java.time.temporal.ChronoField.INSTANT_SECONDS;
+import static java.time.temporal.ChronoField.MICRO_OF_SECOND;
+import static java.time.temporal.ChronoField.MILLI_OF_SECOND;
+import static java.time.temporal.ChronoField.NANO_OF_SECOND;
+import static java.time.temporal.ChronoUnit.NANOS;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.time.format.DateTimeFormatters;
+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.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;
+
+/**
+ * An instantaneous point on the time-line.
+ * <p>
+ * This class models a single instantaneous point on the time-line.
+ * This might be used to record event time-stamps in the application.
+ * <p>
+ * For practicality, the instant is stored with some constraints.
+ * The measurable time-line is restricted to the number of seconds that can be held
+ * in a {@code long}. This is greater than the current estimated age of the universe.
+ * The instant is stored to nanosecond resolution.
+ * <p>
+ * The range of an instant requires the storage of a number larger than a {@code long}.
+ * To achieve this, the class stores a {@code long} representing epoch-seconds and an
+ * {@code int} representing nanosecond-of-second, which will always be between 0 and 999,999,999.
+ * The epoch-seconds are measured from the standard Java epoch of {@code 1970-01-01T00:00:00Z}
+ * where instants after the epoch have positive values, and earlier instants have negative values.
+ * For both the epoch-second and nanosecond parts, a larger value is always later on the time-line
+ * than a smaller value.
+ *
+ * <h3>Time-scale</h3>
+ * <p>
+ * The length of the solar day is the standard way that humans measure time.
+ * This has traditionally been subdivided into 24 hours of 60 minutes of 60 seconds,
+ * forming a 86400 second day.
+ * <p>
+ * Modern timekeeping is based on atomic clocks which precisely define an SI second
+ * relative to the transitions of a Caesium atom. The length of an SI second was defined
+ * to be very close to the 86400th fraction of a day.
+ * <p>
+ * Unfortunately, as the Earth rotates the length of the day varies.
+ * In addition, over time the average length of the day is getting longer as the Earth slows.
+ * As a result, the length of a solar day in 2012 is slightly longer than 86400 SI seconds.
+ * The actual length of any given day and the amount by which the Earth is slowing
+ * are not predictable and can only be determined by measurement.
+ * The UT1 time-scale captures the accurate length of day, but is only available some
+ * time after the day has completed.
+ * <p>
+ * The UTC time-scale is a standard approach to bundle up all the additional fractions
+ * of a second from UT1 into whole seconds, known as <i>leap-seconds</i>.
+ * A leap-second may be added or removed depending on the Earth's rotational changes.
+ * As such, UTC permits a day to have 86399 SI seconds or 86401 SI seconds where
+ * necessary in order to keep the day aligned with the Sun.
+ * <p>
+ * The modern UTC time-scale was introduced in 1972, introducing the concept of whole leap-seconds.
+ * Between 1958 and 1972, the definition of UTC was complex, with minor sub-second leaps and
+ * alterations to the length of the notional second. As of 2012, discussions are underway
+ * to change the definition of UTC again, with the potential to remove leap seconds or
+ * introduce other changes.
+ * <p>
+ * Given the complexity of accurate timekeeping described above, this Java API defines
+ * its own time-scale with a simplification. The Java time-scale is defined as follows:
+ * <p><ul>
+ * <li>midday will always be exactly as defined by the agreed international civil time</li>
+ * <li>other times during the day will be broadly in line with the agreed international civil time</li>
+ * <li>the day will be divided into exactly 86400 subdivisions, referred to as "seconds"</li>
+ * <li>the Java "second" may differ from an SI second</li>
+ * </ul><p>
+ * Agreed international civil time is the base time-scale agreed by international convention,
+ * which in 2012 is UTC (with leap-seconds).
+ * <p>
+ * In 2012, the definition of the Java time-scale is the same as UTC for all days except
+ * those where a leap-second occurs. On days where a leap-second does occur, the time-scale
+ * effectively eliminates the leap-second, maintaining the fiction of 86400 seconds in the day.
+ * <p>
+ * The main benefit of always dividing the day into 86400 subdivisions is that it matches the
+ * expectations of most users of the API. The alternative is to force every user to understand
+ * what a leap second is and to force them to have special logic to handle them.
+ * Most applications do not have access to a clock that is accurate enough to record leap-seconds.
+ * Most applications also do not have a problem with a second being a very small amount longer or
+ * shorter than a real SI second during a leap-second.
+ * <p>
+ * If an application does have access to an accurate clock that reports leap-seconds, then the
+ * recommended technique to implement the Java time-scale is to use the UTC-SLS convention.
+ * <a href="http://www.cl.cam.ac.uk/~mgk25/time/utc-sls/">UTC-SLS</a> effectively smoothes the
+ * leap-second over the last 1000 seconds of the day, making each of the last 1000 "seconds"
+ * 1/1000th longer or shorter than a real SI second.
+ * <p>
+ * One final problem is the definition of the agreed international civil time before the
+ * introduction of modern UTC in 1972. This includes the Java epoch of {@code 1970-01-01}.
+ * It is intended that instants before 1972 be interpreted based on the solar day divided
+ * into 86400 subdivisions.
+ * <p>
+ * The Java time-scale is used for all date-time classes.
+ * This includes {@code Instant}, {@code LocalDate}, {@code LocalTime}, {@code OffsetDateTime},
+ * {@code ZonedDateTime} and {@code Duration}.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class Instant
+        implements Temporal, TemporalAdjuster, Comparable<Instant>, Serializable {
+
+    /**
+     * Constant for the 1970-01-01T00:00:00Z epoch instant.
+     */
+    public static final Instant EPOCH = new Instant(0, 0);
+    /**
+     * The minimum supported epoch second.
+     */
+    private static final long MIN_SECOND = -31557014167219200L;
+    /**
+     * The maximum supported epoch second.
+     */
+    private static final long MAX_SECOND = 31556889864403199L;
+    /**
+     * The minimum supported {@code Instant}, '-1000000000-01-01T00:00Z'.
+     * This could be used by an application as a "far past" instant.
+     * <p>
+     * This is one year earlier than the minimum {@code LocalDateTime}.
+     * This provides sufficient values to handle the range of {@code ZoneOffset}
+     * which affect the instant in addition to the local date-time.
+     * The value is also chosen such that the value of the year fits in
+     * an {@code int}.
+     */
+    public static final Instant MIN = Instant.ofEpochSecond(MIN_SECOND, 0);
+    /**
+     * The minimum supported {@code Instant}, '-1000000000-01-01T00:00Z'.
+     * This could be used by an application as a "far future" instant.
+     * <p>
+     * This is one year later than the maximum {@code LocalDateTime}.
+     * This provides sufficient values to handle the range of {@code ZoneOffset}
+     * which affect the instant in addition to the local date-time.
+     * The value is also chosen such that the value of the year fits in
+     * an {@code int}.
+     */
+    public static final Instant MAX = Instant.ofEpochSecond(MAX_SECOND, 999_999_999);
+
+    /**
+     * 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.
+     */
+    private final long seconds;
+    /**
+     * The number of nanoseconds, later along the time-line, from the seconds field.
+     * This is always positive, and never exceeds 999,999,999.
+     */
+    private final int nanos;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains the current instant from the system clock.
+     * <p>
+     * This will query the {@link Clock#systemUTC() system UTC clock} to
+     * obtain the current instant.
+     * <p>
+     * Using this method will prevent the ability to use an alternate time-source for
+     * testing because the clock is effectively hard-coded.
+     *
+     * @return the current instant using the system clock, not null
+     */
+    public static Instant now() {
+        return Clock.systemUTC().instant();
+    }
+
+    /**
+     * Obtains the current instant from the specified clock.
+     * <p>
+     * This will query the specified clock to obtain the current time.
+     * <p>
+     * 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 instant, not null
+     */
+    public static Instant now(Clock clock) {
+        Objects.requireNonNull(clock, "clock");
+        return clock.instant();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Instant} using seconds from the
+     * epoch of 1970-01-01T00:00:00Z.
+     * <p>
+     * The nanosecond field is set to zero.
+     *
+     * @param epochSecond  the number of seconds from 1970-01-01T00:00:00Z
+     * @return an instant, not null
+     * @throws DateTimeException if the instant exceeds the maximum or minimum instant
+     */
+    public static Instant ofEpochSecond(long epochSecond) {
+        return create(epochSecond, 0);
+    }
+
+    /**
+     * Obtains an instance of {@code Instant} using seconds from the
+     * epoch of 1970-01-01T00:00:00Z and nanosecond fraction of second.
+     * <p>
+     * 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
+     * to ensure that the stored nanosecond is in the range 0 to 999,999,999.
+     * For example, the following will result in the exactly the same instant:
+     * <pre>
+     *  Instant.ofSeconds(3, 1);
+     *  Instant.ofSeconds(4, -999_999_999);
+     *  Instant.ofSeconds(2, 1000_000_001);
+     * </pre>
+     *
+     * @param epochSecond  the number of seconds from 1970-01-01T00:00:00Z
+     * @param nanoAdjustment  the nanosecond adjustment to the number of seconds, positive or negative
+     * @return an instant, not null
+     * @throws DateTimeException if the instant exceeds the maximum or minimum instant
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public static Instant ofEpochSecond(long epochSecond, long nanoAdjustment) {
+        long secs = Math.addExact(epochSecond, Math.floorDiv(nanoAdjustment, NANOS_PER_SECOND));
+        int nos = (int)Math.floorMod(nanoAdjustment, NANOS_PER_SECOND);
+        return create(secs, nos);
+    }
+
+    /**
+     * Obtains an instance of {@code Instant} using milliseconds from the
+     * epoch of 1970-01-01T00:00:00Z.
+     * <p>
+     * The seconds and nanoseconds are extracted from the specified milliseconds.
+     *
+     * @param epochMilli  the number of milliseconds from 1970-01-01T00:00:00Z
+     * @return an instant, not null
+     * @throws DateTimeException if the instant exceeds the maximum or minimum instant
+     */
+    public static Instant ofEpochMilli(long epochMilli) {
+        long secs = Math.floorDiv(epochMilli, 1000);
+        int mos = (int)Math.floorMod(epochMilli, 1000);
+        return create(secs, mos * 1000_000);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Instant} from a temporal object.
+     * <p>
+     * A {@code TemporalAccessor} represents some form of date and time information.
+     * This factory converts the arbitrary temporal object to an instance of {@code Instant}.
+     * <p>
+     * The conversion extracts the {@link ChronoField#INSTANT_SECONDS INSTANT_SECONDS}
+     * and {@link ChronoField#NANO_OF_SECOND NANO_OF_SECOND} fields.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used as a query via method reference, {@code Instant::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the instant, not null
+     * @throws DateTimeException if unable to convert to an {@code Instant}
+     */
+    public static Instant from(TemporalAccessor temporal) {
+        long instantSecs = temporal.getLong(INSTANT_SECONDS);
+        int nanoOfSecond = temporal.get(NANO_OF_SECOND);
+        return Instant.ofEpochSecond(instantSecs, nanoOfSecond);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Instant} from a text string such as
+     * {@code 2007-12-03T10:15:30:00}.
+     * <p>
+     * The string must represent a valid instant in UTC and is parsed using
+     * {@link DateTimeFormatters#isoInstant()}.
+     *
+     * @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);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Instant} using seconds and nanoseconds.
+     *
+     * @param seconds  the length of the duration in seconds
+     * @param nanoOfSecond  the nano-of-second, from 0 to 999,999,999
+     * @throws DateTimeException if the instant exceeds the maximum or minimum instant
+     */
+    private static Instant create(long seconds, int nanoOfSecond) {
+        if ((seconds | nanoOfSecond) == 0) {
+            return EPOCH;
+        }
+        if (seconds < MIN_SECOND || seconds > MAX_SECOND) {
+            throw new DateTimeException("Instant exceeds minimum or maximum instant");
+        }
+        return new Instant(seconds, nanoOfSecond);
+    }
+
+    /**
+     * Constructs an instance of {@code Instant} using seconds from the epoch of
+     * 1970-01-01T00:00:00Z and nanosecond fraction of second.
+     *
+     * @param epochSecond  the number of seconds from 1970-01-01T00:00:00Z
+     * @param nanos  the nanoseconds within the second, must be positive
+     */
+    private Instant(long epochSecond, int nanos) {
+        super();
+        this.seconds = epochSecond;
+        this.nanos = nanos;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if this instant 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.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The supported fields are:
+     * <ul>
+     * <li>{@code NANO_OF_SECOND}
+     * <li>{@code MICRO_OF_SECOND}
+     * <li>{@code MILLI_OF_SECOND}
+     * <li>{@code INSTANT_SECONDS}
+     * </ul>
+     * All other {@code ChronoField} instances will return false.
+     * <p>
+     * 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 instant, false if not
+     */
+    @Override
+    public boolean isSupported(TemporalField field) {
+        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);
+    }
+
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * The range object expresses the minimum and maximum valid values for a field.
+     * This instant 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.
+     * <p>
+     * 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}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the range can be obtained is determined by the field.
+     *
+     * @param field  the field to query the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     */
+    @Override  // override for Javadoc
+    public ValueRange range(TemporalField field) {
+        return Temporal.super.range(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this instant as an {@code int}.
+     * <p>
+     * This queries this instant 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.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this date-time, except {@code INSTANT_SECONDS} which is too
+     * large to fit in an {@code int} and throws a {@code DateTimeException}.
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override  // override for Javadoc and performance
+    public int get(TemporalField field) {
+        if (field instanceof ChronoField) {
+            switch ((ChronoField) field) {
+                case NANO_OF_SECOND: return nanos;
+                case MICRO_OF_SECOND: return nanos / 1000;
+                case MILLI_OF_SECOND: return nanos / 1000_000;
+                case INSTANT_SECONDS: INSTANT_SECONDS.checkValidIntValue(seconds);
+            }
+            throw new DateTimeException("Unsupported field: " + field.getName());
+        }
+        return range(field).checkValidIntValue(field.doGet(this), field);
+    }
+
+    /**
+     * Gets the value of the specified field from this instant as a {@code long}.
+     * <p>
+     * This queries this instant 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.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this date-time.
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long getLong(TemporalField field) {
+        if (field instanceof ChronoField) {
+            switch ((ChronoField) field) {
+                case NANO_OF_SECOND: return nanos;
+                case MICRO_OF_SECOND: return nanos / 1000;
+                case MILLI_OF_SECOND: return nanos / 1000_000;
+                case INSTANT_SECONDS: return seconds;
+            }
+            throw new DateTimeException("Unsupported field: " + field.getName());
+        }
+        return field.doGet(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the number of seconds from the Java epoch of 1970-01-01T00:00:00Z.
+     * <p>
+     * The epoch second count is a simple incrementing count of seconds where
+     * second 0 is 1970-01-01T00:00:00Z.
+     * The nanosecond part of the day is returned by {@code getNanosOfSecond}.
+     *
+     * @return the seconds from the epoch of 1970-01-01T00:00:00Z
+     */
+    public long getEpochSecond() {
+        return seconds;
+    }
+
+    /**
+     * Gets the number of nanoseconds, later along the time-line, from the start
+     * of the second.
+     * <p>
+     * The nanosecond-of-second value measures the total number of nanoseconds from
+     * the second returned by {@code getEpochSecond}.
+     *
+     * @return the nanoseconds within the second, always positive, never exceeds 999,999,999
+     */
+    public int getNano() {
+        return nanos;
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Returns an adjusted copy of this instant.
+     * <p>
+     * This returns a new {@code Instant}, 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.
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param adjuster the adjuster to use, not null
+     * @return an {@code Instant} 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 Instant with(TemporalAdjuster adjuster) {
+        return (Instant) adjuster.adjustInto(this);
+    }
+
+    /**
+     * Returns a copy of this instant with the specified field set to a new value.
+     * <p>
+     * This returns a new {@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.
+     * <p>
+     * If the field is a {@link ChronoField} then the adjustment is implemented here.
+     * The supported fields behave as follows:
+     * <ul>
+     * <li>{@code NANO_OF_SECOND} -
+     *  Returns an {@code Instant} with the specified nano-of-second.
+     *  The epoch-second will be unchanged.
+     * <li>{@code MICRO_OF_SECOND} -
+     *  Returns an {@code Instant} with the nano-of-second replaced by the specified
+     *  micro-of-second multiplied by 1,000. The epoch-second will be unchanged.
+     * <li>{@code MILLI_OF_SECOND} -
+     *  Returns an {@code Instant} with the nano-of-second replaced by the specified
+     *  milli-of-second multiplied by 1,000,000. The epoch-second will be unchanged.
+     * <li>{@code INSTANT_SECONDS} -
+     *  Returns an {@code Instant} with the specified epoch-second.
+     *  The nano-of-second will be unchanged.
+     * </ul>
+     * <p>
+     * In all cases, if the new value is outside the valid range of values for the field
+     * then a {@code DateTimeException} will be thrown.
+     * <p>
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * 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.
+     * <p>
+     * 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 Instant} 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 Instant with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            f.checkValidValue(newValue);
+            switch (f) {
+                case MILLI_OF_SECOND: {
+                    int nval = (int) newValue * 1000_000;
+                    return (nval != nanos ? create(seconds, nval) : this);
+                }
+                case MICRO_OF_SECOND: {
+                    int nval = (int) newValue * 1000;
+                    return (nval != nanos ? create(seconds, nval) : this);
+                }
+                case NANO_OF_SECOND: return (newValue != nanos ? create(seconds, (int) newValue) : this);
+                case INSTANT_SECONDS: return (newValue != seconds ? create(newValue, nanos) : this);
+            }
+            throw new DateTimeException("Unsupported field: " + field.getName());
+        }
+        return field.doWith(this, newValue);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public Instant plus(TemporalAdder adder) {
+        return (Instant) adder.addTo(this);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public Instant plus(long amountToAdd, TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            switch ((ChronoUnit) unit) {
+                case NANOS: return plusNanos(amountToAdd);
+                case MICROS: return plus(amountToAdd / 1000_000, (amountToAdd % 1000_000) * 1000);
+                case MILLIS: return plusMillis(amountToAdd);
+                case SECONDS: return plusSeconds(amountToAdd);
+                case MINUTES: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_MINUTE));
+                case HOURS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_HOUR));
+                case HALF_DAYS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY / 2));
+                case DAYS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY));
+            }
+            throw new DateTimeException("Unsupported unit: " + unit.getName());
+        }
+        return unit.doPlus(this, amountToAdd);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this instant with the specified duration in seconds added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param secondsToAdd  the seconds to add, positive or negative
+     * @return an {@code Instant} based on this instant with the specified seconds added, not null
+     * @throws DateTimeException if the result exceeds the maximum or minimum instant
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Instant plusSeconds(long secondsToAdd) {
+        return plus(secondsToAdd, 0);
+    }
+
+    /**
+     * Returns a copy of this instant with the specified duration in milliseconds added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param millisToAdd  the milliseconds to add, positive or negative
+     * @return an {@code Instant} based on this instant with the specified milliseconds added, not null
+     * @throws DateTimeException if the result exceeds the maximum or minimum instant
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Instant plusMillis(long millisToAdd) {
+        return plus(millisToAdd / 1000, (millisToAdd % 1000) * 1000_000);
+    }
+
+    /**
+     * Returns a copy of this instant with the specified duration in nanoseconds added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanosToAdd  the nanoseconds to add, positive or negative
+     * @return an {@code Instant} based on this instant with the specified nanoseconds added, not null
+     * @throws DateTimeException if the result exceeds the maximum or minimum instant
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Instant plusNanos(long nanosToAdd) {
+        return plus(0, nanosToAdd);
+    }
+
+    /**
+     * Returns a copy of this instant with the specified duration added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param secondsToAdd  the seconds to add, positive or negative
+     * @param nanosToAdd  the nanos to add, positive or negative
+     * @return an {@code Instant} based on this instant with the specified seconds added, not null
+     * @throws DateTimeException if the result exceeds the maximum or minimum instant
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    private Instant plus(long secondsToAdd, long nanosToAdd) {
+        if ((secondsToAdd | nanosToAdd) == 0) {
+            return this;
+        }
+        long epochSec = Math.addExact(seconds, secondsToAdd);
+        epochSec = Math.addExact(epochSec, nanosToAdd / NANOS_PER_SECOND);
+        nanosToAdd = nanosToAdd % NANOS_PER_SECOND;
+        long nanoAdjustment = nanos + nanosToAdd;  // safe int+NANOS_PER_SECOND
+        return ofEpochSecond(epochSec, nanoAdjustment);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public Instant minus(TemporalSubtractor subtractor) {
+        return (Instant) subtractor.subtractFrom(this);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public Instant 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 instant with the specified duration in seconds subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param secondsToSubtract  the seconds to subtract, positive or negative
+     * @return an {@code Instant} based on this instant with the specified seconds subtracted, not null
+     * @throws DateTimeException if the result exceeds the maximum or minimum instant
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Instant minusSeconds(long secondsToSubtract) {
+        if (secondsToSubtract == Long.MIN_VALUE) {
+            return plusSeconds(Long.MAX_VALUE).plusSeconds(1);
+        }
+        return plusSeconds(-secondsToSubtract);
+    }
+
+    /**
+     * Returns a copy of this instant with the specified duration in milliseconds subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param millisToSubtract  the milliseconds to subtract, positive or negative
+     * @return an {@code Instant} based on this instant with the specified milliseconds subtracted, not null
+     * @throws DateTimeException if the result exceeds the maximum or minimum instant
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Instant minusMillis(long millisToSubtract) {
+        if (millisToSubtract == Long.MIN_VALUE) {
+            return plusMillis(Long.MAX_VALUE).plusMillis(1);
+        }
+        return plusMillis(-millisToSubtract);
+    }
+
+    /**
+     * Returns a copy of this instant with the specified duration in nanoseconds subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanosToSubtract  the nanoseconds to subtract, positive or negative
+     * @return an {@code Instant} based on this instant with the specified nanoseconds subtracted, not null
+     * @throws DateTimeException if the result exceeds the maximum or minimum instant
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Instant minusNanos(long nanosToSubtract) {
+        if (nanosToSubtract == Long.MIN_VALUE) {
+            return plusNanos(Long.MAX_VALUE).plusNanos(1);
+        }
+        return plusNanos(-nanosToSubtract);
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Queries this instant using the specified query.
+     * <p>
+     * This queries this instant 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.
+     * <p>
+     * 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 <R> 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> R query(TemporalQuery<R> query) {
+        if (query == Queries.precision()) {
+            return (R) NANOS;
+        }
+        // inline TemporalAccessor.super.query(query) as an optimization
+        if (query == Queries.chrono() || query == Queries.zoneId() || query == Queries.zone() || query == Queries.offset()) {
+            return null;
+        }
+        return query.queryFrom(this);
+    }
+
+    /**
+     * Adjusts the specified temporal object to have this instant.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with the instant changed to be the same as this.
+     * <p>
+     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+     * twice, passing {@link ChronoField#INSTANT_SECONDS} and
+     * {@link ChronoField#NANO_OF_SECOND} as the fields.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisInstant.adjustInto(temporal);
+     *   temporal = temporal.with(thisInstant);
+     * </pre>
+     * <p>
+     * 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(INSTANT_SECONDS, seconds).with(NANO_OF_SECOND, nanos);
+    }
+
+    /**
+     * Calculates the period between this instant and another instant in
+     * terms of the specified unit.
+     * <p>
+     * This calculates the period between two instants in terms of a single unit.
+     * The start and end points are {@code this} and the specified instant.
+     * The result will be negative if the end is before the start.
+     * The calculation returns a whole number, representing the number of
+     * complete units between the two instants.
+     * The {@code Temporal} passed to this method must be an {@code Instant}.
+     * For example, the period in days between two dates can be calculated
+     * using {@code startInstant.periodUntil(endInstant, SECONDS)}.
+     * <p>
+     * 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:
+     * <pre>
+     *   long period = start.periodUntil(end, SECONDS);   // this method
+     *   dateTime.plus(SECONDS.between(start, end));      // use in plus/minus
+     * </pre>
+     * <p>
+     * The calculation is implemented in this method for {@link ChronoUnit}.
+     * The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS},
+     * {@code MINUTES}, {@code HOURS}, {@code HALF_DAYS} and {@code DAYS}
+     * are supported. Other {@code ChronoUnit} values will throw an exception.
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param endInstant  the end date, which must be a {@code LocalDate}, 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 endInstant, TemporalUnit unit) {
+        if (endInstant instanceof Instant == false) {
+            Objects.requireNonNull(endInstant, "endInstant");
+            throw new DateTimeException("Unable to calculate period between objects of two different types");
+        }
+        Instant end = (Instant) endInstant;
+        if (unit instanceof ChronoUnit) {
+            ChronoUnit f = (ChronoUnit) unit;
+            switch (f) {
+                case NANOS: return nanosUntil(end);
+                case MICROS: return nanosUntil(end) / 1000;
+                case MILLIS: return Math.subtractExact(end.toEpochMilli(), toEpochMilli());
+                case SECONDS: return secondsUntil(end);
+                case MINUTES: return secondsUntil(end) / SECONDS_PER_MINUTE;
+                case HOURS: return secondsUntil(end) / SECONDS_PER_HOUR;
+                case HALF_DAYS: return secondsUntil(end) / (12 * SECONDS_PER_HOUR);
+                case DAYS: return secondsUntil(end) / (SECONDS_PER_DAY);
+            }
+            throw new DateTimeException("Unsupported unit: " + unit.getName());
+        }
+        return unit.between(this, endInstant).getAmount();
+    }
+
+    private long nanosUntil(Instant end) {
+        long secs = Math.multiplyExact(secondsUntil(end), NANOS_PER_SECOND);
+        return Math.addExact(secs, end.nanos - nanos);
+    }
+
+    private long secondsUntil(Instant end) {
+        return Math.subtractExact(end.seconds, seconds);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Converts this instant to the number of milliseconds from the epoch
+     * of 1970-01-01T00:00:00Z.
+     * <p>
+     * If this instant represents a point on the time-line too far in the future
+     * or past to fit in a {@code long} milliseconds, then an exception is thrown.
+     * <p>
+     * If this instant has greater than millisecond precision, then the conversion
+     * will drop any excess precision information as though the amount in nanoseconds
+     * was subject to integer division by one million.
+     *
+     * @return the number of milliseconds since the epoch of 1970-01-01T00:00:00Z
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public long toEpochMilli() {
+        long millis = Math.multiplyExact(seconds, 1000);
+        return millis + nanos / 1000_000;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this instant to the specified instant.
+     * <p>
+     * The comparison is based on the time-line position of the instants.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     *
+     * @param otherInstant  the other instant to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     * @throws NullPointerException if otherInstant is null
+     */
+    @Override
+    public int compareTo(Instant otherInstant) {
+        int cmp = Long.compare(seconds, otherInstant.seconds);
+        if (cmp != 0) {
+            return cmp;
+        }
+        return nanos - otherInstant.nanos;
+    }
+
+    /**
+     * Checks if this instant is after the specified instant.
+     * <p>
+     * The comparison is based on the time-line position of the instants.
+     *
+     * @param otherInstant  the other instant to compare to, not null
+     * @return true if this instant is after the specified instant
+     * @throws NullPointerException if otherInstant is null
+     */
+    public boolean isAfter(Instant otherInstant) {
+        return compareTo(otherInstant) > 0;
+    }
+
+    /**
+     * Checks if this instant is before the specified instant.
+     * <p>
+     * The comparison is based on the time-line position of the instants.
+     *
+     * @param otherInstant  the other instant to compare to, not null
+     * @return true if this instant is before the specified instant
+     * @throws NullPointerException if otherInstant is null
+     */
+    public boolean isBefore(Instant otherInstant) {
+        return compareTo(otherInstant) < 0;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this instant is equal to the specified instant.
+     * <p>
+     * The comparison is based on the time-line position of the instants.
+     *
+     * @param otherInstant  the other instant, null returns false
+     * @return true if the other instant is equal to this one
+     */
+    @Override
+    public boolean equals(Object otherInstant) {
+        if (this == otherInstant) {
+            return true;
+        }
+        if (otherInstant instanceof Instant) {
+            Instant other = (Instant) otherInstant;
+            return this.seconds == other.seconds &&
+                   this.nanos == other.nanos;
+        }
+        return false;
+    }
+
+    /**
+     * Returns a hash code for this instant.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return ((int) (seconds ^ (seconds >>> 32))) + 51 * nanos;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * A string representation of this instant using ISO-8601 representation.
+     * <p>
+     * The format used is the same as {@link DateTimeFormatters#isoInstant()}.
+     *
+     * @return an ISO-8601 representation of this instant, not null
+     */
+    @Override
+    public String toString() {
+        return DateTimeFormatters.isoInstant().print(this);
+    }
+
+    // -----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * <pre>
+     *  out.writeByte(2);  // identifies this as an Instant
+     *  out.writeLong(seconds);
+     *  out.writeInt(nanos);
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.INSTANT_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     * @return never
+     * @throws InvalidObjectException always
+     */
+    private Object readResolve() throws ObjectStreamException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        out.writeLong(seconds);
+        out.writeInt(nanos);
+    }
+
+    static Instant readExternal(DataInput in) throws IOException {
+        long seconds = in.readLong();
+        int nanos = in.readInt();
+        return Instant.ofEpochSecond(seconds, nanos);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/LocalDate.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,1875 @@
+/*
+ * 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;
+
+import static java.time.LocalTime.SECONDS_PER_DAY;
+import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH;
+import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR;
+import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH;
+import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR;
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.DAY_OF_YEAR;
+import static java.time.temporal.ChronoField.EPOCH_DAY;
+import static java.time.temporal.ChronoField.EPOCH_MONTH;
+import static java.time.temporal.ChronoField.ERA;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.YEAR;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.time.format.DateTimeBuilder;
+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.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdder;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.TemporalSubtractor;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.ValueRange;
+import java.time.temporal.Year;
+import java.time.zone.ZoneOffsetTransition;
+import java.time.zone.ZoneRules;
+import java.util.Objects;
+
+/**
+ * A date without a time-zone in the ISO-8601 calendar system,
+ * such as {@code 2007-12-03}.
+ * <p>
+ * {@code LocalDate} is an immutable date-time object that represents a date,
+ * often viewed as year-month-day. Other date fields, such as day-of-year,
+ * day-of-week and week-of-year, can also be accessed.
+ * For example, the value "2nd October 2007" can be stored in a {@code LocalDate}.
+ * <p>
+ * This class does not store or represent a time or time-zone.
+ * Instead, it is a description of the date, as used for birthdays.
+ * It cannot represent an instant on the time-line without additional information
+ * such as an offset or time-zone.
+ * <p>
+ * The ISO-8601 calendar system is the modern civil calendar system used today
+ * in most of the world. It is equivalent to the proleptic Gregorian calendar
+ * system, in which today's rules for leap years are applied for all time.
+ * For most applications written today, the ISO-8601 rules are entirely suitable.
+ * However, any application that makes use of historical dates, and requires them
+ * to be accurate will find the ISO-8601 approach unsuitable.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class LocalDate
+        implements Temporal, TemporalAdjuster, ChronoLocalDate<ISOChrono>, Serializable {
+
+    /**
+     * The minimum supported {@code LocalDate}, '-999999999-01-01'.
+     * This could be used by an application as a "far past" date.
+     */
+    public static final LocalDate MIN = LocalDate.of(Year.MIN_VALUE, 1, 1);
+    /**
+     * The maximum supported {@code LocalDate}, '+999999999-12-31'.
+     * This could be used by an application as a "far future" date.
+     */
+    public static final LocalDate MAX = LocalDate.of(Year.MAX_VALUE, 12, 31);
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 2942565459149668126L;
+    /**
+     * The number of days in a 400 year cycle.
+     */
+    private static final int DAYS_PER_CYCLE = 146097;
+    /**
+     * The number of days from year zero to year 1970.
+     * There are five 400 year cycles from year zero to 2000.
+     * There are 7 leap years from 1970 to 2000.
+     */
+    static final long DAYS_0000_TO_1970 = (DAYS_PER_CYCLE * 5L) - (30L * 365L + 7L);
+
+    /**
+     * The year.
+     */
+    private final int year;
+    /**
+     * The month-of-year.
+     */
+    private final short month;
+    /**
+     * The day-of-month.
+     */
+    private final short day;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains the current date from the system clock in the default time-zone.
+     * <p>
+     * This will query the {@link Clock#systemDefaultZone() system clock} in the default
+     * time-zone to obtain the current date.
+     * <p>
+     * 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 LocalDate now() {
+        return now(Clock.systemDefaultZone());
+    }
+
+    /**
+     * Obtains the current date from the system clock in the specified time-zone.
+     * <p>
+     * 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.
+     * <p>
+     * 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 LocalDate now(ZoneId zone) {
+        return now(Clock.system(zone));
+    }
+
+    /**
+     * Obtains the current date from the specified clock.
+     * <p>
+     * This will query the specified clock to obtain the current date - today.
+     * Using this method allows the use of an alternate clock for testing.
+     * The alternate clock may be introduced using {@link Clock dependency injection}.
+     *
+     * @param clock  the clock to use, not null
+     * @return the current date, not null
+     */
+    public static LocalDate now(Clock clock) {
+        Objects.requireNonNull(clock, "clock");
+        // inline OffsetDate factory to avoid creating object and InstantProvider checks
+        final Instant now = clock.instant();  // called once
+        ZoneOffset offset = clock.getZone().getRules().getOffset(now);
+        long epochSec = now.getEpochSecond() + offset.getTotalSeconds();  // overflow caught later
+        long epochDay = Math.floorDiv(epochSec, SECONDS_PER_DAY);
+        return LocalDate.ofEpochDay(epochDay);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code LocalDate} from a year, month and day.
+     * <p>
+     * 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
+     */
+    public static LocalDate of(int year, Month month, int dayOfMonth) {
+        YEAR.checkValidValue(year);
+        Objects.requireNonNull(month, "month");
+        DAY_OF_MONTH.checkValidValue(dayOfMonth);
+        return create(year, month, dayOfMonth);
+    }
+
+    /**
+     * Obtains an instance of {@code LocalDate} from a year, month and day.
+     * <p>
+     * The day must be valid for the year and month, otherwise an exception will be thrown.
+     *
+     * @param year  the year to represent, from MIN_YEAR to MAX_YEAR
+     * @param month  the month-of-year to represent, from 1 (January) to 12 (December)
+     * @param dayOfMonth  the day-of-month to represent, from 1 to 31
+     * @return the local date, not null
+     * @throws DateTimeException if the value of any field is out of range
+     * @throws DateTimeException if the day-of-month is invalid for the month-year
+     */
+    public static LocalDate of(int year, int month, int dayOfMonth) {
+        YEAR.checkValidValue(year);
+        MONTH_OF_YEAR.checkValidValue(month);
+        DAY_OF_MONTH.checkValidValue(dayOfMonth);
+        return create(year, Month.of(month), dayOfMonth);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code LocalDate} from a year and day-of-year.
+     * <p>
+     * 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
+     */
+    public static LocalDate ofYearDay(int year, int dayOfYear) {
+        YEAR.checkValidValue(year);
+        DAY_OF_YEAR.checkValidValue(dayOfYear);
+        boolean leap = ISOChrono.INSTANCE.isLeapYear(year);
+        if (dayOfYear == 366 && leap == false) {
+            throw new DateTimeException("Invalid date 'DayOfYear 366' as '" + year + "' is not a leap year");
+        }
+        Month moy = Month.of((dayOfYear - 1) / 31 + 1);
+        int monthEnd = moy.firstDayOfYear(leap) + moy.length(leap) - 1;
+        if (dayOfYear > monthEnd) {
+            moy = moy.plus(1);
+        }
+        int dom = dayOfYear - moy.firstDayOfYear(leap) + 1;
+        return create(year, moy, dom);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code LocalDate} from the epoch day count.
+     * <p>
+     * The Epoch Day count is a simple incrementing count of days
+     * where day 0 is 1970-01-01. Negative numbers represent earlier days.
+     *
+     * @param epochDay  the Epoch Day to convert, based on the epoch 1970-01-01
+     * @return the local date, not null
+     * @throws DateTimeException if the epoch days exceeds the supported date range
+     */
+    public static LocalDate ofEpochDay(long epochDay) {
+        long zeroDay = epochDay + DAYS_0000_TO_1970;
+        // find the march-based year
+        zeroDay -= 60;  // adjust to 0000-03-01 so leap day is at end of four year cycle
+        long adjust = 0;
+        if (zeroDay < 0) {
+            // adjust negative years to positive for calculation
+            long adjustCycles = (zeroDay + 1) / DAYS_PER_CYCLE - 1;
+            adjust = adjustCycles * 400;
+            zeroDay += -adjustCycles * DAYS_PER_CYCLE;
+        }
+        long yearEst = (400 * zeroDay + 591) / DAYS_PER_CYCLE;
+        long doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400);
+        if (doyEst < 0) {
+            // fix estimate
+            yearEst--;
+            doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400);
+        }
+        yearEst += adjust;  // reset any negative year
+        int marchDoy0 = (int) doyEst;
+
+        // convert march-based values back to january-based
+        int marchMonth0 = (marchDoy0 * 5 + 2) / 153;
+        int month = (marchMonth0 + 2) % 12 + 1;
+        int dom = marchDoy0 - (marchMonth0 * 306 + 5) / 10 + 1;
+        yearEst += marchMonth0 / 10;
+
+        // check year now we are certain it is correct
+        int year = YEAR.checkValidIntValue(yearEst);
+        return new LocalDate(year, month, dom);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code LocalDate} from a temporal object.
+     * <p>
+     * A {@code TemporalAccessor} represents some form of date and time information.
+     * This factory converts the arbitrary temporal object to an instance of {@code LocalDate}.
+     * <p>
+     * The conversion extracts the {@link ChronoField#EPOCH_DAY EPOCH_DAY} field.
+     * <p>
+     * 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}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the local date, not null
+     * @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);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code LocalDate} from a text string such as {@code 2007-12-03}.
+     * <p>
+     * The string must represent a valid date and is parsed using
+     * {@link java.time.format.DateTimeFormatters#isoLocalDate()}.
+     *
+     * @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());
+    }
+
+    /**
+     * Obtains an instance of {@code LocalDate} from a text string using a specific formatter.
+     * <p>
+     * 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 local date, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static LocalDate parse(CharSequence text, DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.parse(text, LocalDate::from);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Creates a local date from the year, month and day fields.
+     *
+     * @param year  the year to represent, validated from MIN_YEAR to MAX_YEAR
+     * @param month  the month-of-year to represent, validated not null
+     * @param dayOfMonth  the day-of-month to represent, validated from 1 to 31
+     * @return the local date, not null
+     * @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 == 29) {
+                throw new DateTimeException("Invalid date 'February 29' as '" + year + "' is not a leap year");
+            } else {
+                throw new DateTimeException("Invalid date '" + month.name() + " " + dayOfMonth + "'");
+            }
+        }
+        return new LocalDate(year, month.getValue(), dayOfMonth);
+    }
+
+    /**
+     * Resolves the date, resolving days past the end of month.
+     *
+     * @param year  the year to represent, validated from MIN_YEAR to MAX_YEAR
+     * @param month  the month-of-year to represent, validated from 1 to 12
+     * @param day  the day-of-month to represent, validated from 1 to 31
+     * @return the resolved date, not null
+     */
+    private static LocalDate resolvePreviousValid(int year, int month, int day) {
+        switch (month) {
+            case 2:
+                day = Math.min(day, ISOChrono.INSTANCE.isLeapYear(year) ? 29 : 28);
+                break;
+            case 4:
+            case 6:
+            case 9:
+            case 11:
+                day = Math.min(day, 30);
+                break;
+        }
+        return LocalDate.of(year, month, day);
+    }
+
+    /**
+     * Constructor, previously validated.
+     *
+     * @param year  the year to represent, from MIN_YEAR to MAX_YEAR
+     * @param month  the month-of-year to represent, not null
+     * @param dayOfMonth  the day-of-month to represent, valid for year-month, from 1 to 31
+     */
+    private LocalDate(int year, int month, int dayOfMonth) {
+        this.year = year;
+        this.month = (short) month;
+        this.day = (short) dayOfMonth;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * 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.
+     * <p>
+     * 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:
+     * <ul>
+     * <li>{@code DAY_OF_WEEK}
+     * <li>{@code ALIGNED_DAY_OF_WEEK_IN_MONTH}
+     * <li>{@code ALIGNED_DAY_OF_WEEK_IN_YEAR}
+     * <li>{@code DAY_OF_MONTH}
+     * <li>{@code DAY_OF_YEAR}
+     * <li>{@code EPOCH_DAY}
+     * <li>{@code ALIGNED_WEEK_OF_MONTH}
+     * <li>{@code ALIGNED_WEEK_OF_YEAR}
+     * <li>{@code MONTH_OF_YEAR}
+     * <li>{@code EPOCH_MONTH}
+     * <li>{@code YEAR_OF_ERA}
+     * <li>{@code YEAR}
+     * <li>{@code ERA}
+     * </ul>
+     * All other {@code ChronoField} instances will return false.
+     * <p>
+     * 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  // override for Javadoc
+    public boolean isSupported(TemporalField field) {
+        return ChronoLocalDate.super.isSupported(field);
+    }
+
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * 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.
+     * <p>
+     * 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}.
+     * <p>
+     * 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) {
+            ChronoField f = (ChronoField) field;
+            if (f.isDateField()) {
+                switch (f) {
+                    case DAY_OF_MONTH: return ValueRange.of(1, lengthOfMonth());
+                    case DAY_OF_YEAR: return ValueRange.of(1, lengthOfYear());
+                    case ALIGNED_WEEK_OF_MONTH: return ValueRange.of(1, getMonth() == Month.FEBRUARY && isLeapYear() == false ? 4 : 5);
+                    case YEAR_OF_ERA:
+                        return (getYear() <= 0 ? ValueRange.of(1, Year.MAX_VALUE + 1) : ValueRange.of(1, Year.MAX_VALUE));
+                }
+                return field.range();
+            }
+            throw new DateTimeException("Unsupported field: " + field.getName());
+        }
+        return field.doRange(this);
+    }
+
+    /**
+     * Gets the value of the specified field from this date as an {@code int}.
+     * <p>
+     * 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.
+     * <p>
+     * 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}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override  // override for Javadoc and performance
+    public int get(TemporalField field) {
+        if (field instanceof ChronoField) {
+            return get0(field);
+        }
+        return ChronoLocalDate.super.get(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this date as a {@code long}.
+     * <p>
+     * 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.
+     * <p>
+     * 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}.
+     * <p>
+     * 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 == EPOCH_DAY) {
+                return toEpochDay();
+            }
+            if (field == EPOCH_MONTH) {
+                return getEpochMonth();
+            }
+            return get0(field);
+        }
+        return field.doGet(this);
+    }
+
+    private int get0(TemporalField field) {
+        switch ((ChronoField) field) {
+            case DAY_OF_WEEK: return getDayOfWeek().getValue();
+            case ALIGNED_DAY_OF_WEEK_IN_MONTH: return ((day - 1) % 7) + 1;
+            case ALIGNED_DAY_OF_WEEK_IN_YEAR: return ((getDayOfYear() - 1) % 7) + 1;
+            case DAY_OF_MONTH: return day;
+            case DAY_OF_YEAR: return getDayOfYear();
+            case EPOCH_DAY: throw new DateTimeException("Field too large for an int: " + field);
+            case ALIGNED_WEEK_OF_MONTH: return ((day - 1) / 7) + 1;
+            case ALIGNED_WEEK_OF_YEAR: return ((getDayOfYear() - 1) / 7) + 1;
+            case MONTH_OF_YEAR: return month;
+            case EPOCH_MONTH: throw new DateTimeException("Field too large for an int: " + field);
+            case YEAR_OF_ERA: return (year >= 1 ? year : 1 - year);
+            case YEAR: return year;
+            case ERA: return (year >= 1 ? 1 : 0);
+        }
+        throw new DateTimeException("Unsupported field: " + field.getName());
+    }
+
+    private long getEpochMonth() {
+        return ((year - 1970) * 12L) + (month - 1);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the chronology of this date, which is the ISO calendar system.
+     * <p>
+     * The {@code Chrono} represents the calendar system in use.
+     * The ISO-8601 calendar system is the modern civil calendar system used today
+     * in most of the world. It is equivalent to the proleptic Gregorian calendar
+     * system, in which todays's rules for leap years are applied for all time.
+     *
+     * @return the ISO chronology, not null
+     */
+    @Override
+    public ISOChrono getChrono() {
+        return ISOChrono.INSTANCE;
+    }
+
+    /**
+     * Gets the era applicable at this date.
+     * <p>
+     * The official ISO-8601 standard does not define eras, however {@code ISOChrono} does.
+     * It defines two eras, 'CE' from year one onwards and 'BCE' from year zero backwards.
+     * Since dates before the Julian-Gregorian cutover are not in line with history,
+     * the cutover between 'BCE' and 'CE' is also not aligned with the commonly used
+     * eras, often referred to using 'BC' and 'AD'.
+     * <p>
+     * Users of this class should typically ignore this method as it exists primarily
+     * to fulfill the {@link ChronoLocalDate} contract where it is necessary to support
+     * the Japanese calendar system.
+     * <p>
+     * The returned era will be a singleton capable of being compared with the constants
+     * in {@link ISOChrono} using the {@code ==} operator.
+     *
+     * @return the {@code ISOChrono} era constant applicable at this date, not null
+     */
+    @Override // override for Javadoc
+    public Era<ISOChrono> getEra() {
+        return ChronoLocalDate.super.getEra();
+    }
+
+    /**
+     * Gets the year field.
+     * <p>
+     * This method returns the primitive {@code int} value for the year.
+     * <p>
+     * The year returned by this method is proleptic as per {@code get(YEAR)}.
+     * To obtain the year-of-era, use {@code get(YEAR_OF_ERA}.
+     *
+     * @return the year, from MIN_YEAR to MAX_YEAR
+     */
+    public int getYear() {
+        return year;
+    }
+
+    /**
+     * Gets the month-of-year field from 1 to 12.
+     * <p>
+     * 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 month;
+    }
+
+    /**
+     * Gets the month-of-year field using the {@code Month} enum.
+     * <p>
+     * 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 Month.of(month);
+    }
+
+    /**
+     * Gets the day-of-month field.
+     * <p>
+     * This method returns the primitive {@code int} value for the day-of-month.
+     *
+     * @return the day-of-month, from 1 to 31
+     */
+    public int getDayOfMonth() {
+        return day;
+    }
+
+    /**
+     * Gets the day-of-year field.
+     * <p>
+     * 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 getMonth().firstDayOfYear(isLeapYear()) + day - 1;
+    }
+
+    /**
+     * Gets the day-of-week field, which is an enum {@code DayOfWeek}.
+     * <p>
+     * This method returns the enum {@link 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 DayOfWeek#getValue() int value}.
+     * <p>
+     * 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() {
+        int dow0 = (int)Math.floorMod(toEpochDay() + 3, 7);
+        return DayOfWeek.of(dow0 + 1);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the year is a leap year, according to the ISO proleptic
+     * calendar system rules.
+     * <p>
+     * This method applies the current rules for leap years across the whole time-line.
+     * In general, a year is a leap year if it is divisible by four without
+     * remainder. However, years divisible by 100, are not leap years, with
+     * the exception of years divisible by 400 which are.
+     * <p>
+     * For example, 1904 is a leap year it is divisible by 4.
+     * 1900 was not a leap year as it is divisible by 100, however 2000 was a
+     * leap year as it is divisible by 400.
+     * <p>
+     * The calculation is proleptic - applying the same rules into the far future and far past.
+     * This is historically inaccurate, but is correct for the ISO-8601 standard.
+     *
+     * @return true if the year is leap, false otherwise
+     */
+    @Override // override for Javadoc and performance
+    public boolean isLeapYear() {
+        return ISOChrono.INSTANCE.isLeapYear(year);
+    }
+
+    /**
+     * Returns the length of the month represented by this date.
+     * <p>
+     * This returns the length of the month in days.
+     * For example, a date in January would return 31.
+     *
+     * @return the length of the month in days
+     */
+    @Override
+    public int lengthOfMonth() {
+        switch (month) {
+            case 2:
+                return (isLeapYear() ? 29 : 28);
+            case 4:
+            case 6:
+            case 9:
+            case 11:
+                return 30;
+            default:
+                return 31;
+        }
+    }
+
+    /**
+     * Returns the length of the year represented by this date.
+     * <p>
+     * This returns the length of the year in days, either 365 or 366.
+     *
+     * @return 366 if the year is leap, 365 otherwise
+     */
+    @Override // override for Javadoc and performance
+    public int lengthOfYear() {
+        return (isLeapYear() ? 366 : 365);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns an adjusted copy of this date.
+     * <p>
+     * This returns a new {@code LocalDate}, 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.
+     * <p>
+     * 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.
+     * <p>
+     * For example this code returns a date on the last day of July:
+     * <pre>
+     *  import static java.time.Month.*;
+     *  import static java.time.temporal.Adjusters.*;
+     *
+     *  result = localDate.with(JULY).with(lastDayOfMonth());
+     * </pre>
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param adjuster the adjuster to use, not null
+     * @return a {@code LocalDate} 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 LocalDate with(TemporalAdjuster adjuster) {
+        // optimizations
+        if (adjuster instanceof LocalDate) {
+            return (LocalDate) adjuster;
+        }
+        return (LocalDate) adjuster.adjustInto(this);
+    }
+
+    /**
+     * Returns a copy of this date with the specified field set to a new value.
+     * <p>
+     * This returns a new {@code LocalDate}, 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.
+     * <p>
+     * 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.
+     * <p>
+     * If the field is a {@link ChronoField} then the adjustment is implemented here.
+     * The supported fields behave as follows:
+     * <ul>
+     * <li>{@code DAY_OF_WEEK} -
+     *  Returns a {@code LocalDate} with the specified day-of-week.
+     *  The date is adjusted up to 6 days forward or backward within the boundary
+     *  of a Monday to Sunday week.
+     * <li>{@code ALIGNED_DAY_OF_WEEK_IN_MONTH} -
+     *  Returns a {@code LocalDate} with the specified aligned-day-of-week.
+     *  The date is adjusted to the specified month-based aligned-day-of-week.
+     *  Aligned weeks are counted such that the first week of a given month starts
+     *  on the first day of that month.
+     *  This may cause the date to be moved up to 6 days into the following month.
+     * <li>{@code ALIGNED_DAY_OF_WEEK_IN_YEAR} -
+     *  Returns a {@code LocalDate} with the specified aligned-day-of-week.
+     *  The date is adjusted to the specified year-based aligned-day-of-week.
+     *  Aligned weeks are counted such that the first week of a given year starts
+     *  on the first day of that year.
+     *  This may cause the date to be moved up to 6 days into the following year.
+     * <li>{@code DAY_OF_MONTH} -
+     *  Returns a {@code LocalDate} with the specified day-of-month.
+     *  The month and year will be unchanged. If the day-of-month is invalid for the
+     *  year and month, then a {@code DateTimeException} is thrown.
+     * <li>{@code DAY_OF_YEAR} -
+     *  Returns a {@code LocalDate} with the specified day-of-year.
+     *  The year will be unchanged. If the day-of-year is invalid for the
+     *  year, then a {@code DateTimeException} is thrown.
+     * <li>{@code EPOCH_DAY} -
+     *  Returns a {@code LocalDate} with the specified epoch-day.
+     *  This completely replaces the date and is equivalent to {@link #ofEpochDay(long)}.
+     * <li>{@code ALIGNED_WEEK_OF_MONTH} -
+     *  Returns a {@code LocalDate} with the specified aligned-week-of-month.
+     *  Aligned weeks are counted such that the first week of a given month starts
+     *  on the first day of that month.
+     *  This adjustment moves the date in whole week chunks to match the specified week.
+     *  The result will have the same day-of-week as this date.
+     *  This may cause the date to be moved into the following month.
+     * <li>{@code ALIGNED_WEEK_OF_YEAR} -
+     *  Returns a {@code LocalDate} with the specified aligned-week-of-year.
+     *  Aligned weeks are counted such that the first week of a given year starts
+     *  on the first day of that year.
+     *  This adjustment moves the date in whole week chunks to match the specified week.
+     *  The result will have the same day-of-week as this date.
+     *  This may cause the date to be moved into the following year.
+     * <li>{@code MONTH_OF_YEAR} -
+     *  Returns a {@code LocalDate} with the specified month-of-year.
+     *  The year will be unchanged. The day-of-month will also be unchanged,
+     *  unless it would be invalid for the new month and year. In that case, the
+     *  day-of-month is adjusted to the maximum valid value for the new month and year.
+     * <li>{@code EPOCH_MONTH} -
+     *  Returns a {@code LocalDate} with the specified epoch-month.
+     *  The day-of-month will be unchanged, unless it would be invalid for the new month
+     *  and year. In that case, the day-of-month is adjusted to the maximum valid value
+     *  for the new month and year.
+     * <li>{@code YEAR_OF_ERA} -
+     *  Returns a {@code LocalDate} with the specified year-of-era.
+     *  The era and month will be unchanged. The day-of-month will also be unchanged,
+     *  unless it would be invalid for the new month and year. In that case, the
+     *  day-of-month is adjusted to the maximum valid value for the new month and year.
+     * <li>{@code YEAR} -
+     *  Returns a {@code LocalDate} with the specified year.
+     *  The month will be unchanged. The day-of-month will also be unchanged,
+     *  unless it would be invalid for the new month and year. In that case, the
+     *  day-of-month is adjusted to the maximum valid value for the new month and year.
+     * <li>{@code ERA} -
+     *  Returns a {@code LocalDate} with the specified era.
+     *  The year-of-era and month will be unchanged. The day-of-month will also be unchanged,
+     *  unless it would be invalid for the new month and year. In that case, the
+     *  day-of-month is adjusted to the maximum valid value for the new month and year.
+     * </ul>
+     * <p>
+     * In all cases, if the new value is outside the valid range of values for the field
+     * then a {@code DateTimeException} will be thrown.
+     * <p>
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param field  the field to set in the result, not null
+     * @param newValue  the new value of the field in the result
+     * @return a {@code LocalDate} 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 LocalDate with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            f.checkValidValue(newValue);
+            switch (f) {
+                case DAY_OF_WEEK: return plusDays(newValue - getDayOfWeek().getValue());
+                case ALIGNED_DAY_OF_WEEK_IN_MONTH: return plusDays(newValue - getLong(ALIGNED_DAY_OF_WEEK_IN_MONTH));
+                case ALIGNED_DAY_OF_WEEK_IN_YEAR: return plusDays(newValue - getLong(ALIGNED_DAY_OF_WEEK_IN_YEAR));
+                case DAY_OF_MONTH: return withDayOfMonth((int) newValue);
+                case DAY_OF_YEAR: return withDayOfYear((int) newValue);
+                case EPOCH_DAY: return LocalDate.ofEpochDay(newValue);
+                case ALIGNED_WEEK_OF_MONTH: return plusWeeks(newValue - getLong(ALIGNED_WEEK_OF_MONTH));
+                case ALIGNED_WEEK_OF_YEAR: return plusWeeks(newValue - getLong(ALIGNED_WEEK_OF_YEAR));
+                case MONTH_OF_YEAR: return withMonth((int) newValue);
+                case EPOCH_MONTH: return plusMonths(newValue - getLong(EPOCH_MONTH));
+                case YEAR_OF_ERA: return withYear((int) (year >= 1 ? newValue : 1 - newValue));
+                case YEAR: return withYear((int) newValue);
+                case ERA: return (getLong(ERA) == newValue ? this : withYear(1 - year));
+            }
+            throw new DateTimeException("Unsupported field: " + field.getName());
+        }
+        return field.doWith(this, newValue);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this date with the year altered.
+     * If the day-of-month is invalid for the year, it will be changed to the last valid day of the month.
+     * <p>
+     * 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 a {@code LocalDate} based on this date with the requested year, not null
+     * @throws DateTimeException if the year value is invalid
+     */
+    public LocalDate withYear(int year) {
+        if (this.year == year) {
+            return this;
+        }
+        YEAR.checkValidValue(year);
+        return resolvePreviousValid(year, month, day);
+    }
+
+    /**
+     * Returns a copy of this date with the month-of-year altered.
+     * If the day-of-month is invalid for the year, it will be changed to the last valid day of the month.
+     * <p>
+     * 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 a {@code LocalDate} based on this date with the requested month, not null
+     * @throws DateTimeException if the month-of-year value is invalid
+     */
+    public LocalDate withMonth(int month) {
+        if (this.month == month) {
+            return this;
+        }
+        MONTH_OF_YEAR.checkValidValue(month);
+        return resolvePreviousValid(year, month, day);
+    }
+
+    /**
+     * Returns a copy of this date with the day-of-month altered.
+     * If the resulting date is invalid, an exception is thrown.
+     * <p>
+     * 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 a {@code LocalDate} 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 LocalDate withDayOfMonth(int dayOfMonth) {
+        if (this.day == dayOfMonth) {
+            return this;
+        }
+        return of(year, month, dayOfMonth);
+    }
+
+    /**
+     * Returns a copy of this date with the day-of-year altered.
+     * If the resulting date is invalid, an exception is thrown.
+     * <p>
+     * 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 a {@code LocalDate} 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 LocalDate withDayOfYear(int dayOfYear) {
+        if (this.getDayOfYear() == dayOfYear) {
+            return this;
+        }
+        return ofYearDay(year, dayOfYear);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this date with the specified period added.
+     * <p>
+     * This method returns a new date based on this date with the specified period added.
+     * The adder is typically {@link 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)}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param adder  the adder to use, not null
+     * @return a {@code LocalDate} 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 LocalDate plus(TemporalAdder adder) {
+        return (LocalDate) adder.addTo(this);
+    }
+
+    /**
+     * Returns a copy of this date with the specified period added.
+     * <p>
+     * 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.
+     * <p>
+     * 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 a {@code LocalDate} based on this date with the specified period added, not null
+     * @throws DateTimeException if the unit cannot be added to this type
+     */
+    @Override
+    public LocalDate plus(long amountToAdd, TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            ChronoUnit f = (ChronoUnit) unit;
+            switch (f) {
+                case DAYS: return plusDays(amountToAdd);
+                case WEEKS: return plusWeeks(amountToAdd);
+                case MONTHS: return plusMonths(amountToAdd);
+                case YEARS: return plusYears(amountToAdd);
+                case DECADES: return plusYears(Math.multiplyExact(amountToAdd, 10));
+                case CENTURIES: return plusYears(Math.multiplyExact(amountToAdd, 100));
+                case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000));
+                case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd));
+            }
+            throw new DateTimeException("Unsupported unit: " + unit.getName());
+        }
+        return unit.doPlus(this, amountToAdd);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code LocalDate} with the specified period in years added.
+     * <p>
+     * This method adds the specified amount to the years field in three steps:
+     * <ol>
+     * <li>Add the input years to the year field</li>
+     * <li>Check if the resulting date would be invalid</li>
+     * <li>Adjust the day-of-month to the last valid day if necessary</li>
+     * </ol>
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param yearsToAdd  the years to add, may be negative
+     * @return a {@code LocalDate} based on this date with the years added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDate plusYears(long yearsToAdd) {
+        if (yearsToAdd == 0) {
+            return this;
+        }
+        int newYear = YEAR.checkValidIntValue(year + yearsToAdd);  // safe overflow
+        return resolvePreviousValid(newYear, month, day);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDate} with the specified period in months added.
+     * <p>
+     * This method adds the specified amount to the months field in three steps:
+     * <ol>
+     * <li>Add the input months to the month-of-year field</li>
+     * <li>Check if the resulting date would be invalid</li>
+     * <li>Adjust the day-of-month to the last valid day if necessary</li>
+     * </ol>
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param monthsToAdd  the months to add, may be negative
+     * @return a {@code LocalDate} based on this date with the months added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDate plusMonths(long monthsToAdd) {
+        if (monthsToAdd == 0) {
+            return this;
+        }
+        long monthCount = year * 12L + (month - 1);
+        long calcMonths = monthCount + monthsToAdd;  // safe overflow
+        int newYear = YEAR.checkValidIntValue(Math.floorDiv(calcMonths, 12));
+        int newMonth = (int)Math.floorMod(calcMonths, 12) + 1;
+        return resolvePreviousValid(newYear, newMonth, day);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDate} with the specified period in weeks added.
+     * <p>
+     * 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.
+     * <p>
+     * For example, 2008-12-31 plus one week would result in 2009-01-07.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param weeksToAdd  the weeks to add, may be negative
+     * @return a {@code LocalDate} based on this date with the weeks added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDate plusWeeks(long weeksToAdd) {
+        return plusDays(Math.multiplyExact(weeksToAdd, 7));
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDate} with the specified number of days added.
+     * <p>
+     * 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.
+     * <p>
+     * For example, 2008-12-31 plus one day would result in 2009-01-01.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param daysToAdd  the days to add, may be negative
+     * @return a {@code LocalDate} based on this date with the days added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDate plusDays(long daysToAdd) {
+        if (daysToAdd == 0) {
+            return this;
+        }
+        long mjDay = Math.addExact(toEpochDay(), daysToAdd);
+        return LocalDate.ofEpochDay(mjDay);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this date with the specified period subtracted.
+     * <p>
+     * This method returns a new date based on this date with the specified period subtracted.
+     * The subtractor is typically {@link 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)}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param subtractor  the subtractor to use, not null
+     * @return a {@code LocalDate} 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 LocalDate minus(TemporalSubtractor subtractor) {
+        return (LocalDate) subtractor.subtractFrom(this);
+    }
+
+    /**
+     * Returns a copy of this date with the specified period subtracted.
+     * <p>
+     * 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.
+     * <p>
+     * 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 a {@code LocalDate} based on this date with the specified period subtracted, not null
+     * @throws DateTimeException if the unit cannot be added to this type
+     */
+    @Override
+    public LocalDate 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 LocalDate} with the specified period in years subtracted.
+     * <p>
+     * This method subtracts the specified amount from the years field in three steps:
+     * <ol>
+     * <li>Subtract the input years to the year field</li>
+     * <li>Check if the resulting date would be invalid</li>
+     * <li>Adjust the day-of-month to the last valid day if necessary</li>
+     * </ol>
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param yearsToSubtract  the years to subtract, may be negative
+     * @return a {@code LocalDate} based on this date with the years subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDate minusYears(long yearsToSubtract) {
+        return (yearsToSubtract == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-yearsToSubtract));
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDate} with the specified period in months subtracted.
+     * <p>
+     * This method subtracts the specified amount from the months field in three steps:
+     * <ol>
+     * <li>Subtract the input months to the month-of-year field</li>
+     * <li>Check if the resulting date would be invalid</li>
+     * <li>Adjust the day-of-month to the last valid day if necessary</li>
+     * </ol>
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param monthsToSubtract  the months to subtract, may be negative
+     * @return a {@code LocalDate} based on this date with the months subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDate minusMonths(long monthsToSubtract) {
+        return (monthsToSubtract == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-monthsToSubtract));
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDate} with the specified period in weeks subtracted.
+     * <p>
+     * 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.
+     * <p>
+     * For example, 2009-01-07 minus one week would result in 2008-12-31.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param weeksToSubtract  the weeks to subtract, may be negative
+     * @return a {@code LocalDate} based on this date with the weeks subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDate minusWeeks(long weeksToSubtract) {
+        return (weeksToSubtract == Long.MIN_VALUE ? plusWeeks(Long.MAX_VALUE).plusWeeks(1) : plusWeeks(-weeksToSubtract));
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDate} with the specified number of days subtracted.
+     * <p>
+     * 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.
+     * <p>
+     * For example, 2009-01-01 minus one day would result in 2008-12-31.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param daysToSubtract  the days to subtract, may be negative
+     * @return a {@code LocalDate} based on this date with the days subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDate minusDays(long daysToSubtract) {
+        return (daysToSubtract == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-daysToSubtract));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this date using the specified query.
+     * <p>
+     * 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.
+     * <p>
+     * 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 <R> 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)
+     */
+    @Override  // override for Javadoc
+    public <R> R query(TemporalQuery<R> query) {
+        return ChronoLocalDate.super.query(query);
+    }
+
+    /**
+     * Adjusts the specified temporal object to have the same date as this object.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with the date changed to be the same as this.
+     * <p>
+     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+     * passing {@link ChronoField#EPOCH_DAY} as the field.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisLocalDate.adjustInto(temporal);
+     *   temporal = temporal.with(thisLocalDate);
+     * </pre>
+     * <p>
+     * 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  // override for Javadoc
+    public Temporal adjustInto(Temporal temporal) {
+        return ChronoLocalDate.super.adjustInto(temporal);
+    }
+
+    /**
+     * Calculates the period between this date and another date in
+     * terms of the specified unit.
+     * <p>
+     * This calculates the period between two dates in terms of a single unit.
+     * The start and end points are {@code this} and the specified date.
+     * The result will be negative if the end is before the start.
+     * The {@code Temporal} passed to this method must be a {@code LocalDate}.
+     * For example, the period in days between two dates can be calculated
+     * using {@code startDate.periodUntil(endDate, DAYS)}.
+     * <p>
+     * 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-15 and 2012-08-14
+     * will only be one month as it is one day short of two months.
+     * <p>
+     * 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:
+     * <pre>
+     *   long period = start.periodUntil(end, MONTHS);   // this method
+     *   dateTime.plus(MONTHS.between(start, end));      // use in plus/minus
+     * </pre>
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param endDate  the end date, which must be a {@code LocalDate}, 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 LocalDate == false) {
+            Objects.requireNonNull(endDate, "endDate");
+            throw new DateTimeException("Unable to calculate period between objects of two different types");
+        }
+        LocalDate end = (LocalDate) endDate;
+        if (unit instanceof ChronoUnit) {
+            switch ((ChronoUnit) unit) {
+                case DAYS: return daysUntil(end);
+                case WEEKS: return daysUntil(end) / 7;
+                case MONTHS: return monthsUntil(end);
+                case YEARS: return monthsUntil(end) / 12;
+                case DECADES: return monthsUntil(end) / 120;
+                case CENTURIES: return monthsUntil(end) / 1200;
+                case MILLENNIA: return monthsUntil(end) / 12000;
+                case ERAS: return end.getLong(ERA) - getLong(ERA);
+            }
+            throw new DateTimeException("Unsupported unit: " + unit.getName());
+        }
+        return unit.between(this, endDate).getAmount();
+    }
+
+    long daysUntil(LocalDate end) {
+        return end.toEpochDay() - toEpochDay();  // no overflow
+    }
+
+    private long monthsUntil(LocalDate end) {
+        long packed1 = getEpochMonth() * 32L + getDayOfMonth();  // no overflow
+        long packed2 = end.getEpochMonth() * 32L + end.getDayOfMonth();  // no overflow
+        return (packed2 - packed1) / 32;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a local date-time formed from this date at the specified time.
+     * <p>
+     * This combines this date with the specified time to form a {@code LocalDateTime}.
+     * All possible combinations of date and time are valid.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param time  the time to combine with, not null
+     * @return the local date-time formed from this date and the specified time, not null
+     */
+    @Override
+    public LocalDateTime atTime(LocalTime time) {
+        return LocalDateTime.of(this, time);
+    }
+
+    /**
+     * Returns a local date-time formed from this date at the specified time.
+     * <p>
+     * This combines this date with the specified time to form a {@code LocalDateTime}.
+     * The individual time fields must be within their valid range.
+     * All possible combinations of date and time are valid.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hour  the hour-of-day to use, from 0 to 23
+     * @param minute  the minute-of-hour to use, from 0 to 59
+     * @return the local date-time formed from this date and the specified time, not null
+     * @throws DateTimeException if the value of any field is out of range
+     */
+    public LocalDateTime atTime(int hour, int minute) {
+        return atTime(LocalTime.of(hour, minute));
+    }
+
+    /**
+     * Returns a local date-time formed from this date at the specified time.
+     * <p>
+     * This combines this date with the specified time to form a {@code LocalDateTime}.
+     * The individual time fields must be within their valid range.
+     * All possible combinations of date and time are valid.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hour  the hour-of-day to use, from 0 to 23
+     * @param minute  the minute-of-hour to use, from 0 to 59
+     * @param second  the second-of-minute to represent, from 0 to 59
+     * @return the local date-time formed from this date and the specified time, not null
+     * @throws DateTimeException if the value of any field is out of range
+     */
+    public LocalDateTime atTime(int hour, int minute, int second) {
+        return atTime(LocalTime.of(hour, minute, second));
+    }
+
+    /**
+     * Returns a local date-time formed from this date at the specified time.
+     * <p>
+     * This combines this date with the specified time to form a {@code LocalDateTime}.
+     * The individual time fields must be within their valid range.
+     * All possible combinations of date and time are valid.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hour  the hour-of-day to use, from 0 to 23
+     * @param minute  the minute-of-hour to use, from 0 to 59
+     * @param second  the second-of-minute to represent, from 0 to 59
+     * @param nanoOfSecond  the nano-of-second to represent, from 0 to 999,999,999
+     * @return the local date-time formed from this date and the specified time, not null
+     * @throws DateTimeException if the value of any field is out of range
+     */
+    public LocalDateTime atTime(int hour, int minute, int second, int nanoOfSecond) {
+        return atTime(LocalTime.of(hour, minute, second, nanoOfSecond));
+    }
+
+    /**
+     * Returns an offset date formed from this date and the specified offset.
+     * <p>
+     * This combines this date with the specified offset to form an {@code OffsetDate}.
+     * All possible combinations of date and offset are valid.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param offset  the offset to combine with, not null
+     * @return the offset date formed from this date and the specified offset, not null
+     */
+    public OffsetDate atOffset(ZoneOffset offset) {
+        return OffsetDate.of(this, offset);
+    }
+
+    /**
+     * Returns a zoned date-time from this date at the earliest valid time according
+     * to the rules in the time-zone.
+     * <p>
+     * Time-zone rules, such as daylight savings, mean that not every local date-time
+     * is valid for the specified zone, thus the local date-time may not be midnight.
+     * <p>
+     * In most cases, there is only one valid offset for a local date-time.
+     * In the case of an overlap, there are two valid offsets, and the earlier one is used,
+     * corresponding to the first occurrence of midnight on the date.
+     * In the case of a gap, the zoned date-time will represent the instant just after the gap.
+     * <p>
+     * If the zone ID is a {@link ZoneOffset}, then the result always has a time of midnight.
+     * <p>
+     * To convert to a specific time in a given time-zone call {@link #atTime(LocalTime)}
+     * followed by {@link LocalDateTime#atZone(ZoneId)}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param zone  the zone ID to use, not null
+     * @return the zoned date-time formed from this date and the earliest valid time for the zone, not null
+     */
+    public ZonedDateTime atStartOfDay(ZoneId zone) {
+        Objects.requireNonNull(zone, "zone");
+        // need to handle case where there is a gap from 11:30 to 00:30
+        // standard ZDT factory would result in 01:00 rather than 00:30
+        LocalDateTime ldt = atTime(LocalTime.MIDNIGHT);
+        if (zone instanceof ZoneOffset == false) {
+            ZoneRules rules = zone.getRules();
+            ZoneOffsetTransition trans = rules.getTransition(ldt);
+            if (trans != null && trans.isGap()) {
+                ldt = trans.getDateTimeAfter();
+            }
+        }
+        return ZonedDateTime.of(ldt, zone);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public long toEpochDay() {
+        long y = year;
+        long m = month;
+        long total = 0;
+        total += 365 * y;
+        if (y >= 0) {
+            total += (y + 3) / 4 - (y + 99) / 100 + (y + 399) / 400;
+        } else {
+            total -= y / -4 - y / -100 + y / -400;
+        }
+        total += ((367 * m - 362) / 12);
+        total += day - 1;
+        if (m > 2) {
+            total--;
+            if (isLeapYear() == false) {
+                total--;
+            }
+        }
+        return total - DAYS_0000_TO_1970;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this date to another date.
+     * <p>
+     * The comparison is primarily based on the date, from earliest to latest.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     * <p>
+     * If all the dates being compared are instances of {@code LocalDate},
+     * then the comparison will be entirely based on the date.
+     * If some dates being compared are in different chronologies, then the
+     * chronology is also considered, see {@link java.time.temporal.ChronoLocalDate#compareTo}.
+     *
+     * @param other  the other date to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     */
+    @Override  // override for Javadoc and performance
+    public int compareTo(ChronoLocalDate<?> other) {
+        if (other instanceof LocalDate) {
+            return compareTo0((LocalDate) other);
+        }
+        return ChronoLocalDate.super.compareTo(other);
+    }
+
+    int compareTo0(LocalDate otherDate) {
+        int cmp = (year - otherDate.year);
+        if (cmp == 0) {
+            cmp = (month - otherDate.month);
+            if (cmp == 0) {
+                cmp = (day - otherDate.day);
+            }
+        }
+        return cmp;
+    }
+
+    /**
+     * Checks if this date is after the specified date.
+     * <p>
+     * This checks to see if this date represents a point on the
+     * local time-line after the other date.
+     * <pre>
+     *   LocalDate a = LocalDate.of(2012, 6, 30);
+     *   LocalDate b = LocalDate.of(2012, 7, 1);
+     *   a.isAfter(b) == false
+     *   a.isAfter(a) == false
+     *   b.isAfter(a) == true
+     * </pre>
+     * <p>
+     * This method only considers the position of the two dates on the local time-line.
+     * It does not take into account the chronology, or calendar system.
+     * This is different from the comparison in {@link #compareTo(ChronoLocalDate)},
+     * but is the same approach as {@link #DATE_COMPARATOR}.
+     *
+     * @param other  the other date to compare to, not null
+     * @return true if this date is after the specified date
+     */
+    @Override  // override for Javadoc and performance
+    public boolean isAfter(ChronoLocalDate<?> other) {
+        if (other instanceof LocalDate) {
+            return compareTo0((LocalDate) other) > 0;
+        }
+        return ChronoLocalDate.super.isAfter(other);
+    }
+
+    /**
+     * Checks if this date is before the specified date.
+     * <p>
+     * This checks to see if this date represents a point on the
+     * local time-line before the other date.
+     * <pre>
+     *   LocalDate a = LocalDate.of(2012, 6, 30);
+     *   LocalDate b = LocalDate.of(2012, 7, 1);
+     *   a.isBefore(b) == true
+     *   a.isBefore(a) == false
+     *   b.isBefore(a) == false
+     * </pre>
+     * <p>
+     * This method only considers the position of the two dates on the local time-line.
+     * It does not take into account the chronology, or calendar system.
+     * This is different from the comparison in {@link #compareTo(ChronoLocalDate)},
+     * but is the same approach as {@link #DATE_COMPARATOR}.
+     *
+     * @param other  the other date to compare to, not null
+     * @return true if this date is before the specified date
+     */
+    @Override  // override for Javadoc and performance
+    public boolean isBefore(ChronoLocalDate<?> other) {
+        if (other instanceof LocalDate) {
+            return compareTo0((LocalDate) other) < 0;
+        }
+        return ChronoLocalDate.super.isBefore(other);
+    }
+
+    /**
+     * Checks if this date is equal to the specified date.
+     * <p>
+     * This checks to see if this date represents the same point on the
+     * local time-line as the other date.
+     * <pre>
+     *   LocalDate a = LocalDate.of(2012, 6, 30);
+     *   LocalDate b = LocalDate.of(2012, 7, 1);
+     *   a.isEqual(b) == false
+     *   a.isEqual(a) == true
+     *   b.isEqual(a) == false
+     * </pre>
+     * <p>
+     * This method only considers the position of the two dates on the local time-line.
+     * It does not take into account the chronology, or calendar system.
+     * This is different from the comparison in {@link #compareTo(ChronoLocalDate)}
+     * but is the same approach as {@link #DATE_COMPARATOR}.
+     *
+     * @param other  the other date to compare to, not null
+     * @return true if this date is equal to the specified date
+     */
+    @Override  // override for Javadoc and performance
+    public boolean isEqual(ChronoLocalDate<?> other) {
+        if (other instanceof LocalDate) {
+            return compareTo0((LocalDate) other) == 0;
+        }
+        return ChronoLocalDate.super.isEqual(other);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this date is equal to another date.
+     * <p>
+     * Compares this {@code LocalDate} with another ensuring that the date is the same.
+     * <p>
+     * Only objects of type {@code LocalDate} are compared, other types return false.
+     * To compare the dates of two {@code TemporalAccessor} instances, including dates
+     * in two different chronologies, use {@link ChronoField#EPOCH_DAY} as a comparator.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other date
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof LocalDate) {
+            return compareTo0((LocalDate) obj) == 0;
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this date.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        int yearValue = year;
+        int monthValue = month;
+        int dayValue = day;
+        return (yearValue & 0xFFFFF800) ^ ((yearValue << 11) + (monthValue << 6) + (dayValue));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this date as a {@code String}, such as {@code 2007-12-03}.
+     * <p>
+     * The output will be in the ISO-8601 format {@code yyyy-MM-dd}.
+     *
+     * @return a string representation of this date, not null
+     */
+    @Override
+    public String toString() {
+        int yearValue = year;
+        int monthValue = month;
+        int dayValue = day;
+        int absYear = Math.abs(yearValue);
+        StringBuilder buf = new StringBuilder(10);
+        if (absYear < 1000) {
+            if (yearValue < 0) {
+                buf.append(yearValue - 10000).deleteCharAt(1);
+            } else {
+                buf.append(yearValue + 10000).deleteCharAt(0);
+            }
+        } else {
+            if (yearValue > 9999) {
+                buf.append('+');
+            }
+            buf.append(yearValue);
+        }
+        return buf.append(monthValue < 10 ? "-0" : "-")
+            .append(monthValue)
+            .append(dayValue < 10 ? "-0" : "-")
+            .append(dayValue)
+            .toString();
+    }
+
+    /**
+     * Outputs this date as a {@code String} using the formatter.
+     * <p>
+     * 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
+     */
+    @Override  // override for Javadoc
+    public String toString(DateTimeFormatter formatter) {
+        return ChronoLocalDate.super.toString(formatter);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * <pre>
+     *  out.writeByte(3);  // identifies this as a LocalDate
+     *  out.writeInt(year);
+     *  out.writeByte(month);
+     *  out.writeByte(day);
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.LOCAL_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(DataOutput out) throws IOException {
+        out.writeInt(year);
+        out.writeByte(month);
+        out.writeByte(day);
+    }
+
+    static LocalDate readExternal(DataInput in) throws IOException {
+        int year = in.readInt();
+        int month = in.readByte();
+        int dayOfMonth = in.readByte();
+        return LocalDate.of(year, month, dayOfMonth);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/LocalDateTime.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,1860 @@
+/*
+ * 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;
+
+import static java.time.LocalTime.HOURS_PER_DAY;
+import static java.time.LocalTime.MICROS_PER_DAY;
+import static java.time.LocalTime.MILLIS_PER_DAY;
+import static java.time.LocalTime.MINUTES_PER_DAY;
+import static java.time.LocalTime.NANOS_PER_DAY;
+import static java.time.LocalTime.NANOS_PER_HOUR;
+import static java.time.LocalTime.NANOS_PER_MINUTE;
+import static java.time.LocalTime.NANOS_PER_SECOND;
+import static java.time.LocalTime.SECONDS_PER_DAY;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatters;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoLocalDateTime;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.ISOChrono;
+import java.time.temporal.OffsetDateTime;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdder;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.TemporalSubtractor;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.ValueRange;
+import java.time.zone.ZoneRules;
+import java.util.Objects;
+
+/**
+ * A date-time without a time-zone in the ISO-8601 calendar system,
+ * such as {@code 2007-12-03T10:15:30}.
+ * <p>
+ * {@code LocalDateTime} is an immutable date-time object that represents a date-time,
+ * often viewed as year-month-day-hour-minute-second. Other date and time fields,
+ * such as day-of-year, day-of-week and week-of-year, can also be accessed.
+ * Time is represented to nanosecond precision.
+ * For example, the value "2nd October 2007 at 13:45.30.123456789" can be
+ * stored in a {@code LocalDateTime}.
+ * <p>
+ * This class does not store or represent a time-zone.
+ * Instead, it is a description of the date, as used for birthdays, combined with
+ * the local time as seen on a wall clock.
+ * It cannot represent an instant on the time-line without additional information
+ * such as an offset or time-zone.
+ * <p>
+ * The ISO-8601 calendar system is the modern civil calendar system used today
+ * in most of the world. It is equivalent to the proleptic Gregorian calendar
+ * system, in which today's rules for leap years are applied for all time.
+ * For most applications written today, the ISO-8601 rules are entirely suitable.
+ * However, any application that makes use of historical dates, and requires them
+ * to be accurate will find the ISO-8601 approach unsuitable.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class LocalDateTime
+        implements Temporal, TemporalAdjuster, ChronoLocalDateTime<ISOChrono>, Serializable {
+
+    /**
+     * The minimum supported {@code LocalDateTime}, '-999999999-01-01T00:00:00'.
+     * This is the local date-time of midnight at the start of the minimum date.
+     * This combines {@link LocalDate#MIN} and {@link LocalTime#MIN}.
+     * This could be used by an application as a "far past" date-time.
+     */
+    public static final LocalDateTime MIN = LocalDateTime.of(LocalDate.MIN, LocalTime.MIN);
+    /**
+     * The maximum supported {@code LocalDateTime}, '+999999999-12-31T23:59:59.999999999'.
+     * This is the local date-time just before midnight at the end of the maximum date.
+     * This combines {@link LocalDate#MAX} and {@link LocalTime#MAX}.
+     * This could be used by an application as a "far future" date-time.
+     */
+    public static final LocalDateTime MAX = LocalDateTime.of(LocalDate.MAX, LocalTime.MAX);
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 6207766400415563566L;
+
+    /**
+     * The date part.
+     */
+    private final LocalDate date;
+    /**
+     * The time part.
+     */
+    private final LocalTime time;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains the current date-time from the system clock in the default time-zone.
+     * <p>
+     * This will query the {@link Clock#systemDefaultZone() system clock} in the default
+     * time-zone to obtain the current date-time.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @return the current date-time using the system clock and default time-zone, not null
+     */
+    public static LocalDateTime now() {
+        return now(Clock.systemDefaultZone());
+    }
+
+    /**
+     * Obtains the current date-time from the system clock in the specified time-zone.
+     * <p>
+     * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date-time.
+     * Specifying the time-zone avoids dependence on the default time-zone.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @param zone  the zone ID to use, not null
+     * @return the current date-time using the system clock, not null
+     */
+    public static LocalDateTime now(ZoneId zone) {
+        return now(Clock.system(zone));
+    }
+
+    /**
+     * Obtains the current date-time from the specified clock.
+     * <p>
+     * This will query the specified clock to obtain the current date-time.
+     * Using this method allows the use of an alternate clock for testing.
+     * The alternate clock may be introduced using {@link Clock dependency injection}.
+     *
+     * @param clock  the clock to use, not null
+     * @return the current date-time, not null
+     */
+    public static LocalDateTime now(Clock clock) {
+        Objects.requireNonNull(clock, "clock");
+        final Instant now = clock.instant();  // called once
+        ZoneOffset offset = clock.getZone().getRules().getOffset(now);
+        return ofEpochSecond(now.getEpochSecond(), now.getNano(), offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code LocalDateTime} from year, month,
+     * day, hour and minute, setting the second and nanosecond to zero.
+     * <p>
+     * The day must be valid for the year and month, otherwise an exception will be thrown.
+     * The second and nanosecond fields will be set to zero.
+     *
+     * @param year  the year to represent, from MIN_YEAR to MAX_YEAR
+     * @param month  the month-of-year to represent, not null
+     * @param dayOfMonth  the day-of-month to represent, from 1 to 31
+     * @param hour  the hour-of-day to represent, from 0 to 23
+     * @param minute  the minute-of-hour to represent, from 0 to 59
+     * @return the local date-time, not null
+     * @throws DateTimeException if the value of any field is out of range
+     * @throws DateTimeException if the day-of-month is invalid for the month-year
+     */
+    public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute) {
+        LocalDate date = LocalDate.of(year, month, dayOfMonth);
+        LocalTime time = LocalTime.of(hour, minute);
+        return new LocalDateTime(date, time);
+    }
+
+    /**
+     * Obtains an instance of {@code LocalDateTime} from year, month,
+     * day, hour, minute and second, setting the nanosecond to zero.
+     * <p>
+     * The day must be valid for the year and month, otherwise an exception will be thrown.
+     * The nanosecond field will be set to zero.
+     *
+     * @param year  the year to represent, from MIN_YEAR to MAX_YEAR
+     * @param month  the month-of-year to represent, not null
+     * @param dayOfMonth  the day-of-month to represent, from 1 to 31
+     * @param hour  the hour-of-day to represent, from 0 to 23
+     * @param minute  the minute-of-hour to represent, from 0 to 59
+     * @param second  the second-of-minute to represent, from 0 to 59
+     * @return the local date-time, not null
+     * @throws DateTimeException if the value of any field is out of range
+     * @throws DateTimeException if the day-of-month is invalid for the month-year
+     */
+    public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute, int second) {
+        LocalDate date = LocalDate.of(year, month, dayOfMonth);
+        LocalTime time = LocalTime.of(hour, minute, second);
+        return new LocalDateTime(date, time);
+    }
+
+    /**
+     * Obtains an instance of {@code LocalDateTime} from year, month,
+     * day, hour, minute, second and nanosecond.
+     * <p>
+     * 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
+     * @param hour  the hour-of-day to represent, from 0 to 23
+     * @param minute  the minute-of-hour to represent, from 0 to 59
+     * @param second  the second-of-minute to represent, from 0 to 59
+     * @param nanoOfSecond  the nano-of-second to represent, from 0 to 999,999,999
+     * @return the local date-time, not null
+     * @throws DateTimeException if the value of any field is out of range
+     * @throws DateTimeException if the day-of-month is invalid for the month-year
+     */
+    public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond) {
+        LocalDate date = LocalDate.of(year, month, dayOfMonth);
+        LocalTime time = LocalTime.of(hour, minute, second, nanoOfSecond);
+        return new LocalDateTime(date, time);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code LocalDateTime} from year, month,
+     * day, hour and minute, setting the second and nanosecond to zero.
+     * <p>
+     * The day must be valid for the year and month, otherwise an exception will be thrown.
+     * The second and nanosecond fields will be set to zero.
+     *
+     * @param year  the year to represent, from MIN_YEAR to MAX_YEAR
+     * @param month  the month-of-year to represent, from 1 (January) to 12 (December)
+     * @param dayOfMonth  the day-of-month to represent, from 1 to 31
+     * @param hour  the hour-of-day to represent, from 0 to 23
+     * @param minute  the minute-of-hour to represent, from 0 to 59
+     * @return the local date-time, not null
+     * @throws DateTimeException if the value of any field is out of range
+     * @throws DateTimeException if the day-of-month is invalid for the month-year
+     */
+    public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute) {
+        LocalDate date = LocalDate.of(year, month, dayOfMonth);
+        LocalTime time = LocalTime.of(hour, minute);
+        return new LocalDateTime(date, time);
+    }
+
+    /**
+     * Obtains an instance of {@code LocalDateTime} from year, month,
+     * day, hour, minute and second, setting the nanosecond to zero.
+     * <p>
+     * The day must be valid for the year and month, otherwise an exception will be thrown.
+     * The nanosecond field will be set to zero.
+     *
+     * @param year  the year to represent, from MIN_YEAR to MAX_YEAR
+     * @param month  the month-of-year to represent, from 1 (January) to 12 (December)
+     * @param dayOfMonth  the day-of-month to represent, from 1 to 31
+     * @param hour  the hour-of-day to represent, from 0 to 23
+     * @param minute  the minute-of-hour to represent, from 0 to 59
+     * @param second  the second-of-minute to represent, from 0 to 59
+     * @return the local date-time, not null
+     * @throws DateTimeException if the value of any field is out of range
+     * @throws DateTimeException if the day-of-month is invalid for the month-year
+     */
+    public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second) {
+        LocalDate date = LocalDate.of(year, month, dayOfMonth);
+        LocalTime time = LocalTime.of(hour, minute, second);
+        return new LocalDateTime(date, time);
+    }
+
+    /**
+     * Obtains an instance of {@code LocalDateTime} from year, month,
+     * day, hour, minute, second and nanosecond.
+     * <p>
+     * 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
+     * @param hour  the hour-of-day to represent, from 0 to 23
+     * @param minute  the minute-of-hour to represent, from 0 to 59
+     * @param second  the second-of-minute to represent, from 0 to 59
+     * @param nanoOfSecond  the nano-of-second to represent, from 0 to 999,999,999
+     * @return the local date-time, not null
+     * @throws DateTimeException if the value of any field is out of range
+     * @throws DateTimeException if the day-of-month is invalid for the month-year
+     */
+    public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond) {
+        LocalDate date = LocalDate.of(year, month, dayOfMonth);
+        LocalTime time = LocalTime.of(hour, minute, second, nanoOfSecond);
+        return new LocalDateTime(date, time);
+    }
+
+    /**
+     * Obtains an instance of {@code LocalDateTime} from a date and time.
+     *
+     * @param date  the local date, not null
+     * @param time  the local time, not null
+     * @return the local date-time, not null
+     */
+    public static LocalDateTime of(LocalDate date, LocalTime time) {
+        Objects.requireNonNull(date, "date");
+        Objects.requireNonNull(time, "time");
+        return new LocalDateTime(date, time);
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code LocalDateTime} from an {@code Instant} and zone ID.
+     * <p>
+     * This creates a local date-time based on the specified instant.
+     * First, the offset from UTC/Greenwich is obtained using the zone ID and instant,
+     * which is simple as there is only one valid offset for each instant.
+     * Then, the instant and offset are used to calculate the local date-time.
+     *
+     * @param instant  the instant to create the date-time from, not null
+     * @param zone  the time-zone, which may be an offset, not null
+     * @return the local date-time, not null
+     * @throws DateTimeException if the result exceeds the supported range
+     */
+    public static LocalDateTime ofInstant(Instant instant, ZoneId zone) {
+        Objects.requireNonNull(instant, "instant");
+        Objects.requireNonNull(zone, "zone");
+        ZoneRules rules = zone.getRules();
+        ZoneOffset offset = rules.getOffset(instant);
+        return ofEpochSecond(instant.getEpochSecond(), instant.getNano(), offset);
+    }
+
+    /**
+     * Obtains an instance of {@code LocalDateTime} using seconds from the
+     * epoch of 1970-01-01T00:00:00Z.
+     * <p>
+     * This allows the {@link ChronoField#INSTANT_SECONDS epoch-second} field
+     * to be converted to a local date-time. This is primarily intended for
+     * low-level conversions rather than general application usage.
+     *
+     * @param epochSecond  the number of seconds from the epoch of 1970-01-01T00:00:00Z
+     * @param nanoOfSecond  the nanosecond within the second, from 0 to 999,999,999
+     * @param offset  the zone offset, not null
+     * @return the local date-time, not null
+     * @throws DateTimeException if the result exceeds the supported range
+     */
+    public static LocalDateTime ofEpochSecond(long epochSecond, int nanoOfSecond, ZoneOffset offset) {
+        Objects.requireNonNull(offset, "offset");
+        long localSecond = epochSecond + offset.getTotalSeconds();  // overflow caught later
+        long localEpochDay = Math.floorDiv(localSecond, SECONDS_PER_DAY);
+        int secsOfDay = (int)Math.floorMod(localSecond, SECONDS_PER_DAY);
+        LocalDate date = LocalDate.ofEpochDay(localEpochDay);
+        LocalTime time = LocalTime.ofSecondOfDay(secsOfDay, nanoOfSecond);
+        return new LocalDateTime(date, time);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code LocalDateTime} from a temporal object.
+     * <p>
+     * A {@code TemporalAccessor} represents some form of date and time information.
+     * This factory converts the arbitrary temporal object to an instance of {@code LocalDateTime}.
+     * <p>
+     * The conversion extracts and combines {@code LocalDate} and {@code LocalTime}.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used as a query via method reference, {@code LocalDateTime::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the local date-time, not null
+     * @throws DateTimeException if unable to convert to a {@code LocalDateTime}
+     */
+    public static LocalDateTime from(TemporalAccessor temporal) {
+        if (temporal instanceof LocalDateTime) {
+            return (LocalDateTime) temporal;
+        } else if (temporal instanceof ZonedDateTime) {
+            return ((ZonedDateTime) temporal).getDateTime();
+        }
+        try {
+            LocalDate date = LocalDate.from(temporal);
+            LocalTime time = LocalTime.from(temporal);
+            return new LocalDateTime(date, time);
+        } catch (DateTimeException ex) {
+            throw new DateTimeException("Unable to obtain LocalDateTime from TemporalAccessor: " + temporal.getClass(), ex);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code LocalDateTime} from a text string such as {@code 2007-12-03T10:15:30}.
+     * <p>
+     * The string must represent a valid date-time and is parsed using
+     * {@link java.time.format.DateTimeFormatters#isoLocalDateTime()}.
+     *
+     * @param text  the text to parse such as "2007-12-03T10:15:30", not null
+     * @return the parsed local date-time, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static LocalDateTime parse(CharSequence text) {
+        return parse(text, DateTimeFormatters.isoLocalDateTime());
+    }
+
+    /**
+     * Obtains an instance of {@code LocalDateTime} from a text string using a specific formatter.
+     * <p>
+     * The text is parsed using the formatter, returning a date-time.
+     *
+     * @param text  the text to parse, not null
+     * @param formatter  the formatter to use, not null
+     * @return the parsed local date-time, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static LocalDateTime parse(CharSequence text, DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.parse(text, LocalDateTime::from);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructor.
+     *
+     * @param date  the date part of the date-time, validated not null
+     * @param time  the time part of the date-time, validated not null
+     */
+    private LocalDateTime(LocalDate date, LocalTime time) {
+        this.date = date;
+        this.time = time;
+    }
+
+    /**
+     * Returns a copy of this date-time with the new date and time, checking
+     * to see if a new object is in fact required.
+     *
+     * @param newDate  the date of the new date-time, not null
+     * @param newTime  the time of the new date-time, not null
+     * @return the date-time, not null
+     */
+    private LocalDateTime with(LocalDate newDate, LocalTime newTime) {
+        if (date == newDate && time == newTime) {
+            return this;
+        }
+        return new LocalDateTime(newDate, newTime);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if this date-time can be queried for the specified field.
+     * If false, then calling the {@link #range(TemporalField) range} and
+     * {@link #get(TemporalField) get} methods will throw an exception.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The supported fields are:
+     * <ul>
+     * <li>{@code NANO_OF_SECOND}
+     * <li>{@code NANO_OF_DAY}
+     * <li>{@code MICRO_OF_SECOND}
+     * <li>{@code MICRO_OF_DAY}
+     * <li>{@code MILLI_OF_SECOND}
+     * <li>{@code MILLI_OF_DAY}
+     * <li>{@code SECOND_OF_MINUTE}
+     * <li>{@code SECOND_OF_DAY}
+     * <li>{@code MINUTE_OF_HOUR}
+     * <li>{@code MINUTE_OF_DAY}
+     * <li>{@code HOUR_OF_AMPM}
+     * <li>{@code CLOCK_HOUR_OF_AMPM}
+     * <li>{@code HOUR_OF_DAY}
+     * <li>{@code CLOCK_HOUR_OF_DAY}
+     * <li>{@code AMPM_OF_DAY}
+     * <li>{@code DAY_OF_WEEK}
+     * <li>{@code ALIGNED_DAY_OF_WEEK_IN_MONTH}
+     * <li>{@code ALIGNED_DAY_OF_WEEK_IN_YEAR}
+     * <li>{@code DAY_OF_MONTH}
+     * <li>{@code DAY_OF_YEAR}
+     * <li>{@code EPOCH_DAY}
+     * <li>{@code ALIGNED_WEEK_OF_MONTH}
+     * <li>{@code ALIGNED_WEEK_OF_YEAR}
+     * <li>{@code MONTH_OF_YEAR}
+     * <li>{@code EPOCH_MONTH}
+     * <li>{@code YEAR_OF_ERA}
+     * <li>{@code YEAR}
+     * <li>{@code ERA}
+     * </ul>
+     * All other {@code ChronoField} instances will return false.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the field is supported is determined by the field.
+     *
+     * @param field  the field to check, null returns false
+     * @return true if the field is supported on this date-time, false if not
+     */
+    @Override
+    public boolean isSupported(TemporalField field) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            return f.isDateField() || f.isTimeField();
+        }
+        return field != null && field.doIsSupported(this);
+    }
+
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * The range object expresses the minimum and maximum valid values for a field.
+     * This date-time is used to enhance the accuracy of the returned range.
+     * If it is not possible to return the range, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * 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}.
+     * <p>
+     * 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) {
+            ChronoField f = (ChronoField) field;
+            return (f.isTimeField() ? time.range(field) : date.range(field));
+        }
+        return field.doRange(this);
+    }
+
+    /**
+     * Gets the value of the specified field from this date-time as an {@code int}.
+     * <p>
+     * This queries this date-time for the value for the specified field.
+     * The returned value will always be within the valid range of values for the field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this date-time, except {@code NANO_OF_DAY}, {@code MICRO_OF_DAY},
+     * {@code EPOCH_DAY} 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}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public int get(TemporalField field) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            return (f.isTimeField() ? time.get(field) : date.get(field));
+        }
+        return ChronoLocalDateTime.super.get(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this date-time as a {@code long}.
+     * <p>
+     * This queries this date-time for the value for the specified field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this date-time.
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * 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) {
+            ChronoField f = (ChronoField) field;
+            return (f.isTimeField() ? time.getLong(field) : date.getLong(field));
+        }
+        return field.doGet(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the {@code LocalDate} part of this date-time.
+     * <p>
+     * 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
+     */
+    @Override
+    public LocalDate getDate() {
+        return date;
+    }
+
+    /**
+     * Gets the year field.
+     * <p>
+     * This method returns the primitive {@code int} value for the year.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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}.
+     * <p>
+     * This method returns the enum {@link 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 DayOfWeek#getValue() int value}.
+     * <p>
+     * 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();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the {@code LocalTime} part of this date-time.
+     * <p>
+     * This returns a {@code LocalTime} with the same hour, minute, second and
+     * nanosecond as this date-time.
+     *
+     * @return the time part of this date-time, not null
+     */
+    @Override
+    public LocalTime getTime() {
+        return time;
+    }
+
+    /**
+     * Gets the hour-of-day field.
+     *
+     * @return the hour-of-day, from 0 to 23
+     */
+    public int getHour() {
+        return time.getHour();
+    }
+
+    /**
+     * Gets the minute-of-hour field.
+     *
+     * @return the minute-of-hour, from 0 to 59
+     */
+    public int getMinute() {
+        return time.getMinute();
+    }
+
+    /**
+     * Gets the second-of-minute field.
+     *
+     * @return the second-of-minute, from 0 to 59
+     */
+    public int getSecond() {
+        return time.getSecond();
+    }
+
+    /**
+     * Gets the nano-of-second field.
+     *
+     * @return the nano-of-second, from 0 to 999,999,999
+     */
+    public int getNano() {
+        return time.getNano();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns an adjusted copy of this date-time.
+     * <p>
+     * This returns a new {@code LocalDateTime}, based on this one, with the date-time adjusted.
+     * The adjustment takes place using the specified adjuster strategy object.
+     * Read the documentation of the adjuster to understand what adjustment will be made.
+     * <p>
+     * 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.
+     * <p>
+     * For example this code returns a date on the last day of July:
+     * <pre>
+     *  import static java.time.Month.*;
+     *  import static java.time.temporal.Adjusters.*;
+     *
+     *  result = localDateTime.with(JULY).with(lastDayOfMonth());
+     * </pre>
+     * <p>
+     * The classes {@link LocalDate} and {@link LocalTime} implement {@code TemporalAdjuster},
+     * thus this method can be used to change the date, time or offset:
+     * <pre>
+     *  result = localDateTime.with(date);
+     *  result = localDateTime.with(time);
+     * </pre>
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param adjuster the adjuster to use, not null
+     * @return a {@code LocalDateTime} 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 LocalDateTime with(TemporalAdjuster adjuster) {
+        // optimizations
+        if (adjuster instanceof LocalDate) {
+            return with((LocalDate) adjuster, time);
+        } else if (adjuster instanceof LocalTime) {
+            return with(date, (LocalTime) adjuster);
+        } else if (adjuster instanceof LocalDateTime) {
+            return (LocalDateTime) adjuster;
+        }
+        return (LocalDateTime) adjuster.adjustInto(this);
+    }
+
+    /**
+     * Returns a copy of this date-time with the specified field set to a new value.
+     * <p>
+     * This returns a new {@code LocalDateTime}, 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.
+     * <p>
+     * In some cases, changing the specified field can cause the resulting date-time to become invalid,
+     * such as changing the month from 31st January to February would make the day-of-month invalid.
+     * In cases like this, the field is responsible for resolving the date. Typically it will choose
+     * the previous valid date, which would be the last valid day of February in this example.
+     * <p>
+     * If the field is a {@link ChronoField} then the adjustment is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will behave as per
+     * the matching method on {@link LocalDate#with(TemporalField, long) LocalDate}
+     * or {@link LocalTime#with(TemporalField, long) LocalTime}.
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param field  the field to set in the result, not null
+     * @param newValue  the new value of the field in the result
+     * @return a {@code LocalDateTime} 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 LocalDateTime with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            if (f.isTimeField()) {
+                return with(date, time.with(field, newValue));
+            } else {
+                return with(date.with(field, newValue), time);
+            }
+        }
+        return field.doWith(this, newValue);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the year altered.
+     * The time 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.
+     * <p>
+     * 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 a {@code LocalDateTime} based on this date-time with the requested year, not null
+     * @throws DateTimeException if the year value is invalid
+     */
+    public LocalDateTime withYear(int year) {
+        return with(date.withYear(year), time);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the month-of-year altered.
+     * The time 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.
+     * <p>
+     * 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 a {@code LocalDateTime} based on this date-time with the requested month, not null
+     * @throws DateTimeException if the month-of-year value is invalid
+     */
+    public LocalDateTime withMonth(int month) {
+        return with(date.withMonth(month), time);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the day-of-month altered.
+     * If the resulting {@code LocalDateTime} is invalid, an exception is thrown.
+     * The time does not affect the calculation and will be the same in the result.
+     * <p>
+     * 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 a {@code LocalDateTime} based on this date-time with the requested day, not null
+     * @throws DateTimeException if the day-of-month value is invalid
+     * @throws DateTimeException if the day-of-month is invalid for the month-year
+     */
+    public LocalDateTime withDayOfMonth(int dayOfMonth) {
+        return with(date.withDayOfMonth(dayOfMonth), time);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the day-of-year altered.
+     * If the resulting {@code LocalDateTime} is invalid, an exception is thrown.
+     * <p>
+     * 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 a {@code LocalDateTime} 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 LocalDateTime withDayOfYear(int dayOfYear) {
+        return with(date.withDayOfYear(dayOfYear), time);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the hour-of-day value altered.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hour  the hour-of-day to set in the result, from 0 to 23
+     * @return a {@code LocalDateTime} based on this date-time with the requested hour, not null
+     * @throws DateTimeException if the hour value is invalid
+     */
+    public LocalDateTime withHour(int hour) {
+        LocalTime newTime = time.withHour(hour);
+        return with(date, newTime);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the minute-of-hour value altered.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minute  the minute-of-hour to set in the result, from 0 to 59
+     * @return a {@code LocalDateTime} based on this date-time with the requested minute, not null
+     * @throws DateTimeException if the minute value is invalid
+     */
+    public LocalDateTime withMinute(int minute) {
+        LocalTime newTime = time.withMinute(minute);
+        return with(date, newTime);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the second-of-minute value altered.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param second  the second-of-minute to set in the result, from 0 to 59
+     * @return a {@code LocalDateTime} based on this date-time with the requested second, not null
+     * @throws DateTimeException if the second value is invalid
+     */
+    public LocalDateTime withSecond(int second) {
+        LocalTime newTime = time.withSecond(second);
+        return with(date, newTime);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the nano-of-second value altered.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanoOfSecond  the nano-of-second to set in the result, from 0 to 999,999,999
+     * @return a {@code LocalDateTime} based on this date-time with the requested nanosecond, not null
+     * @throws DateTimeException if the nano value is invalid
+     */
+    public LocalDateTime withNano(int nanoOfSecond) {
+        LocalTime newTime = time.withNano(nanoOfSecond);
+        return with(date, newTime);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the time truncated.
+     * <p>
+     * Truncation returns a copy of the original date-time with fields
+     * smaller than the specified unit set to zero.
+     * For example, truncating with the {@link ChronoUnit#MINUTES minutes} unit
+     * will set the second-of-minute and nano-of-second field to zero.
+     * <p>
+     * Not all units are accepted. The {@link ChronoUnit#DAYS days} unit and time
+     * units with an exact duration can be used, other units throw an exception.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param unit  the unit to truncate to, not null
+     * @return a {@code LocalDateTime} based on this date-time with the time truncated, not null
+     * @throws DateTimeException if unable to truncate
+     */
+    public LocalDateTime truncatedTo(TemporalUnit unit) {
+        return with(date, time.truncatedTo(unit));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this date-time with the specified period added.
+     * <p>
+     * This method returns a new date-time based on this time with the specified period added.
+     * The adder is typically {@link 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)}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param adder  the adder to use, not null
+     * @return a {@code LocalDateTime} based on this date-time with the addition made, not null
+     * @throws DateTimeException if the addition cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public LocalDateTime plus(TemporalAdder adder) {
+        return (LocalDateTime) adder.addTo(this);
+    }
+
+    /**
+     * Returns a copy of this date-time with the specified period added.
+     * <p>
+     * This method returns a new date-time based on this date-time with the specified period added.
+     * This can be used to add any period that is defined by a unit, for example to add years, months or days.
+     * The unit is responsible for the details of the calculation, including the resolution
+     * of any edge cases in the calculation.
+     * <p>
+     * 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 a {@code LocalDateTime} based on this date-time with the specified period added, not null
+     * @throws DateTimeException if the unit cannot be added to this type
+     */
+    @Override
+    public LocalDateTime plus(long amountToAdd, TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            ChronoUnit f = (ChronoUnit) unit;
+            switch (f) {
+                case NANOS: return plusNanos(amountToAdd);
+                case MICROS: return plusDays(amountToAdd / MICROS_PER_DAY).plusNanos((amountToAdd % MICROS_PER_DAY) * 1000);
+                case MILLIS: return plusDays(amountToAdd / MILLIS_PER_DAY).plusNanos((amountToAdd % MILLIS_PER_DAY) * 1000_000);
+                case SECONDS: return plusSeconds(amountToAdd);
+                case MINUTES: return plusMinutes(amountToAdd);
+                case HOURS: return plusHours(amountToAdd);
+                case HALF_DAYS: return plusDays(amountToAdd / 256).plusHours((amountToAdd % 256) * 12);  // no overflow (256 is multiple of 2)
+            }
+            return with(date.plus(amountToAdd, unit), time);
+        }
+        return unit.doPlus(this, amountToAdd);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified period in years added.
+     * <p>
+     * This method adds the specified amount to the years field in three steps:
+     * <ol>
+     * <li>Add the input years to the year field</li>
+     * <li>Check if the resulting date would be invalid</li>
+     * <li>Adjust the day-of-month to the last valid day if necessary</li>
+     * </ol>
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param years  the years to add, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the years added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime plusYears(long years) {
+        LocalDate newDate = date.plusYears(years);
+        return with(newDate, time);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified period in months added.
+     * <p>
+     * This method adds the specified amount to the months field in three steps:
+     * <ol>
+     * <li>Add the input months to the month-of-year field</li>
+     * <li>Check if the resulting date would be invalid</li>
+     * <li>Adjust the day-of-month to the last valid day if necessary</li>
+     * </ol>
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param months  the months to add, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the months added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime plusMonths(long months) {
+        LocalDate newDate = date.plusMonths(months);
+        return with(newDate, time);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified period in weeks added.
+     * <p>
+     * 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.
+     * <p>
+     * For example, 2008-12-31 plus one week would result in 2009-01-07.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param weeks  the weeks to add, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the weeks added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime plusWeeks(long weeks) {
+        LocalDate newDate = date.plusWeeks(weeks);
+        return with(newDate, time);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified period in days added.
+     * <p>
+     * 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.
+     * <p>
+     * For example, 2008-12-31 plus one day would result in 2009-01-01.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param days  the days to add, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the days added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime plusDays(long days) {
+        LocalDate newDate = date.plusDays(days);
+        return with(newDate, time);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified period in hours added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hours  the hours to add, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the hours added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime plusHours(long hours) {
+        return plusWithOverflow(date, hours, 0, 0, 0, 1);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified period in minutes added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minutes  the minutes to add, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the minutes added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime plusMinutes(long minutes) {
+        return plusWithOverflow(date, 0, minutes, 0, 0, 1);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified period in seconds added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param seconds  the seconds to add, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the seconds added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime plusSeconds(long seconds) {
+        return plusWithOverflow(date, 0, 0, seconds, 0, 1);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified period in nanoseconds added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanos  the nanos to add, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the nanoseconds added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime plusNanos(long nanos) {
+        return plusWithOverflow(date, 0, 0, 0, nanos, 1);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this date-time with the specified period subtracted.
+     * <p>
+     * This method returns a new date-time based on this time with the specified period subtracted.
+     * The subtractor is typically {@link 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)}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param subtractor  the subtractor to use, not null
+     * @return a {@code LocalDateTime} based on this date-time with the subtraction made, not null
+     * @throws DateTimeException if the subtraction cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public LocalDateTime minus(TemporalSubtractor subtractor) {
+        return (LocalDateTime) subtractor.subtractFrom(this);
+    }
+
+    /**
+     * Returns a copy of this date-time with the specified period subtracted.
+     * <p>
+     * This method returns a new date-time based on this date-time with the specified period subtracted.
+     * This can be used to subtract any period that is defined by a unit, for example to subtract years, months or days.
+     * The unit is responsible for the details of the calculation, including the resolution
+     * of any edge cases in the calculation.
+     * <p>
+     * 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 a {@code LocalDateTime} based on this date-time with the specified period subtracted, not null
+     * @throws DateTimeException if the unit cannot be added to this type
+     */
+    @Override
+    public LocalDateTime 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 LocalDateTime} with the specified period in years subtracted.
+     * <p>
+     * This method subtracts the specified amount from the years field in three steps:
+     * <ol>
+     * <li>Subtract the input years from the year field</li>
+     * <li>Check if the resulting date would be invalid</li>
+     * <li>Adjust the day-of-month to the last valid day if necessary</li>
+     * </ol>
+     * <p>
+     * For example, 2008-02-29 (leap year) minus one year would result in the
+     * invalid date 2009-02-29 (standard year). Instead of returning an invalid
+     * result, the last valid day of the month, 2009-02-28, is selected instead.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param years  the years to subtract, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the years subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime minusYears(long years) {
+        return (years == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-years));
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified period in months subtracted.
+     * <p>
+     * This method subtracts the specified amount from the months field in three steps:
+     * <ol>
+     * <li>Subtract the input months from the month-of-year field</li>
+     * <li>Check if the resulting date would be invalid</li>
+     * <li>Adjust the day-of-month to the last valid day if necessary</li>
+     * </ol>
+     * <p>
+     * For example, 2007-03-31 minus one month would result in the invalid date
+     * 2007-04-31. Instead of returning an invalid result, the last valid day
+     * of the month, 2007-04-30, is selected instead.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param months  the months to subtract, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the months subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime minusMonths(long months) {
+        return (months == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-months));
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified period in weeks subtracted.
+     * <p>
+     * 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.
+     * <p>
+     * For example, 2009-01-07 minus one week would result in 2008-12-31.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param weeks  the weeks to subtract, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the weeks subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime minusWeeks(long weeks) {
+        return (weeks == Long.MIN_VALUE ? plusWeeks(Long.MAX_VALUE).plusWeeks(1) : plusWeeks(-weeks));
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified period in days subtracted.
+     * <p>
+     * This method subtracts the specified amount from the days field incrementing the
+     * month and year fields as necessary to ensure the result remains valid.
+     * The result is only invalid if the maximum/minimum year is exceeded.
+     * <p>
+     * For example, 2009-01-01 minus one day would result in 2008-12-31.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param days  the days to subtract, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the days subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime minusDays(long days) {
+        return (days == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-days));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified period in hours subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hours  the hours to subtract, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the hours subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime minusHours(long hours) {
+        return plusWithOverflow(date, hours, 0, 0, 0, -1);
+   }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified period in minutes subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minutes  the minutes to subtract, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the minutes subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime minusMinutes(long minutes) {
+        return plusWithOverflow(date, 0, minutes, 0, 0, -1);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified period in seconds subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param seconds  the seconds to subtract, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the seconds subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime minusSeconds(long seconds) {
+        return plusWithOverflow(date, 0, 0, seconds, 0, -1);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified period in nanoseconds subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanos  the nanos to subtract, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the nanoseconds subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime minusNanos(long nanos) {
+        return plusWithOverflow(date, 0, 0, 0, nanos, -1);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified period added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param newDate  the new date to base the calculation on, not null
+     * @param hours  the hours to add, may be negative
+     * @param minutes the minutes to add, may be negative
+     * @param seconds the seconds to add, may be negative
+     * @param nanos the nanos to add, may be negative
+     * @param sign  the sign to determine add or subtract
+     * @return the combined result, not null
+     */
+    private LocalDateTime plusWithOverflow(LocalDate newDate, long hours, long minutes, long seconds, long nanos, int sign) {
+        // 9223372036854775808 long, 2147483648 int
+        if ((hours | minutes | seconds | nanos) == 0) {
+            return with(newDate, time);
+        }
+        long totDays = nanos / NANOS_PER_DAY +             //   max/24*60*60*1B
+                seconds / SECONDS_PER_DAY +                //   max/24*60*60
+                minutes / MINUTES_PER_DAY +                //   max/24*60
+                hours / HOURS_PER_DAY;                     //   max/24
+        totDays *= sign;                                   // total max*0.4237...
+        long totNanos = nanos % NANOS_PER_DAY +                    //   max  86400000000000
+                (seconds % SECONDS_PER_DAY) * NANOS_PER_SECOND +   //   max  86400000000000
+                (minutes % MINUTES_PER_DAY) * NANOS_PER_MINUTE +   //   max  86400000000000
+                (hours % HOURS_PER_DAY) * NANOS_PER_HOUR;          //   max  86400000000000
+        long curNoD = time.toNanoOfDay();                       //   max  86400000000000
+        totNanos = totNanos * sign + curNoD;                    // total 432000000000000
+        totDays += Math.floorDiv(totNanos, NANOS_PER_DAY);
+        long newNoD = Math.floorMod(totNanos, NANOS_PER_DAY);
+        LocalTime newTime = (newNoD == curNoD ? time : LocalTime.ofNanoOfDay(newNoD));
+        return with(newDate.plusDays(totDays), newTime);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this date-time using the specified query.
+     * <p>
+     * This queries this date-time using the specified query strategy object.
+     * The {@code TemporalQuery} object defines the logic to be used to
+     * obtain the result. Read the documentation of the query to understand
+     * what the result of this method will be.
+     * <p>
+     * The result of this method is obtained by invoking the
+     * {@link java.time.temporal.TemporalQuery#queryFrom(TemporalAccessor)} method on the
+     * specified query passing {@code this} as the argument.
+     *
+     * @param <R> 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)
+     */
+    @Override  // override for Javadoc
+    public <R> R query(TemporalQuery<R> query) {
+        return ChronoLocalDateTime.super.query(query);
+    }
+
+    /**
+     * Adjusts the specified temporal object to have the same date and time as this object.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with the date and time changed to be the same as this.
+     * <p>
+     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+     * twice, passing {@link ChronoField#EPOCH_DAY} and
+     * {@link ChronoField#NANO_OF_DAY} as the fields.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisLocalDateTime.adjustInto(temporal);
+     *   temporal = temporal.with(thisLocalDateTime);
+     * </pre>
+     * <p>
+     * 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  // override for Javadoc
+    public Temporal adjustInto(Temporal temporal) {
+        return ChronoLocalDateTime.super.adjustInto(temporal);
+    }
+
+    /**
+     * Calculates the period between this date-time and another date-time in
+     * terms of the specified unit.
+     * <p>
+     * This calculates the period between two date-times in terms of a single unit.
+     * The start and end points are {@code this} and the specified date-time.
+     * The result will be negative if the end is before the start.
+     * The {@code Temporal} passed to this method must be a {@code LocalDateTime}.
+     * For example, the period in days between two date-times can be calculated
+     * using {@code startDateTime.periodUntil(endDateTime, DAYS)}.
+     * <p>
+     * The calculation returns a whole number, representing the number of
+     * complete units between the two date-times.
+     * For example, the period in months between 2012-06-15T00:00 and 2012-08-14T23:59
+     * will only be one month as it is one minute short of two months.
+     * <p>
+     * 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:
+     * <pre>
+     *   long period = start.periodUntil(end, MONTHS);   // this method
+     *   dateTime.plus(MONTHS.between(start, end));      // use in plus/minus
+     * </pre>
+     * <p>
+     * The calculation is implemented in this method for {@link ChronoUnit}.
+     * The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS},
+     * {@code MINUTES}, {@code HOURS} and {@code HALF_DAYS}, {@code DAYS},
+     * {@code WEEKS}, {@code MONTHS}, {@code YEARS}, {@code DECADES},
+     * {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS} are supported.
+     * Other {@code ChronoUnit} values will throw an exception.
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param endDateTime  the end date-time, which must be a {@code LocalDateTime}, not null
+     * @param unit  the unit to measure the period in, not null
+     * @return the amount of the period between this date-time and the end date-time
+     * @throws DateTimeException if the period cannot be calculated
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long periodUntil(Temporal endDateTime, TemporalUnit unit) {
+        if (endDateTime instanceof LocalDateTime == false) {
+            Objects.requireNonNull(endDateTime, "endDateTime");
+            throw new DateTimeException("Unable to calculate period between objects of two different types");
+        }
+        LocalDateTime end = (LocalDateTime) endDateTime;
+        if (unit instanceof ChronoUnit) {
+            ChronoUnit f = (ChronoUnit) unit;
+            if (f.isTimeUnit()) {
+                long amount = date.daysUntil(end.date);
+                switch (f) {
+                    case NANOS: amount = Math.multiplyExact(amount, NANOS_PER_DAY); break;
+                    case MICROS: amount = Math.multiplyExact(amount, MICROS_PER_DAY); break;
+                    case MILLIS: amount = Math.multiplyExact(amount, MILLIS_PER_DAY); break;
+                    case SECONDS: amount = Math.multiplyExact(amount, SECONDS_PER_DAY); break;
+                    case MINUTES: amount = Math.multiplyExact(amount, MINUTES_PER_DAY); break;
+                    case HOURS: amount = Math.multiplyExact(amount, HOURS_PER_DAY); break;
+                    case HALF_DAYS: amount = Math.multiplyExact(amount, 2); break;
+                }
+                return Math.addExact(amount, time.periodUntil(end.time, unit));
+            }
+            LocalDate endDate = end.date;
+            if (end.time.isBefore(time)) {
+                endDate = endDate.minusDays(1);
+            }
+            return date.periodUntil(endDate, unit);
+        }
+        return unit.between(this, endDateTime).getAmount();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns an offset date-time formed from this date-time and the specified offset.
+     * <p>
+     * This combines this date-time with the specified offset to form an {@code OffsetDateTime}.
+     * All possible combinations of date-time and offset are valid.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param offset  the offset to combine with, not null
+     * @return the offset date-time formed from this date-time and the specified offset, not null
+     */
+    public OffsetDateTime atOffset(ZoneOffset offset) {
+        return OffsetDateTime.of(this, offset);
+    }
+
+    /**
+     * Returns a zoned date-time formed from this date-time and the specified time-zone.
+     * <p>
+     * This creates a zoned date-time matching the input date-time as closely as possible.
+     * Time-zone rules, such as daylight savings, mean that not every local date-time
+     * is valid for the specified zone, thus the local date-time may be adjusted.
+     * <p>
+     * The local date-time is resolved to a single instant on the time-line.
+     * This is achieved by finding a valid offset from UTC/Greenwich for the local
+     * date-time as defined by the {@link ZoneRules rules} of the zone ID.
+     *<p>
+     * In most cases, there is only one valid offset for a local date-time.
+     * In the case of an overlap, where clocks are set back, there are two valid offsets.
+     * This method uses the earlier offset typically corresponding to "summer".
+     * <p>
+     * In the case of a gap, where clocks jump forward, there is no valid offset.
+     * Instead, the local date-time is adjusted to be later by the length of the gap.
+     * For a typical one hour daylight savings change, the local date-time will be
+     * moved one hour later into the offset typically corresponding to "summer".
+     * <p>
+     * To obtain the later offset during an overlap, call
+     * {@link ZonedDateTime#withLaterOffsetAtOverlap()} on the result of this method.
+     * To throw an exception when there is a gap or overlap, use
+     * {@link ZonedDateTime#ofStrict(LocalDateTime, ZoneOffset, ZoneId)}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param zone  the time-zone to use, not null
+     * @return the zoned date-time formed from this date-time, not null
+     */
+    @Override
+    public ZonedDateTime atZone(ZoneId zone) {
+        return ZonedDateTime.of(this, zone);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this date-time to another date-time.
+     * <p>
+     * The comparison is primarily based on the date-time, from earliest to latest.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     * <p>
+     * If all the date-times being compared are instances of {@code LocalDateTime},
+     * then the comparison will be entirely based on the date-time.
+     * If some dates being compared are in different chronologies, then the
+     * chronology is also considered, see {@link ChronoLocalDateTime#compareTo}.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     */
+    @Override  // override for Javadoc and performance
+    public int compareTo(ChronoLocalDateTime<?> other) {
+        if (other instanceof LocalDateTime) {
+            return compareTo0((LocalDateTime) other);
+        }
+        return ChronoLocalDateTime.super.compareTo(other);
+    }
+
+    private int compareTo0(LocalDateTime other) {
+        int cmp = date.compareTo0(other.getDate());
+        if (cmp == 0) {
+            cmp = time.compareTo(other.getTime());
+        }
+        return cmp;
+    }
+
+    /**
+     * Checks if this date-time is after the specified date-time.
+     * <p>
+     * This checks to see if this date-time represents a point on the
+     * local time-line after the other date-time.
+     * <pre>
+     *   LocalDate a = LocalDateTime.of(2012, 6, 30, 12, 00);
+     *   LocalDate b = LocalDateTime.of(2012, 7, 1, 12, 00);
+     *   a.isAfter(b) == false
+     *   a.isAfter(a) == false
+     *   b.isAfter(a) == true
+     * </pre>
+     * <p>
+     * This method only considers the position of the two date-times on the local time-line.
+     * It does not take into account the chronology, or calendar system.
+     * This is different from the comparison in {@link #compareTo(ChronoLocalDateTime)},
+     * but is the same approach as {@link #DATE_TIME_COMPARATOR}.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return true if this date-time is after the specified date-time
+     */
+    @Override  // override for Javadoc and performance
+    public boolean isAfter(ChronoLocalDateTime<?> other) {
+        if (other instanceof LocalDateTime) {
+            return compareTo0((LocalDateTime) other) > 0;
+        }
+        return ChronoLocalDateTime.super.isAfter(other);
+    }
+
+    /**
+     * Checks if this date-time is before the specified date-time.
+     * <p>
+     * This checks to see if this date-time represents a point on the
+     * local time-line before the other date-time.
+     * <pre>
+     *   LocalDate a = LocalDateTime.of(2012, 6, 30, 12, 00);
+     *   LocalDate b = LocalDateTime.of(2012, 7, 1, 12, 00);
+     *   a.isBefore(b) == true
+     *   a.isBefore(a) == false
+     *   b.isBefore(a) == false
+     * </pre>
+     * <p>
+     * This method only considers the position of the two date-times on the local time-line.
+     * It does not take into account the chronology, or calendar system.
+     * This is different from the comparison in {@link #compareTo(ChronoLocalDateTime)},
+     * but is the same approach as {@link #DATE_TIME_COMPARATOR}.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return true if this date-time is before the specified date-time
+     */
+    @Override  // override for Javadoc and performance
+    public boolean isBefore(ChronoLocalDateTime<?> other) {
+        if (other instanceof LocalDateTime) {
+            return compareTo0((LocalDateTime) other) < 0;
+        }
+        return ChronoLocalDateTime.super.isBefore(other);
+    }
+
+    /**
+     * Checks if this date-time is equal to the specified date-time.
+     * <p>
+     * This checks to see if this date-time represents the same point on the
+     * local time-line as the other date-time.
+     * <pre>
+     *   LocalDate a = LocalDateTime.of(2012, 6, 30, 12, 00);
+     *   LocalDate b = LocalDateTime.of(2012, 7, 1, 12, 00);
+     *   a.isEqual(b) == false
+     *   a.isEqual(a) == true
+     *   b.isEqual(a) == false
+     * </pre>
+     * <p>
+     * This method only considers the position of the two date-times on the local time-line.
+     * It does not take into account the chronology, or calendar system.
+     * This is different from the comparison in {@link #compareTo(ChronoLocalDateTime)},
+     * but is the same approach as {@link #DATE_TIME_COMPARATOR}.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return true if this date-time is equal to the specified date-time
+     */
+    @Override  // override for Javadoc and performance
+    public boolean isEqual(ChronoLocalDateTime<?> other) {
+        if (other instanceof LocalDateTime) {
+            return compareTo0((LocalDateTime) other) == 0;
+        }
+        return ChronoLocalDateTime.super.isEqual(other);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this date-time is equal to another date-time.
+     * <p>
+     * Compares this {@code LocalDateTime} with another ensuring that the date-time is the same.
+     * Only objects of type {@code LocalDateTime} are compared, other types return false.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other date-time
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof LocalDateTime) {
+            LocalDateTime other = (LocalDateTime) obj;
+            return date.equals(other.date) && time.equals(other.time);
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this date-time.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return date.hashCode() ^ time.hashCode();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this date-time as a {@code String}, such as {@code 2007-12-03T10:15:30}.
+     * <p>
+     * The output will be one of the following ISO-8601 formats:
+     * <p><ul>
+     * <li>{@code yyyy-MM-dd'T'HH:mm}</li>
+     * <li>{@code yyyy-MM-dd'T'HH:mm:ss}</li>
+     * <li>{@code yyyy-MM-dd'T'HH:mm:ss.SSS}</li>
+     * <li>{@code yyyy-MM-dd'T'HH:mm:ss.SSSSSS}</li>
+     * <li>{@code yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS}</li>
+     * </ul><p>
+     * The format used will be the shortest that outputs the full value of
+     * the time where the omitted parts are implied to be zero.
+     *
+     * @return a string representation of this date-time, not null
+     */
+    @Override
+    public String toString() {
+        return date.toString() + 'T' + time.toString();
+    }
+
+    /**
+     * Outputs this date-time as a {@code String} using the formatter.
+     * <p>
+     * This date-time will be passed to the formatter
+     * {@link DateTimeFormatter#print(TemporalAccessor) print method}.
+     *
+     * @param formatter  the formatter to use, not null
+     * @return the formatted date-time string, not null
+     * @throws DateTimeException if an error occurs during printing
+     */
+    @Override  // override for Javadoc
+    public String toString(DateTimeFormatter formatter) {
+        return ChronoLocalDateTime.super.toString(formatter);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * <pre>
+     *  out.writeByte(5);  // identifies this as a LocalDateTime
+     *  // the <a href="../../serialized-form.html#java.time.LocalDate">date</a> excluding the one byte header
+     *  // the <a href="../../serialized-form.html#java.time.LocalTime">time</a> excluding the one byte header
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.LOCAL_DATE_TIME_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     * @return never
+     * @throws InvalidObjectException always
+     */
+    private Object readResolve() throws ObjectStreamException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        date.writeExternal(out);
+        time.writeExternal(out);
+    }
+
+    static LocalDateTime readExternal(DataInput in) throws IOException {
+        LocalDate date = LocalDate.readExternal(in);
+        LocalTime time = LocalTime.readExternal(in);
+        return LocalDateTime.of(date, time);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/LocalTime.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,1630 @@
+/*
+ * 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;
+
+import static java.time.temporal.ChronoField.HOUR_OF_DAY;
+import static java.time.temporal.ChronoField.MICRO_OF_DAY;
+import static java.time.temporal.ChronoField.MINUTE_OF_HOUR;
+import static java.time.temporal.ChronoField.NANO_OF_DAY;
+import static java.time.temporal.ChronoField.NANO_OF_SECOND;
+import static java.time.temporal.ChronoField.SECOND_OF_DAY;
+import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
+import static java.time.temporal.ChronoUnit.NANOS;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.time.format.DateTimeBuilder;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatters;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoLocalDateTime;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.ChronoZonedDateTime;
+import java.time.temporal.OffsetTime;
+import java.time.temporal.Queries;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdder;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.TemporalSubtractor;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.ValueRange;
+import java.util.Objects;
+
+/**
+ * A time without time-zone in the ISO-8601 calendar system,
+ * such as {@code 10:15:30}.
+ * <p>
+ * {@code LocalTime} is an immutable date-time object that represents a time,
+ * often viewed as hour-minute-second.
+ * Time is represented to nanosecond precision.
+ * For example, the value "13:45.30.123456789" can be stored in a {@code LocalTime}.
+ * <p>
+ * It does not store or represent a date or time-zone.
+ * Instead, it is a description of the local time as seen on a wall clock.
+ * It cannot represent an instant on the time-line without additional information
+ * such as an offset or time-zone.
+ * <p>
+ * The ISO-8601 calendar system is the modern civil calendar system used today
+ * in most of the world. This API assumes that all calendar systems use the same
+ * representation, this class, for time-of-day.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class LocalTime
+        implements Temporal, TemporalAdjuster, Comparable<LocalTime>, Serializable {
+
+    /**
+     * The minimum supported {@code LocalTime}, '00:00'.
+     * This is the time of midnight at the start of the day.
+     */
+    public static final LocalTime MIN;
+    /**
+     * The minimum supported {@code LocalTime}, '23:59:59.999999999'.
+     * This is the time just before midnight at the end of the day.
+     */
+    public static final LocalTime MAX;
+    /**
+     * The time of midnight at the start of the day, '00:00'.
+     */
+    public static final LocalTime MIDNIGHT;
+    /**
+     * The time of noon in the middle of the day, '12:00'.
+     */
+    public static final LocalTime NOON;
+    /**
+     * Constants for the local time of each hour.
+     */
+    private static final LocalTime[] HOURS = new LocalTime[24];
+    static {
+        for (int i = 0; i < HOURS.length; i++) {
+            HOURS[i] = new LocalTime(i, 0, 0, 0);
+        }
+        MIDNIGHT = HOURS[0];
+        NOON = HOURS[12];
+        MIN = HOURS[0];
+        MAX = new LocalTime(23, 59, 59, 999_999_999);
+    }
+
+    /**
+     * Hours per day.
+     */
+    static final int HOURS_PER_DAY = 24;
+    /**
+     * Minutes per hour.
+     */
+    static final int MINUTES_PER_HOUR = 60;
+    /**
+     * Minutes per day.
+     */
+    static final int MINUTES_PER_DAY = MINUTES_PER_HOUR * HOURS_PER_DAY;
+    /**
+     * Seconds per minute.
+     */
+    static final int SECONDS_PER_MINUTE = 60;
+    /**
+     * Seconds per hour.
+     */
+    static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;
+    /**
+     * Seconds per day.
+     */
+    static final int SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY;
+    /**
+     * Milliseconds per day.
+     */
+    static final long MILLIS_PER_DAY = SECONDS_PER_DAY * 1000L;
+    /**
+     * Microseconds per day.
+     */
+    static final long MICROS_PER_DAY = SECONDS_PER_DAY * 1000_000L;
+    /**
+     * Nanos per second.
+     */
+    static final long NANOS_PER_SECOND = 1000_000_000L;
+    /**
+     * Nanos per minute.
+     */
+    static final long NANOS_PER_MINUTE = NANOS_PER_SECOND * SECONDS_PER_MINUTE;
+    /**
+     * Nanos per hour.
+     */
+    static final long NANOS_PER_HOUR = NANOS_PER_MINUTE * MINUTES_PER_HOUR;
+    /**
+     * Nanos per day.
+     */
+    static final long NANOS_PER_DAY = NANOS_PER_HOUR * HOURS_PER_DAY;
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 6414437269572265201L;
+
+    /**
+     * The hour.
+     */
+    private final byte hour;
+    /**
+     * The minute.
+     */
+    private final byte minute;
+    /**
+     * The second.
+     */
+    private final byte second;
+    /**
+     * The nanosecond.
+     */
+    private final int nano;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains the current time from the system clock in the default time-zone.
+     * <p>
+     * This will query the {@link Clock#systemDefaultZone() system clock} in the default
+     * time-zone to obtain the current time.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @return the current time using the system clock and default time-zone, not null
+     */
+    public static LocalTime now() {
+        return now(Clock.systemDefaultZone());
+    }
+
+    /**
+     * Obtains the current time from the system clock in the specified time-zone.
+     * <p>
+     * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current time.
+     * Specifying the time-zone avoids dependence on the default time-zone.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @param zone  the zone ID to use, not null
+     * @return the current time using the system clock, not null
+     */
+    public static LocalTime now(ZoneId zone) {
+        return now(Clock.system(zone));
+    }
+
+    /**
+     * Obtains the current time from the specified clock.
+     * <p>
+     * This will query the specified clock to obtain the current time.
+     * Using this method allows the use of an alternate clock for testing.
+     * The alternate clock may be introduced using {@link Clock dependency injection}.
+     *
+     * @param clock  the clock to use, not null
+     * @return the current time, not null
+     */
+    public static LocalTime now(Clock clock) {
+        Objects.requireNonNull(clock, "clock");
+        // inline OffsetTime factory to avoid creating object and InstantProvider checks
+        final Instant now = clock.instant();  // called once
+        ZoneOffset offset = clock.getZone().getRules().getOffset(now);
+        long secsOfDay = now.getEpochSecond() % SECONDS_PER_DAY;
+        secsOfDay = (secsOfDay + offset.getTotalSeconds()) % SECONDS_PER_DAY;
+        if (secsOfDay < 0) {
+            secsOfDay += SECONDS_PER_DAY;
+        }
+        return LocalTime.ofSecondOfDay(secsOfDay, now.getNano());
+    }
+
+    //------------------------get-----------------------------------------------
+    /**
+     * Obtains an instance of {@code LocalTime} from an hour and minute.
+     * <p>
+     * The second and nanosecond fields will be set to zero by this factory method.
+     * <p>
+     * This factory may return a cached value, but applications must not rely on this.
+     *
+     * @param hour  the hour-of-day to represent, from 0 to 23
+     * @param minute  the minute-of-hour to represent, from 0 to 59
+     * @return the local time, not null
+     * @throws DateTimeException if the value of any field is out of range
+     */
+    public static LocalTime of(int hour, int minute) {
+        HOUR_OF_DAY.checkValidValue(hour);
+        if (minute == 0) {
+            return HOURS[hour];  // for performance
+        }
+        MINUTE_OF_HOUR.checkValidValue(minute);
+        return new LocalTime(hour, minute, 0, 0);
+    }
+
+    /**
+     * Obtains an instance of {@code LocalTime} from an hour, minute and second.
+     * <p>
+     * The nanosecond field will be set to zero by this factory method.
+     * <p>
+     * This factory may return a cached value, but applications must not rely on this.
+     *
+     * @param hour  the hour-of-day to represent, from 0 to 23
+     * @param minute  the minute-of-hour to represent, from 0 to 59
+     * @param second  the second-of-minute to represent, from 0 to 59
+     * @return the local time, not null
+     * @throws DateTimeException if the value of any field is out of range
+     */
+    public static LocalTime of(int hour, int minute, int second) {
+        HOUR_OF_DAY.checkValidValue(hour);
+        if ((minute | second) == 0) {
+            return HOURS[hour];  // for performance
+        }
+        MINUTE_OF_HOUR.checkValidValue(minute);
+        SECOND_OF_MINUTE.checkValidValue(second);
+        return new LocalTime(hour, minute, second, 0);
+    }
+
+    /**
+     * Obtains an instance of {@code LocalTime} from an hour, minute, second and nanosecond.
+     * <p>
+     * This factory may return a cached value, but applications must not rely on this.
+     *
+     * @param hour  the hour-of-day to represent, from 0 to 23
+     * @param minute  the minute-of-hour to represent, from 0 to 59
+     * @param second  the second-of-minute to represent, from 0 to 59
+     * @param nanoOfSecond  the nano-of-second to represent, from 0 to 999,999,999
+     * @return the local time, not null
+     * @throws DateTimeException if the value of any field is out of range
+     */
+    public static LocalTime of(int hour, int minute, int second, int nanoOfSecond) {
+        HOUR_OF_DAY.checkValidValue(hour);
+        MINUTE_OF_HOUR.checkValidValue(minute);
+        SECOND_OF_MINUTE.checkValidValue(second);
+        NANO_OF_SECOND.checkValidValue(nanoOfSecond);
+        return create(hour, minute, second, nanoOfSecond);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code LocalTime} from a second-of-day value.
+     * <p>
+     * This factory may return a cached value, but applications must not rely on this.
+     *
+     * @param secondOfDay  the second-of-day, from {@code 0} to {@code 24 * 60 * 60 - 1}
+     * @return the local time, not null
+     * @throws DateTimeException if the second-of-day value is invalid
+     */
+    public static LocalTime ofSecondOfDay(long secondOfDay) {
+        SECOND_OF_DAY.checkValidValue(secondOfDay);
+        int hours = (int) (secondOfDay / SECONDS_PER_HOUR);
+        secondOfDay -= hours * SECONDS_PER_HOUR;
+        int minutes = (int) (secondOfDay / SECONDS_PER_MINUTE);
+        secondOfDay -= minutes * SECONDS_PER_MINUTE;
+        return create(hours, minutes, (int) secondOfDay, 0);
+    }
+
+    /**
+     * Obtains an instance of {@code LocalTime} from a second-of-day value, with
+     * associated nanos of second.
+     * <p>
+     * This factory may return a cached value, but applications must not rely on this.
+     *
+     * @param secondOfDay  the second-of-day, from {@code 0} to {@code 24 * 60 * 60 - 1}
+     * @param nanoOfSecond  the nano-of-second, from 0 to 999,999,999
+     * @return the local time, not null
+     * @throws DateTimeException if the either input value is invalid
+     */
+    public static LocalTime ofSecondOfDay(long secondOfDay, int nanoOfSecond) {
+        SECOND_OF_DAY.checkValidValue(secondOfDay);
+        NANO_OF_SECOND.checkValidValue(nanoOfSecond);
+        int hours = (int) (secondOfDay / SECONDS_PER_HOUR);
+        secondOfDay -= hours * SECONDS_PER_HOUR;
+        int minutes = (int) (secondOfDay / SECONDS_PER_MINUTE);
+        secondOfDay -= minutes * SECONDS_PER_MINUTE;
+        return create(hours, minutes, (int) secondOfDay, nanoOfSecond);
+    }
+
+    /**
+     * Obtains an instance of {@code LocalTime} from a nanos-of-day value.
+     * <p>
+     * This factory may return a cached value, but applications must not rely on this.
+     *
+     * @param nanoOfDay  the nano of day, from {@code 0} to {@code 24 * 60 * 60 * 1,000,000,000 - 1}
+     * @return the local time, not null
+     * @throws DateTimeException if the nanos of day value is invalid
+     */
+    public static LocalTime ofNanoOfDay(long nanoOfDay) {
+        NANO_OF_DAY.checkValidValue(nanoOfDay);
+        int hours = (int) (nanoOfDay / NANOS_PER_HOUR);
+        nanoOfDay -= hours * NANOS_PER_HOUR;
+        int minutes = (int) (nanoOfDay / NANOS_PER_MINUTE);
+        nanoOfDay -= minutes * NANOS_PER_MINUTE;
+        int seconds = (int) (nanoOfDay / NANOS_PER_SECOND);
+        nanoOfDay -= seconds * NANOS_PER_SECOND;
+        return create(hours, minutes, seconds, (int) nanoOfDay);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code LocalTime} from a temporal object.
+     * <p>
+     * A {@code TemporalAccessor} represents some form of date and time information.
+     * This factory converts the arbitrary temporal object to an instance of {@code LocalTime}.
+     * <p>
+     * The conversion extracts the {@link ChronoField#NANO_OF_DAY NANO_OF_DAY} field.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used in queries via method reference, {@code LocalTime::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the local time, not null
+     * @throws DateTimeException if unable to convert to a {@code LocalTime}
+     */
+    public static LocalTime from(TemporalAccessor temporal) {
+        if (temporal instanceof LocalTime) {
+            return (LocalTime) temporal;
+        } else if (temporal instanceof ChronoLocalDateTime) {
+            return ((ChronoLocalDateTime) temporal).getTime();
+        } else if (temporal instanceof ChronoZonedDateTime) {
+            return ((ChronoZonedDateTime) temporal).getTime();
+        }
+        // handle builder as a special case
+        if (temporal instanceof DateTimeBuilder) {
+            DateTimeBuilder builder = (DateTimeBuilder) temporal;
+            LocalTime time = builder.extract(LocalTime.class);
+            if (time != null) {
+                return time;
+            }
+        }
+        try {
+            return ofNanoOfDay(temporal.getLong(NANO_OF_DAY));
+        } catch (DateTimeException ex) {
+            throw new DateTimeException("Unable to obtain LocalTime from TemporalAccessor: " + temporal.getClass(), ex);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code LocalTime} from a text string such as {@code 10:15}.
+     * <p>
+     * The string must represent a valid time and is parsed using
+     * {@link java.time.format.DateTimeFormatters#isoLocalTime()}.
+     *
+     * @param text the text to parse such as "10:15:30", not null
+     * @return the parsed local time, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static LocalTime parse(CharSequence text) {
+        return parse(text, DateTimeFormatters.isoLocalTime());
+    }
+
+    /**
+     * Obtains an instance of {@code LocalTime} from a text string using a specific formatter.
+     * <p>
+     * The text is parsed using the formatter, returning a time.
+     *
+     * @param text  the text to parse, not null
+     * @param formatter  the formatter to use, not null
+     * @return the parsed local time, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static LocalTime parse(CharSequence text, DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.parse(text, LocalTime::from);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Creates a local time from the hour, minute, second and nanosecond fields.
+     * <p>
+     * This factory may return a cached value, but applications must not rely on this.
+     *
+     * @param hour  the hour-of-day to represent, validated from 0 to 23
+     * @param minute  the minute-of-hour to represent, validated from 0 to 59
+     * @param second  the second-of-minute to represent, validated from 0 to 59
+     * @param nanoOfSecond  the nano-of-second to represent, validated from 0 to 999,999,999
+     * @return the local time, not null
+     */
+    private static LocalTime create(int hour, int minute, int second, int nanoOfSecond) {
+        if ((minute | second | nanoOfSecond) == 0) {
+            return HOURS[hour];
+        }
+        return new LocalTime(hour, minute, second, nanoOfSecond);
+    }
+
+    /**
+     * Constructor, previously validated.
+     *
+     * @param hour  the hour-of-day to represent, validated from 0 to 23
+     * @param minute  the minute-of-hour to represent, validated from 0 to 59
+     * @param second  the second-of-minute to represent, validated from 0 to 59
+     * @param nanoOfSecond  the nano-of-second to represent, validated from 0 to 999,999,999
+     */
+    private LocalTime(int hour, int minute, int second, int nanoOfSecond) {
+        this.hour = (byte) hour;
+        this.minute = (byte) minute;
+        this.second = (byte) second;
+        this.nano = nanoOfSecond;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if this time can be queried for the specified field.
+     * If false, then calling the {@link #range(TemporalField) range} and
+     * {@link #get(TemporalField) get} methods will throw an exception.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The supported fields are:
+     * <ul>
+     * <li>{@code NANO_OF_SECOND}
+     * <li>{@code NANO_OF_DAY}
+     * <li>{@code MICRO_OF_SECOND}
+     * <li>{@code MICRO_OF_DAY}
+     * <li>{@code MILLI_OF_SECOND}
+     * <li>{@code MILLI_OF_DAY}
+     * <li>{@code SECOND_OF_MINUTE}
+     * <li>{@code SECOND_OF_DAY}
+     * <li>{@code MINUTE_OF_HOUR}
+     * <li>{@code MINUTE_OF_DAY}
+     * <li>{@code HOUR_OF_AMPM}
+     * <li>{@code CLOCK_HOUR_OF_AMPM}
+     * <li>{@code HOUR_OF_DAY}
+     * <li>{@code CLOCK_HOUR_OF_DAY}
+     * <li>{@code AMPM_OF_DAY}
+     * </ul>
+     * All other {@code ChronoField} instances will return false.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the field is supported is determined by the field.
+     *
+     * @param field  the field to check, null returns false
+     * @return true if the field is supported on this time, false if not
+     */
+    @Override
+    public boolean isSupported(TemporalField field) {
+        if (field instanceof ChronoField) {
+            return ((ChronoField) field).isTimeField();
+        }
+        return field != null && field.doIsSupported(this);
+    }
+
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * The range object expresses the minimum and maximum valid values for a field.
+     * This time is used to enhance the accuracy of the returned range.
+     * If it is not possible to return the range, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * 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}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the range can be obtained is determined by the field.
+     *
+     * @param field  the field to query the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     */
+    @Override  // override for Javadoc
+    public ValueRange range(TemporalField field) {
+        return Temporal.super.range(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this time as an {@code int}.
+     * <p>
+     * This queries this time for the value for the specified field.
+     * The returned value will always be within the valid range of values for the field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this time, except {@code NANO_OF_DAY} and {@code MICRO_OF_DAY}
+     * which are too large to fit in an {@code int} and throw a {@code DateTimeException}.
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override  // override for Javadoc and performance
+    public int get(TemporalField field) {
+        if (field instanceof ChronoField) {
+            return get0(field);
+        }
+        return Temporal.super.get(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this time as a {@code long}.
+     * <p>
+     * This queries this time for the value for the specified field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this time.
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * 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 == NANO_OF_DAY) {
+                return toNanoOfDay();
+            }
+            if (field == MICRO_OF_DAY) {
+                return toNanoOfDay() / 1000;
+            }
+            return get0(field);
+        }
+        return field.doGet(this);
+    }
+
+    private int get0(TemporalField field) {
+        switch ((ChronoField) field) {
+            case NANO_OF_SECOND: return nano;
+            case NANO_OF_DAY: throw new DateTimeException("Field too large for an int: " + field);
+            case MICRO_OF_SECOND: return nano / 1000;
+            case MICRO_OF_DAY: throw new DateTimeException("Field too large for an int: " + field);
+            case MILLI_OF_SECOND: return nano / 1000_000;
+            case MILLI_OF_DAY: return (int) (toNanoOfDay() / 1000_000);
+            case SECOND_OF_MINUTE: return second;
+            case SECOND_OF_DAY: return toSecondOfDay();
+            case MINUTE_OF_HOUR: return minute;
+            case MINUTE_OF_DAY: return hour * 60 + minute;
+            case HOUR_OF_AMPM: return hour % 12;
+            case CLOCK_HOUR_OF_AMPM: int ham = hour % 12; return (ham % 12 == 0 ? 12 : ham);
+            case HOUR_OF_DAY: return hour;
+            case CLOCK_HOUR_OF_DAY: return (hour == 0 ? 24 : hour);
+            case AMPM_OF_DAY: return hour / 12;
+        }
+        throw new DateTimeException("Unsupported field: " + field.getName());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the hour-of-day field.
+     *
+     * @return the hour-of-day, from 0 to 23
+     */
+    public int getHour() {
+        return hour;
+    }
+
+    /**
+     * Gets the minute-of-hour field.
+     *
+     * @return the minute-of-hour, from 0 to 59
+     */
+    public int getMinute() {
+        return minute;
+    }
+
+    /**
+     * Gets the second-of-minute field.
+     *
+     * @return the second-of-minute, from 0 to 59
+     */
+    public int getSecond() {
+        return second;
+    }
+
+    /**
+     * Gets the nano-of-second field.
+     *
+     * @return the nano-of-second, from 0 to 999,999,999
+     */
+    public int getNano() {
+        return nano;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns an adjusted copy of this time.
+     * <p>
+     * This returns a new {@code LocalTime}, based on this one, with the time adjusted.
+     * The adjustment takes place using the specified adjuster strategy object.
+     * Read the documentation of the adjuster to understand what adjustment will be made.
+     * <p>
+     * A simple adjuster might simply set the one of the fields, such as the hour field.
+     * A more complex adjuster might set the time to the last hour of the day.
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param adjuster the adjuster to use, not null
+     * @return a {@code LocalTime} 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 LocalTime with(TemporalAdjuster adjuster) {
+        // optimizations
+        if (adjuster instanceof LocalTime) {
+            return (LocalTime) adjuster;
+        }
+        return (LocalTime) adjuster.adjustInto(this);
+    }
+
+    /**
+     * Returns a copy of this time with the specified field set to a new value.
+     * <p>
+     * This returns a new {@code LocalTime}, based on this one, with the value
+     * for the specified field changed.
+     * This can be used to change any supported field, such as the hour, minute or second.
+     * If it is not possible to set the value, because the field is not supported or for
+     * some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the adjustment is implemented here.
+     * The supported fields behave as follows:
+     * <ul>
+     * <li>{@code NANO_OF_SECOND} -
+     *  Returns a {@code LocalTime} with the specified nano-of-second.
+     *  The hour, minute and second will be unchanged.
+     * <li>{@code NANO_OF_DAY} -
+     *  Returns a {@code LocalTime} with the specified nano-of-day.
+     *  This completely replaces the time and is equivalent to {@link #ofNanoOfDay(long)}.
+     * <li>{@code MICRO_OF_SECOND} -
+     *  Returns a {@code LocalTime} with the nano-of-second replaced by the specified
+     *  micro-of-second multiplied by 1,000.
+     *  The hour, minute and second will be unchanged.
+     * <li>{@code MICRO_OF_DAY} -
+     *  Returns a {@code LocalTime} with the specified micro-of-day.
+     *  This completely replaces the time and is equivalent to using {@link #ofNanoOfDay(long)}
+     *  with the micro-of-day multiplied by 1,000.
+     * <li>{@code MILLI_OF_SECOND} -
+     *  Returns a {@code LocalTime} with the nano-of-second replaced by the specified
+     *  milli-of-second multiplied by 1,000,000.
+     *  The hour, minute and second will be unchanged.
+     * <li>{@code MILLI_OF_DAY} -
+     *  Returns a {@code LocalTime} with the specified milli-of-day.
+     *  This completely replaces the time and is equivalent to using {@link #ofNanoOfDay(long)}
+     *  with the milli-of-day multiplied by 1,000,000.
+     * <li>{@code SECOND_OF_MINUTE} -
+     *  Returns a {@code LocalTime} with the specified second-of-minute.
+     *  The hour, minute and nano-of-second will be unchanged.
+     * <li>{@code SECOND_OF_DAY} -
+     *  Returns a {@code LocalTime} with the specified second-of-day.
+     *  The nano-of-second will be unchanged.
+     * <li>{@code MINUTE_OF_HOUR} -
+     *  Returns a {@code LocalTime} with the specified minute-of-hour.
+     *  The hour, second-of-minute and nano-of-second will be unchanged.
+     * <li>{@code MINUTE_OF_DAY} -
+     *  Returns a {@code LocalTime} with the specified minute-of-day.
+     *  The second-of-minute and nano-of-second will be unchanged.
+     * <li>{@code HOUR_OF_AMPM} -
+     *  Returns a {@code LocalTime} with the specified hour-of-am-pm.
+     *  The AM/PM, minute-of-hour, second-of-minute and nano-of-second will be unchanged.
+     * <li>{@code CLOCK_HOUR_OF_AMPM} -
+     *  Returns a {@code LocalTime} with the specified clock-hour-of-am-pm.
+     *  The AM/PM, minute-of-hour, second-of-minute and nano-of-second will be unchanged.
+     * <li>{@code HOUR_OF_DAY} -
+     *  Returns a {@code LocalTime} with the specified hour-of-day.
+     *  The minute-of-hour, second-of-minute and nano-of-second will be unchanged.
+     * <li>{@code CLOCK_HOUR_OF_DAY} -
+     *  Returns a {@code LocalTime} with the specified clock-hour-of-day.
+     *  The minute-of-hour, second-of-minute and nano-of-second will be unchanged.
+     * <li>{@code AMPM_OF_DAY} -
+     *  Returns a {@code LocalTime} with the specified AM/PM.
+     *  The hour-of-am-pm, minute-of-hour, second-of-minute and nano-of-second will be unchanged.
+     * </ul>
+     * <p>
+     * In all cases, if the new value is outside the valid range of values for the field
+     * then a {@code DateTimeException} will be thrown.
+     * <p>
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param field  the field to set in the result, not null
+     * @param newValue  the new value of the field in the result
+     * @return a {@code LocalTime} 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 LocalTime with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            f.checkValidValue(newValue);
+            switch (f) {
+                case NANO_OF_SECOND: return withNano((int) newValue);
+                case NANO_OF_DAY: return LocalTime.ofNanoOfDay(newValue);
+                case MICRO_OF_SECOND: return withNano((int) newValue * 1000);
+                case MICRO_OF_DAY: return plusNanos((newValue - toNanoOfDay() / 1000) * 1000);
+                case MILLI_OF_SECOND: return withNano((int) newValue * 1000_000);
+                case MILLI_OF_DAY: return plusNanos((newValue - toNanoOfDay() / 1000_000) * 1000_000);
+                case SECOND_OF_MINUTE: return withSecond((int) newValue);
+                case SECOND_OF_DAY: return plusSeconds(newValue - toSecondOfDay());
+                case MINUTE_OF_HOUR: return withMinute((int) newValue);
+                case MINUTE_OF_DAY: return plusMinutes(newValue - (hour * 60 + minute));
+                case HOUR_OF_AMPM: return plusHours(newValue - (hour % 12));
+                case CLOCK_HOUR_OF_AMPM: return plusHours((newValue == 12 ? 0 : newValue) - (hour % 12));
+                case HOUR_OF_DAY: return withHour((int) newValue);
+                case CLOCK_HOUR_OF_DAY: return withHour((int) (newValue == 24 ? 0 : newValue));
+                case AMPM_OF_DAY: return plusHours((newValue - (hour / 12)) * 12);
+            }
+            throw new DateTimeException("Unsupported field: " + field.getName());
+        }
+        return field.doWith(this, newValue);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code LocalTime} with the hour-of-day value altered.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hour  the hour-of-day to set in the result, from 0 to 23
+     * @return a {@code LocalTime} based on this time with the requested hour, not null
+     * @throws DateTimeException if the hour value is invalid
+     */
+    public LocalTime withHour(int hour) {
+        if (this.hour == hour) {
+            return this;
+        }
+        HOUR_OF_DAY.checkValidValue(hour);
+        return create(hour, minute, second, nano);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalTime} with the minute-of-hour value altered.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minute  the minute-of-hour to set in the result, from 0 to 59
+     * @return a {@code LocalTime} based on this time with the requested minute, not null
+     * @throws DateTimeException if the minute value is invalid
+     */
+    public LocalTime withMinute(int minute) {
+        if (this.minute == minute) {
+            return this;
+        }
+        MINUTE_OF_HOUR.checkValidValue(minute);
+        return create(hour, minute, second, nano);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalTime} with the second-of-minute value altered.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param second  the second-of-minute to set in the result, from 0 to 59
+     * @return a {@code LocalTime} based on this time with the requested second, not null
+     * @throws DateTimeException if the second value is invalid
+     */
+    public LocalTime withSecond(int second) {
+        if (this.second == second) {
+            return this;
+        }
+        SECOND_OF_MINUTE.checkValidValue(second);
+        return create(hour, minute, second, nano);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalTime} with the nano-of-second value altered.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanoOfSecond  the nano-of-second to set in the result, from 0 to 999,999,999
+     * @return a {@code LocalTime} based on this time with the requested nanosecond, not null
+     * @throws DateTimeException if the nanos value is invalid
+     */
+    public LocalTime withNano(int nanoOfSecond) {
+        if (this.nano == nanoOfSecond) {
+            return this;
+        }
+        NANO_OF_SECOND.checkValidValue(nanoOfSecond);
+        return create(hour, minute, second, nanoOfSecond);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code LocalTime} with the time truncated.
+     * <p>
+     * Truncating the time returns a copy of the original time with fields
+     * smaller than the specified unit set to zero.
+     * For example, truncating with the {@link ChronoUnit#MINUTES minutes} unit
+     * will set the second-of-minute and nano-of-second field to zero.
+     * <p>
+     * Not all units are accepted. The {@link ChronoUnit#DAYS days} unit and time
+     * units with an exact duration can be used, other units throw an exception.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param unit  the unit to truncate to, not null
+     * @return a {@code LocalTime} based on this time with the time truncated, not null
+     * @throws DateTimeException if unable to truncate
+     */
+    public LocalTime truncatedTo(TemporalUnit unit) {
+        if (unit == ChronoUnit.NANOS) {
+            return this;
+        } else if (unit == ChronoUnit.DAYS) {
+            return MIDNIGHT;
+        } else if (unit.isDurationEstimated()) {
+            throw new DateTimeException("Unit must not have an estimated duration");
+        }
+        long nod = toNanoOfDay();
+        long dur = unit.getDuration().toNanos();
+        if (dur >= NANOS_PER_DAY) {
+            throw new DateTimeException("Unit must not be a date unit");
+        }
+        nod = (nod / dur) * dur;
+        return ofNanoOfDay(nod);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this date with the specified period added.
+     * <p>
+     * This method returns a new time based on this time with the specified period added.
+     * The adder is typically {@link 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)}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param adder  the adder to use, not null
+     * @return a {@code LocalTime} based on this time with the addition made, not null
+     * @throws DateTimeException if the addition cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public LocalTime plus(TemporalAdder adder) {
+        return (LocalTime) adder.addTo(this);
+    }
+
+    /**
+     * Returns a copy of this time with the specified period added.
+     * <p>
+     * This method returns a new time based on this time with the specified period added.
+     * This can be used to add any period that is defined by a unit, for example to add hours, minutes or seconds.
+     * The unit is responsible for the details of the calculation, including the resolution
+     * of any edge cases in the calculation.
+     * <p>
+     * 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 a {@code LocalTime} based on this time with the specified period added, not null
+     * @throws DateTimeException if the unit cannot be added to this type
+     */
+    @Override
+    public LocalTime plus(long amountToAdd, TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            ChronoUnit f = (ChronoUnit) unit;
+            switch (f) {
+                case NANOS: return plusNanos(amountToAdd);
+                case MICROS: return plusNanos((amountToAdd % MICROS_PER_DAY) * 1000);
+                case MILLIS: return plusNanos((amountToAdd % MILLIS_PER_DAY) * 1000_000);
+                case SECONDS: return plusSeconds(amountToAdd);
+                case MINUTES: return plusMinutes(amountToAdd);
+                case HOURS: return plusHours(amountToAdd);
+                case HALF_DAYS: return plusHours((amountToAdd % 2) * 12);
+                case DAYS: return this;
+            }
+            throw new DateTimeException("Unsupported unit: " + unit.getName());
+        }
+        return unit.doPlus(this, amountToAdd);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code LocalTime} with the specified period in hours added.
+     * <p>
+     * This adds the specified number of hours to this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hoursToAdd  the hours to add, may be negative
+     * @return a {@code LocalTime} based on this time with the hours added, not null
+     */
+    public LocalTime plusHours(long hoursToAdd) {
+        if (hoursToAdd == 0) {
+            return this;
+        }
+        int newHour = ((int) (hoursToAdd % HOURS_PER_DAY) + hour + HOURS_PER_DAY) % HOURS_PER_DAY;
+        return create(newHour, minute, second, nano);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalTime} with the specified period in minutes added.
+     * <p>
+     * This adds the specified number of minutes to this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minutesToAdd  the minutes to add, may be negative
+     * @return a {@code LocalTime} based on this time with the minutes added, not null
+     */
+    public LocalTime plusMinutes(long minutesToAdd) {
+        if (minutesToAdd == 0) {
+            return this;
+        }
+        int mofd = hour * MINUTES_PER_HOUR + minute;
+        int newMofd = ((int) (minutesToAdd % MINUTES_PER_DAY) + mofd + MINUTES_PER_DAY) % MINUTES_PER_DAY;
+        if (mofd == newMofd) {
+            return this;
+        }
+        int newHour = newMofd / MINUTES_PER_HOUR;
+        int newMinute = newMofd % MINUTES_PER_HOUR;
+        return create(newHour, newMinute, second, nano);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalTime} with the specified period in seconds added.
+     * <p>
+     * This adds the specified number of seconds to this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param secondstoAdd  the seconds to add, may be negative
+     * @return a {@code LocalTime} based on this time with the seconds added, not null
+     */
+    public LocalTime plusSeconds(long secondstoAdd) {
+        if (secondstoAdd == 0) {
+            return this;
+        }
+        int sofd = hour * SECONDS_PER_HOUR +
+                    minute * SECONDS_PER_MINUTE + second;
+        int newSofd = ((int) (secondstoAdd % SECONDS_PER_DAY) + sofd + SECONDS_PER_DAY) % SECONDS_PER_DAY;
+        if (sofd == newSofd) {
+            return this;
+        }
+        int newHour = newSofd / SECONDS_PER_HOUR;
+        int newMinute = (newSofd / SECONDS_PER_MINUTE) % MINUTES_PER_HOUR;
+        int newSecond = newSofd % SECONDS_PER_MINUTE;
+        return create(newHour, newMinute, newSecond, nano);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalTime} with the specified period in nanoseconds added.
+     * <p>
+     * This adds the specified number of nanoseconds to this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanosToAdd  the nanos to add, may be negative
+     * @return a {@code LocalTime} based on this time with the nanoseconds added, not null
+     */
+    public LocalTime plusNanos(long nanosToAdd) {
+        if (nanosToAdd == 0) {
+            return this;
+        }
+        long nofd = toNanoOfDay();
+        long newNofd = ((nanosToAdd % NANOS_PER_DAY) + nofd + NANOS_PER_DAY) % NANOS_PER_DAY;
+        if (nofd == newNofd) {
+            return this;
+        }
+        int newHour = (int) (newNofd / NANOS_PER_HOUR);
+        int newMinute = (int) ((newNofd / NANOS_PER_MINUTE) % MINUTES_PER_HOUR);
+        int newSecond = (int) ((newNofd / NANOS_PER_SECOND) % SECONDS_PER_MINUTE);
+        int newNano = (int) (newNofd % NANOS_PER_SECOND);
+        return create(newHour, newMinute, newSecond, newNano);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this time with the specified period subtracted.
+     * <p>
+     * This method returns a new time based on this time with the specified period subtracted.
+     * The subtractor is typically {@link 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)}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param subtractor  the subtractor to use, not null
+     * @return a {@code LocalTime} based on this time with the subtraction made, not null
+     * @throws DateTimeException if the subtraction cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public LocalTime minus(TemporalSubtractor subtractor) {
+        return (LocalTime) subtractor.subtractFrom(this);
+    }
+
+    /**
+     * Returns a copy of this time with the specified period subtracted.
+     * <p>
+     * This method returns a new time based on this time with the specified period subtracted.
+     * This can be used to subtract any period that is defined by a unit, for example to subtract hours, minutes or seconds.
+     * The unit is responsible for the details of the calculation, including the resolution
+     * of any edge cases in the calculation.
+     * <p>
+     * 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 a {@code LocalTime} based on this time with the specified period subtracted, not null
+     * @throws DateTimeException if the unit cannot be added to this type
+     */
+    @Override
+    public LocalTime 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 LocalTime} with the specified period in hours subtracted.
+     * <p>
+     * This subtracts the specified number of hours from this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hoursToSubtract  the hours to subtract, may be negative
+     * @return a {@code LocalTime} based on this time with the hours subtracted, not null
+     */
+    public LocalTime minusHours(long hoursToSubtract) {
+        return plusHours(-(hoursToSubtract % HOURS_PER_DAY));
+    }
+
+    /**
+     * Returns a copy of this {@code LocalTime} with the specified period in minutes subtracted.
+     * <p>
+     * This subtracts the specified number of minutes from this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minutesToSubtract  the minutes to subtract, may be negative
+     * @return a {@code LocalTime} based on this time with the minutes subtracted, not null
+     */
+    public LocalTime minusMinutes(long minutesToSubtract) {
+        return plusMinutes(-(minutesToSubtract % MINUTES_PER_DAY));
+    }
+
+    /**
+     * Returns a copy of this {@code LocalTime} with the specified period in seconds subtracted.
+     * <p>
+     * This subtracts the specified number of seconds from this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param secondsToSubtract  the seconds to subtract, may be negative
+     * @return a {@code LocalTime} based on this time with the seconds subtracted, not null
+     */
+    public LocalTime minusSeconds(long secondsToSubtract) {
+        return plusSeconds(-(secondsToSubtract % SECONDS_PER_DAY));
+    }
+
+    /**
+     * Returns a copy of this {@code LocalTime} with the specified period in nanoseconds subtracted.
+     * <p>
+     * This subtracts the specified number of nanoseconds from this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanosToSubtract  the nanos to subtract, may be negative
+     * @return a {@code LocalTime} based on this time with the nanoseconds subtracted, not null
+     */
+    public LocalTime minusNanos(long nanosToSubtract) {
+        return plusNanos(-(nanosToSubtract % NANOS_PER_DAY));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this time using the specified query.
+     * <p>
+     * This queries this time using the specified query strategy object.
+     * The {@code TemporalQuery} object defines the logic to be used to
+     * obtain the result. Read the documentation of the query to understand
+     * what the result of this method will be.
+     * <p>
+     * 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 <R> 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> R query(TemporalQuery<R> query) {
+        if (query == Queries.precision()) {
+            return (R) NANOS;
+        }
+        // inline TemporalAccessor.super.query(query) as an optimization
+        if (query == Queries.chrono() || query == Queries.zoneId() || query == Queries.zone() || query == Queries.offset()) {
+            return null;
+        }
+        return query.queryFrom(this);
+    }
+
+    /**
+     * Adjusts the specified temporal object to have the same time as this object.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with the time changed to be the same as this.
+     * <p>
+     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+     * passing {@link ChronoField#NANO_OF_DAY} as the field.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisLocalTime.adjustInto(temporal);
+     *   temporal = temporal.with(thisLocalTime);
+     * </pre>
+     * <p>
+     * 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(NANO_OF_DAY, toNanoOfDay());
+    }
+
+    /**
+     * Calculates the period between this time and another time in
+     * terms of the specified unit.
+     * <p>
+     * This calculates the period between two times in terms of a single unit.
+     * The start and end points are {@code this} and the specified time.
+     * The result will be negative if the end is before the start.
+     * The {@code Temporal} passed to this method must be a {@code LocalTime}.
+     * For example, the period in hours between two times can be calculated
+     * using {@code startTime.periodUntil(endTime, HOURS)}.
+     * <p>
+     * The calculation returns a whole number, representing the number of
+     * complete units between the two times.
+     * For example, the period in hours between 11:30 and 13:29 will only
+     * be one hour as it is one minute short of two hours.
+     * <p>
+     * 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:
+     * <pre>
+     *   long period = start.periodUntil(end, HOURS);   // this method
+     *   dateTime.plus(HOURS.between(start, end));      // use in plus/minus
+     * </pre>
+     * <p>
+     * The calculation is implemented in this method for {@link ChronoUnit}.
+     * The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS},
+     * {@code MINUTES}, {@code HOURS} and {@code HALF_DAYS} are supported.
+     * Other {@code ChronoUnit} values will throw an exception.
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param endTime  the end time, which must be a {@code LocalTime}, not null
+     * @param unit  the unit to measure the period in, not null
+     * @return the amount of the period between this time and the end time
+     * @throws DateTimeException if the period cannot be calculated
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long periodUntil(Temporal endTime, TemporalUnit unit) {
+        if (endTime instanceof LocalTime == false) {
+            Objects.requireNonNull(endTime, "endTime");
+            throw new DateTimeException("Unable to calculate period between objects of two different types");
+        }
+        LocalTime end = (LocalTime) endTime;
+        if (unit instanceof ChronoUnit) {
+            long nanosUntil = end.toNanoOfDay() - toNanoOfDay();  // no overflow
+            switch ((ChronoUnit) unit) {
+                case NANOS: return nanosUntil;
+                case MICROS: return nanosUntil / 1000;
+                case MILLIS: return nanosUntil / 1000_000;
+                case SECONDS: return nanosUntil / NANOS_PER_SECOND;
+                case MINUTES: return nanosUntil / NANOS_PER_MINUTE;
+                case HOURS: return nanosUntil / NANOS_PER_HOUR;
+                case HALF_DAYS: return nanosUntil / (12 * NANOS_PER_HOUR);
+            }
+            throw new DateTimeException("Unsupported unit: " + unit.getName());
+        }
+        return unit.between(this, endTime).getAmount();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a local date-time formed from this time at the specified date.
+     * <p>
+     * This combines this time with the specified date to form a {@code LocalDateTime}.
+     * All possible combinations of date and time are valid.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param date  the date to combine with, not null
+     * @return the local date-time formed from this time and the specified date, not null
+     */
+    public LocalDateTime atDate(LocalDate date) {
+        return LocalDateTime.of(date, this);
+    }
+
+    /**
+     * Returns an offset time formed from this time and the specified offset.
+     * <p>
+     * This combines this time with the specified offset to form an {@code OffsetTime}.
+     * All possible combinations of time and offset are valid.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param offset  the offset to combine with, not null
+     * @return the offset time formed from this time and the specified offset, not null
+     */
+    public OffsetTime atOffset(ZoneOffset offset) {
+        return OffsetTime.of(this, offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Extracts the time as seconds of day,
+     * from {@code 0} to {@code 24 * 60 * 60 - 1}.
+     *
+     * @return the second-of-day equivalent to this time
+     */
+    public int toSecondOfDay() {
+        int total = hour * SECONDS_PER_HOUR;
+        total += minute * SECONDS_PER_MINUTE;
+        total += second;
+        return total;
+    }
+
+    /**
+     * Extracts the time as nanos of day,
+     * from {@code 0} to {@code 24 * 60 * 60 * 1,000,000,000 - 1}.
+     *
+     * @return the nano of day equivalent to this time
+     */
+    public long toNanoOfDay() {
+        long total = hour * NANOS_PER_HOUR;
+        total += minute * NANOS_PER_MINUTE;
+        total += second * NANOS_PER_SECOND;
+        total += nano;
+        return total;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this {@code LocalTime} to another time.
+     * <p>
+     * The comparison is based on the time-line position of the local times within a day.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     *
+     * @param other  the other time to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     * @throws NullPointerException if {@code other} is null
+     */
+    @Override
+    public int compareTo(LocalTime other) {
+        int cmp = Integer.compare(hour, other.hour);
+        if (cmp == 0) {
+            cmp = Integer.compare(minute, other.minute);
+            if (cmp == 0) {
+                cmp = Integer.compare(second, other.second);
+                if (cmp == 0) {
+                    cmp = Integer.compare(nano, other.nano);
+                }
+            }
+        }
+        return cmp;
+    }
+
+    /**
+     * Checks if this {@code LocalTime} is after the specified time.
+     * <p>
+     * The comparison is based on the time-line position of the time within a day.
+     *
+     * @param other  the other time to compare to, not null
+     * @return true if this is after the specified time
+     * @throws NullPointerException if {@code other} is null
+     */
+    public boolean isAfter(LocalTime other) {
+        return compareTo(other) > 0;
+    }
+
+    /**
+     * Checks if this {@code LocalTime} is before the specified time.
+     * <p>
+     * The comparison is based on the time-line position of the time within a day.
+     *
+     * @param other  the other time to compare to, not null
+     * @return true if this point is before the specified time
+     * @throws NullPointerException if {@code other} is null
+     */
+    public boolean isBefore(LocalTime other) {
+        return compareTo(other) < 0;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this time is equal to another time.
+     * <p>
+     * The comparison is based on the time-line position of the time within a day.
+     * <p>
+     * Only objects of type {@code LocalTime} are compared, other types return false.
+     * To compare the date of two {@code TemporalAccessor} instances, use
+     * {@link ChronoField#NANO_OF_DAY} as a comparator.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other time
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof LocalTime) {
+            LocalTime other = (LocalTime) obj;
+            return hour == other.hour && minute == other.minute &&
+                    second == other.second && nano == other.nano;
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this time.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        long nod = toNanoOfDay();
+        return (int) (nod ^ (nod >>> 32));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this time as a {@code String}, such as {@code 10:15}.
+     * <p>
+     * The output will be one of the following ISO-8601 formats:
+     * <p><ul>
+     * <li>{@code HH:mm}</li>
+     * <li>{@code HH:mm:ss}</li>
+     * <li>{@code HH:mm:ss.SSS}</li>
+     * <li>{@code HH:mm:ss.SSSSSS}</li>
+     * <li>{@code HH:mm:ss.SSSSSSSSS}</li>
+     * </ul><p>
+     * The format used will be the shortest that outputs the full value of
+     * the time where the omitted parts are implied to be zero.
+     *
+     * @return a string representation of this time, not null
+     */
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder(18);
+        int hourValue = hour;
+        int minuteValue = minute;
+        int secondValue = second;
+        int nanoValue = nano;
+        buf.append(hourValue < 10 ? "0" : "").append(hourValue)
+            .append(minuteValue < 10 ? ":0" : ":").append(minuteValue);
+        if (secondValue > 0 || nanoValue > 0) {
+            buf.append(secondValue < 10 ? ":0" : ":").append(secondValue);
+            if (nanoValue > 0) {
+                buf.append('.');
+                if (nanoValue % 1000_000 == 0) {
+                    buf.append(Integer.toString((nanoValue / 1000_000) + 1000).substring(1));
+                } else if (nanoValue % 1000 == 0) {
+                    buf.append(Integer.toString((nanoValue / 1000) + 1000_000).substring(1));
+                } else {
+                    buf.append(Integer.toString((nanoValue) + 1000_000_000).substring(1));
+                }
+            }
+        }
+        return buf.toString();
+    }
+
+    /**
+     * Outputs this time as a {@code String} using the formatter.
+     * <p>
+     * This time will be passed to the formatter
+     * {@link DateTimeFormatter#print(TemporalAccessor) print method}.
+     *
+     * @param formatter  the formatter to use, not null
+     * @return the formatted time string, not null
+     * @throws DateTimeException if an error occurs during printing
+     */
+    public String toString(DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.print(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * <pre>
+     *  out.writeByte(4);  // identifies this as a LocalTime
+     *  if (nano == 0) {
+     *    if (second == 0) {
+     *      if (minute == 0) {
+     *        out.writeByte(~hour);
+     *      } else {
+     *        out.writeByte(hour);
+     *        out.writeByte(~minute);
+     *      }
+     *    } else {
+     *      out.writeByte(hour);
+     *      out.writeByte(minute);
+     *      out.writeByte(~second);
+     *    }
+     *  } else {
+     *    out.writeByte(hour);
+     *    out.writeByte(minute);
+     *    out.writeByte(second);
+     *    out.writeInt(nano);
+     *  }
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.LOCAL_TIME_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     * @return never
+     * @throws InvalidObjectException always
+     */
+    private Object readResolve() throws ObjectStreamException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        if (nano == 0) {
+            if (second == 0) {
+                if (minute == 0) {
+                    out.writeByte(~hour);
+                } else {
+                    out.writeByte(hour);
+                    out.writeByte(~minute);
+                }
+            } else {
+                out.writeByte(hour);
+                out.writeByte(minute);
+                out.writeByte(~second);
+            }
+        } else {
+            out.writeByte(hour);
+            out.writeByte(minute);
+            out.writeByte(second);
+            out.writeInt(nano);
+        }
+    }
+
+    static LocalTime readExternal(DataInput in) throws IOException {
+        int hour = in.readByte();
+        int minute = 0;
+        int second = 0;
+        int nano = 0;
+        if (hour < 0) {
+            hour = ~hour;
+        } else {
+            minute = in.readByte();
+            if (minute < 0) {
+                minute = ~minute;
+            } else {
+                second = in.readByte();
+                if (second < 0) {
+                    second = ~second;
+                } else {
+                    nano = in.readInt();
+                }
+            }
+        }
+        return LocalTime.of(hour, minute, second, nano);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/Month.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,608 @@
+/*
+ * 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;
+
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoUnit.MONTHS;
+
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.TextStyle;
+import java.time.temporal.Chrono;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ISOChrono;
+import java.time.temporal.Queries;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.ValueRange;
+import java.util.Locale;
+
+/**
+ * A month-of-year, such as 'July'.
+ * <p>
+ * {@code Month} is an enum representing the 12 months of the year -
+ * January, February, March, April, May, June, July, August, September, October,
+ * November and December.
+ * <p>
+ * In addition to the textual enum name, each month-of-year has an {@code int} value.
+ * The {@code int} value follows normal usage and the ISO-8601 standard,
+ * from 1 (January) to 12 (December). It is recommended that applications use the enum
+ * rather than the {@code int} value to ensure code clarity.
+ * <p>
+ * <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code Month}.
+ * Use {@code getValue()} instead.</b>
+ * <p>
+ * This enum represents a common concept that is found in many calendar systems.
+ * As such, this enum may be used by any calendar system that has the month-of-year
+ * concept defined exactly equivalent to the ISO-8601 calendar system.
+ *
+ * <h3>Specification for implementors</h3>
+ * This is an immutable and thread-safe enum.
+ *
+ * @since 1.8
+ */
+public enum Month implements TemporalAccessor, TemporalAdjuster {
+
+    /**
+     * The singleton instance for the month of January with 31 days.
+     * This has the numeric value of {@code 1}.
+     */
+    JANUARY,
+    /**
+     * The singleton instance for the month of February with 28 days, or 29 in a leap year.
+     * This has the numeric value of {@code 2}.
+     */
+    FEBRUARY,
+    /**
+     * The singleton instance for the month of March with 31 days.
+     * This has the numeric value of {@code 3}.
+     */
+    MARCH,
+    /**
+     * The singleton instance for the month of April with 30 days.
+     * This has the numeric value of {@code 4}.
+     */
+    APRIL,
+    /**
+     * The singleton instance for the month of May with 31 days.
+     * This has the numeric value of {@code 5}.
+     */
+    MAY,
+    /**
+     * The singleton instance for the month of June with 30 days.
+     * This has the numeric value of {@code 6}.
+     */
+    JUNE,
+    /**
+     * The singleton instance for the month of July with 31 days.
+     * This has the numeric value of {@code 7}.
+     */
+    JULY,
+    /**
+     * The singleton instance for the month of August with 31 days.
+     * This has the numeric value of {@code 8}.
+     */
+    AUGUST,
+    /**
+     * The singleton instance for the month of September with 30 days.
+     * This has the numeric value of {@code 9}.
+     */
+    SEPTEMBER,
+    /**
+     * The singleton instance for the month of October with 31 days.
+     * This has the numeric value of {@code 10}.
+     */
+    OCTOBER,
+    /**
+     * The singleton instance for the month of November with 30 days.
+     * This has the numeric value of {@code 11}.
+     */
+    NOVEMBER,
+    /**
+     * The singleton instance for the month of December with 31 days.
+     * This has the numeric value of {@code 12}.
+     */
+    DECEMBER;
+    /**
+     * Private cache of all the constants.
+     */
+    private static final Month[] ENUMS = Month.values();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Month} from an {@code int} value.
+     * <p>
+     * {@code Month} is an enum representing the 12 months of the year.
+     * This factory allows the enum to be obtained from the {@code int} value.
+     * The {@code int} value follows the ISO-8601 standard, from 1 (January) to 12 (December).
+     *
+     * @param month  the month-of-year to represent, from 1 (January) to 12 (December)
+     * @return the month-of-year, not null
+     * @throws DateTimeException if the month-of-year is invalid
+     */
+    public static Month of(int month) {
+        if (month < 1 || month > 12) {
+            throw new DateTimeException("Invalid value for MonthOfYear: " + month);
+        }
+        return ENUMS[month - 1];
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Month} from a temporal object.
+     * <p>
+     * A {@code TemporalAccessor} represents some form of date and time information.
+     * This factory converts the arbitrary temporal object to an instance of {@code Month}.
+     * <p>
+     * The conversion extracts the {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} field.
+     * The extraction is only permitted if the temporal object has an ISO
+     * chronology, or can be converted to a {@code LocalDate}.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used in queries via method reference, {@code Month::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the month-of-year, not null
+     * @throws DateTimeException if unable to convert to a {@code Month}
+     */
+    public static Month from(TemporalAccessor temporal) {
+        if (temporal instanceof Month) {
+            return (Month) temporal;
+        }
+        try {
+            if (ISOChrono.INSTANCE.equals(Chrono.from(temporal)) == false) {
+                temporal = LocalDate.from(temporal);
+            }
+            return of(temporal.get(MONTH_OF_YEAR));
+        } catch (DateTimeException ex) {
+            throw new DateTimeException("Unable to obtain Month from TemporalAccessor: " + temporal.getClass(), ex);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the month-of-year {@code int} value.
+     * <p>
+     * The values are numbered following the ISO-8601 standard,
+     * from 1 (January) to 12 (December).
+     *
+     * @return the month-of-year, from 1 (January) to 12 (December)
+     */
+    public int getValue() {
+        return ordinal() + 1;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the textual representation, such as 'Jan' or 'December'.
+     * <p>
+     * This returns the textual name used to identify the month-of-year.
+     * The parameters control the length of the returned text and the locale.
+     * <p>
+     * If no textual mapping is found then the {@link #getValue() numeric value} is returned.
+     *
+     * @param style  the length of the text required, not null
+     * @param locale  the locale to use, not null
+     * @return the text value of the month-of-year, not null
+     */
+    public String getText(TextStyle style, Locale locale) {
+        return new DateTimeFormatterBuilder().appendText(MONTH_OF_YEAR, style).toFormatter(locale).print(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if this month-of-year can be queried for the specified field.
+     * If false, then calling the {@link #range(TemporalField) range} and
+     * {@link #get(TemporalField) get} methods will throw an exception.
+     * <p>
+     * If the field is {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} then
+     * this method returns true.
+     * All other {@code ChronoField} instances will return false.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the field is supported is determined by the field.
+     *
+     * @param field  the field to check, null returns false
+     * @return true if the field is supported on this month-of-year, false if not
+     */
+    @Override
+    public boolean isSupported(TemporalField field) {
+        if (field instanceof ChronoField) {
+            return field == MONTH_OF_YEAR;
+        }
+        return field != null && field.doIsSupported(this);
+    }
+
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * The range object expresses the minimum and maximum valid values for a field.
+     * This month is used to enhance the accuracy of the returned range.
+     * If it is not possible to return the range, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} then the
+     * range of the month-of-year, from 1 to 12, will be returned.
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the range can be obtained is determined by the field.
+     *
+     * @param field  the field to query the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     */
+    @Override
+    public ValueRange range(TemporalField field) {
+        if (field == MONTH_OF_YEAR) {
+            return field.range();
+        }
+        return TemporalAccessor.super.range(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this month-of-year as an {@code int}.
+     * <p>
+     * This queries this month for the value for the specified field.
+     * The returned value will always be within the valid range of values for the field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} then the
+     * value of the month-of-year, from 1 to 12, will be returned.
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * 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, 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
+    public int get(TemporalField field) {
+        if (field == MONTH_OF_YEAR) {
+            return getValue();
+        }
+        return TemporalAccessor.super.get(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this month-of-year as a {@code long}.
+     * <p>
+     * This queries this month for the value for the specified field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} then the
+     * value of the month-of-year, from 1 to 12, will be returned.
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * 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 == MONTH_OF_YEAR) {
+            return getValue();
+        } else if (field instanceof ChronoField) {
+            throw new DateTimeException("Unsupported field: " + field.getName());
+        }
+        return field.doGet(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns the month-of-year that is the specified number of quarters after this one.
+     * <p>
+     * The calculation rolls around the end of the year from December to January.
+     * The specified period may be negative.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param months  the months to add, positive or negative
+     * @return the resulting month, not null
+     */
+    public Month plus(long months) {
+        int amount = (int) (months % 12);
+        return ENUMS[(ordinal() + (amount + 12)) % 12];
+    }
+
+    /**
+     * Returns the month-of-year that is the specified number of months before this one.
+     * <p>
+     * The calculation rolls around the start of the year from January to December.
+     * The specified period may be negative.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param months  the months to subtract, positive or negative
+     * @return the resulting month, not null
+     */
+    public Month minus(long months) {
+        return plus(-(months % 12));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the length of this month in days.
+     * <p>
+     * This takes a flag to determine whether to return the length for a leap year or not.
+     * <p>
+     * February has 28 days in a standard year and 29 days in a leap year.
+     * April, June, September and November have 30 days.
+     * All other months have 31 days.
+     *
+     * @param leapYear  true if the length is required for a leap year
+     * @return the length of this month in days, from 28 to 31
+     */
+    public int length(boolean leapYear) {
+        switch (this) {
+            case FEBRUARY:
+                return (leapYear ? 29 : 28);
+            case APRIL:
+            case JUNE:
+            case SEPTEMBER:
+            case NOVEMBER:
+                return 30;
+            default:
+                return 31;
+        }
+    }
+
+    /**
+     * Gets the minimum length of this month in days.
+     * <p>
+     * February has a minimum length of 28 days.
+     * April, June, September and November have 30 days.
+     * All other months have 31 days.
+     *
+     * @return the minimum length of this month in days, from 28 to 31
+     */
+    public int minLength() {
+        switch (this) {
+            case FEBRUARY:
+                return 28;
+            case APRIL:
+            case JUNE:
+            case SEPTEMBER:
+            case NOVEMBER:
+                return 30;
+            default:
+                return 31;
+        }
+    }
+
+    /**
+     * Gets the maximum length of this month in days.
+     * <p>
+     * February has a maximum length of 29 days.
+     * April, June, September and November have 30 days.
+     * All other months have 31 days.
+     *
+     * @return the maximum length of this month in days, from 29 to 31
+     */
+    public int maxLength() {
+        switch (this) {
+            case FEBRUARY:
+                return 29;
+            case APRIL:
+            case JUNE:
+            case SEPTEMBER:
+            case NOVEMBER:
+                return 30;
+            default:
+                return 31;
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the day-of-year corresponding to the first day of this month.
+     * <p>
+     * This returns the day-of-year that this month begins on, using the leap
+     * year flag to determine the length of February.
+     *
+     * @param leapYear  true if the length is required for a leap year
+     * @return the day of year corresponding to the first day of this month, from 1 to 336
+     */
+    public int firstDayOfYear(boolean leapYear) {
+        int leap = leapYear ? 1 : 0;
+        switch (this) {
+            case JANUARY:
+                return 1;
+            case FEBRUARY:
+                return 32;
+            case MARCH:
+                return 60 + leap;
+            case APRIL:
+                return 91 + leap;
+            case MAY:
+                return 121 + leap;
+            case JUNE:
+                return 152 + leap;
+            case JULY:
+                return 182 + leap;
+            case AUGUST:
+                return 213 + leap;
+            case SEPTEMBER:
+                return 244 + leap;
+            case OCTOBER:
+                return 274 + leap;
+            case NOVEMBER:
+                return 305 + leap;
+            case DECEMBER:
+            default:
+                return 335 + leap;
+        }
+    }
+
+    /**
+     * Gets the month corresponding to the first month of this quarter.
+     * <p>
+     * The year can be divided into four quarters.
+     * This method returns the first month of the quarter for the base month.
+     * January, February and March return January.
+     * April, May and June return April.
+     * July, August and September return July.
+     * October, November and December return October.
+     *
+     * @return the first month of the quarter corresponding to this month, not null
+     */
+    public Month firstMonthOfQuarter() {
+        return ENUMS[(ordinal() / 3) * 3];
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this month-of-year using the specified query.
+     * <p>
+     * This queries this month-of-year using the specified query strategy object.
+     * The {@code TemporalQuery} object defines the logic to be used to
+     * obtain the result. Read the documentation of the query to understand
+     * what the result of this method will be.
+     * <p>
+     * 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 <R> 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> R query(TemporalQuery<R> query) {
+        if (query == Queries.chrono()) {
+            return (R) ISOChrono.INSTANCE;
+        } else if (query == Queries.precision()) {
+            return (R) MONTHS;
+        }
+        return TemporalAccessor.super.query(query);
+    }
+
+    /**
+     * Adjusts the specified temporal object to have this month-of-year.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with the month-of-year changed to be the same as this.
+     * <p>
+     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+     * passing {@link ChronoField#MONTH_OF_YEAR} as the field.
+     * If the specified temporal object does not use the ISO calendar system then
+     * a {@code DateTimeException} is thrown.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisMonth.adjustInto(temporal);
+     *   temporal = temporal.with(thisMonth);
+     * </pre>
+     * <p>
+     * For example, given a date in May, the following are output:
+     * <pre>
+     *   dateInMay.with(JANUARY);    // four months earlier
+     *   dateInMay.with(APRIL);      // one months earlier
+     *   dateInMay.with(MAY);        // same date
+     *   dateInMay.with(JUNE);       // one month later
+     *   dateInMay.with(DECEMBER);   // seven months later
+     * </pre>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param temporal  the target object to be adjusted, not null
+     * @return the adjusted object, not null
+     * @throws DateTimeException if unable to make the adjustment
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Temporal adjustInto(Temporal temporal) {
+        if (Chrono.from(temporal).equals(ISOChrono.INSTANCE) == false) {
+            throw new DateTimeException("Adjustment only supported on ISO date-time");
+        }
+        return temporal.with(MONTH_OF_YEAR, getValue());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/Period.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,1187 @@
+/*
+ * 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;
+
+import static java.time.LocalTime.NANOS_PER_DAY;
+import static java.time.LocalTime.NANOS_PER_HOUR;
+import static java.time.LocalTime.NANOS_PER_MINUTE;
+import static java.time.LocalTime.NANOS_PER_SECOND;
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.EPOCH_MONTH;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.NANO_OF_DAY;
+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.NANOS;
+import static java.time.temporal.ChronoUnit.YEARS;
+
+import java.io.Serializable;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.Chrono;
+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.TemporalUnit;
+import java.time.temporal.ValueRange;
+import java.util.Objects;
+
+/**
+ * A period of time, measured using the most common units, such as '3 Months, 4 Days and 7 Hours'.
+ * <p>
+ * A {@code Period} represents an amount of time measured in terms of the most commonly used units:
+ * <p><ul>
+ * <li>{@link ChronoUnit#YEARS YEARS}</li>
+ * <li>{@link ChronoUnit#MONTHS MONTHS}</li>
+ * <li>{@link ChronoUnit#DAYS DAYS}</li>
+ * <li>time units with an {@linkplain TemporalUnit#isDurationEstimated() exact duration}</li>
+ * </ul><p>
+ * The period may be used with any calendar system with the exception is methods with an "ISO" suffix.
+ * The meaning of a "year" or a "month" is only applied when the object is added to a date.
+ * <p>
+ * The period is modeled as a directed amount of time, meaning that individual parts of the
+ * period may be negative.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ * The maximum number of hours that can be stored is about 2.5 million, limited by storing
+ * a single {@code long} nanoseconds for all time units internally.
+ *
+ * @since 1.8
+ */
+public final class Period
+        implements TemporalAdder, TemporalSubtractor, Serializable {
+    // maximum hours is 2,562,047
+
+    /**
+     * A constant for a period of zero.
+     */
+    public static final Period ZERO = new Period(0, 0, 0, 0);
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -8290556941213247973L;
+
+    /**
+     * The number of years.
+     */
+    private final int years;
+    /**
+     * The number of months.
+     */
+    private final int months;
+    /**
+     * The number of days.
+     */
+    private final int days;
+    /**
+     * The number of nanoseconds.
+     */
+    private final long nanos;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a {@code Period} from date-based and time-based fields.
+     * <p>
+     * This creates an instance based on years, months, days, hours, minutes and seconds.
+     * Within a period, the time fields are always normalized.
+     *
+     * @param years  the amount of years, may be negative
+     * @param months  the amount of months, may be negative
+     * @param days  the amount of days, may be negative
+     * @param hours  the amount of hours, may be negative
+     * @param minutes  the amount of minutes, may be negative
+     * @param seconds  the amount of seconds, may be negative
+     * @return the period, not null
+     */
+    public static Period of(int years, int months, int days, int hours, int minutes, int seconds) {
+        return of(years, months, days, hours, minutes, seconds, 0);
+    }
+
+    /**
+     * Obtains a {@code Period} from date-based and time-based fields.
+     * <p>
+     * This creates an instance based on years, months, days, hours, minutes, seconds and nanoseconds.
+     * Within a period, the time fields are always normalized.
+     *
+     * @param years  the amount of years, may be negative
+     * @param months  the amount of months, may be negative
+     * @param days  the amount of days, may be negative
+     * @param hours  the amount of hours, may be negative
+     * @param minutes  the amount of minutes, may be negative
+     * @param seconds  the amount of seconds, may be negative
+     * @param nanos  the amount of nanos, may be negative
+     * @return the period, not null
+     */
+    public static Period of(int years, int months, int days, int hours, int minutes, int seconds, long nanos) {
+        if ((years | months | days | hours | minutes | seconds | nanos) == 0) {
+            return ZERO;
+        }
+        long totSecs = Math.addExact(hours * 3600L, minutes * 60L) + seconds;
+        long totNanos = Math.addExact(Math.multiplyExact(totSecs, 1_000_000_000L), nanos);
+        return create(years, months, days, totNanos);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a {@code Period} from date-based fields.
+     * <p>
+     * This creates an instance based on years, months and days.
+     *
+     * @param years  the amount of years, may be negative
+     * @param months  the amount of months, may be negative
+     * @param days  the amount of days, may be negative
+     * @return the period, not null
+     */
+    public static Period ofDate(int years, int months, int days) {
+        return of(years, months, days, 0, 0, 0, 0);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a {@code Period} from time-based fields.
+     * <p>
+     * This creates an instance based on hours, minutes and seconds.
+     * Within a period, the time fields are always normalized.
+     *
+     * @param hours  the amount of hours, may be negative
+     * @param minutes  the amount of minutes, may be negative
+     * @param seconds  the amount of seconds, may be negative
+     * @return the period, not null
+     */
+    public static Period ofTime(int hours, int minutes, int seconds) {
+        return of(0, 0, 0, hours, minutes, seconds, 0);
+    }
+
+    /**
+     * Obtains a {@code Period} from time-based fields.
+     * <p>
+     * This creates an instance based on hours, minutes, seconds and nanoseconds.
+     * Within a period, the time fields are always normalized.
+     *
+     * @param hours  the amount of hours, may be negative
+     * @param minutes  the amount of minutes, may be negative
+     * @param seconds  the amount of seconds, may be negative
+     * @param nanos  the amount of nanos, may be negative
+     * @return the period, not null
+     */
+    public static Period ofTime(int hours, int minutes, int seconds, long nanos) {
+        return of(0, 0, 0, hours, minutes, seconds, nanos);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Period} from a period in the specified unit.
+     * <p>
+     * The parameters represent the two parts of a phrase like '6 Days'. For example:
+     * <pre>
+     *  Period.of(3, SECONDS);
+     *  Period.of(5, YEARS);
+     * </pre>
+     * The specified unit must be one of the supported units from {@link ChronoUnit},
+     * {@code YEARS}, {@code MONTHS} or {@code DAYS} or be a time unit with an
+     * {@linkplain TemporalUnit#isDurationEstimated() exact duration}.
+     * Other units throw an exception.
+     *
+     * @param amount  the amount of the period, measured in terms of the unit, positive or negative
+     * @param unit  the unit that the period is measured in, must have an exact duration, not null
+     * @return the period, not null
+     * @throws DateTimeException if the period unit is invalid
+     * @throws ArithmeticException if a numeric overflow occurs
+     */
+    public static Period of(long amount, TemporalUnit unit) {
+        return ZERO.plus(amount, unit);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a {@code Period} from a {@code Duration}.
+     * <p>
+     * This converts the duration to a period.
+     * Within a period, the time fields are always normalized.
+     * The years, months and days fields will be zero.
+     * <p>
+     * To populate the days field, call {@link #normalizedHoursToDays()} on the created period.
+     *
+     * @param duration  the duration to convert, not null
+     * @return the period, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public static Period of(Duration duration) {
+        Objects.requireNonNull(duration, "duration");
+        if (duration.isZero()) {
+            return ZERO;
+        }
+        return new Period(0, 0, 0, duration.toNanos());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a {@code Period} consisting of the number of years, months, days,
+     * hours, minutes, seconds, and nanoseconds between two {@code TemporalAccessor} instances.
+     * <p>
+     * The start date is included, but the end date is not. Only whole years count.
+     * For example, from {@code 2010-01-15} to {@code 2011-03-18} is one year, two months and three days.
+     * <p>
+     * This method examines the {@link ChronoField fields} {@code YEAR}, {@code MONTH_OF_YEAR},
+     * {@code DAY_OF_MONTH} and {@code NANO_OF_DAY}
+     * The difference between each of the fields is calculated independently from the others.
+     * At least one of the four fields must be present.
+     * <p>
+     * The four units are typically retained without normalization.
+     * However, years and months are normalized if the range of months is fixed, as it is with ISO.
+     * <p>
+     * The result of this method can be a negative period if the end is before the start.
+     * The negative sign can be different in each of the four major units.
+     *
+     * @param start  the start date, inclusive, not null
+     * @param end  the end date, exclusive, not null
+     * @return the period between the date-times, not null
+     * @throws DateTimeException if the two date-times do have similar available fields
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public static Period between(TemporalAccessor start, TemporalAccessor end) {
+        if (Chrono.from(start).equals(Chrono.from(end)) == false) {
+            throw new DateTimeException("Unable to calculate period as date-times have different chronologies");
+        }
+        int years = 0;
+        int months = 0;
+        int days = 0;
+        long nanos = 0;
+        boolean valid = false;
+        if (start.isSupported(YEAR)) {
+            years = Math.toIntExact(Math.subtractExact(end.getLong(YEAR), start.getLong(YEAR)));
+            valid = true;
+        }
+        if (start.isSupported(MONTH_OF_YEAR)) {
+            months = Math.toIntExact(Math.subtractExact(end.getLong(MONTH_OF_YEAR), start.getLong(MONTH_OF_YEAR)));
+            ValueRange startRange = Chrono.from(start).range(MONTH_OF_YEAR);
+            ValueRange endRange = Chrono.from(end).range(MONTH_OF_YEAR);
+            if (startRange.isFixed() && startRange.isIntValue() && startRange.equals(endRange)) {
+                int monthCount = (int) (startRange.getMaximum() - startRange.getMinimum() + 1);
+                long totMonths = ((long) months) + years * monthCount;
+                months = (int) (totMonths % monthCount);
+                years = Math.toIntExact(totMonths / monthCount);
+            }
+            valid = true;
+        }
+        if (start.isSupported(DAY_OF_MONTH)) {
+            days = Math.toIntExact(Math.subtractExact(end.getLong(DAY_OF_MONTH), start.getLong(DAY_OF_MONTH)));
+            valid = true;
+        }
+        if (start.isSupported(NANO_OF_DAY)) {
+            nanos = Math.subtractExact(end.getLong(NANO_OF_DAY), start.getLong(NANO_OF_DAY));
+            valid = true;
+        }
+        if (valid == false) {
+            throw new DateTimeException("Unable to calculate period as date-times do not have any valid fields");
+        }
+        return create(years, months, days, nanos);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a {@code Period} consisting of the number of years, months,
+     * and days between two dates.
+     * <p>
+     * The start date is included, but the end date is not.
+     * The period is calculated by removing complete months, then calculating
+     * the remaining number of days, adjusting to ensure that both have the same sign.
+     * The number of months is then split into years and months based on a 12 month year.
+     * A month is considered if the end day-of-month is greater than or equal to the start day-of-month.
+     * For example, from {@code 2010-01-15} to {@code 2011-03-18} is one year, two months and three days.
+     * <p>
+     * The result of this method can be a negative period if the end is before the start.
+     * The negative sign will be the same in each of year, month and day.
+     *
+     * @param startDate  the start date, inclusive, not null
+     * @param endDate  the end date, exclusive, not null
+     * @return the period between the dates, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public static Period betweenISO(LocalDate startDate, LocalDate endDate) {
+        long startMonth = startDate.getLong(EPOCH_MONTH);
+        long endMonth = endDate.getLong(EPOCH_MONTH);
+        long totalMonths = endMonth - startMonth;  // safe
+        int days = endDate.getDayOfMonth() - startDate.getDayOfMonth();
+        if (totalMonths > 0 && days < 0) {
+            totalMonths--;
+            LocalDate calcDate = startDate.plusMonths(totalMonths);
+            days = (int) (endDate.toEpochDay() - calcDate.toEpochDay());  // safe
+        } else if (totalMonths < 0 && days > 0) {
+            totalMonths++;
+            days -= endDate.lengthOfMonth();
+        }
+        long years = totalMonths / 12;  // safe
+        int months = (int) (totalMonths % 12);  // safe
+        return ofDate(Math.toIntExact(years), months, days);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a {@code Period} consisting of the number of hours, minutes,
+     * seconds and nanoseconds between two times.
+     * <p>
+     * The start time is included, but the end time is not.
+     * The period is calculated from the difference between the nano-of-day values
+     * of the two times. For example, from {@code 13:45:00} to {@code 14:50:30.123456789}
+     * is {@code P1H5M30.123456789S}.
+     * <p>
+     * The result of this method can be a negative period if the end is before the start.
+     *
+     * @param startTime  the start time, inclusive, not null
+     * @param endTime  the end time, exclusive, not null
+     * @return the period between the times, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public static Period betweenISO(LocalTime startTime, LocalTime endTime) {
+        return create(0, 0, 0, endTime.toNanoOfDay() - startTime.toNanoOfDay());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a {@code Period} from a text string such as {@code PnYnMnDTnHnMn.nS}.
+     * <p>
+     * This will parse the string produced by {@code toString()} which is
+     * a subset of the ISO-8601 period format {@code PnYnMnDTnHnMn.nS}.
+     * <p>
+     * The string consists of a series of numbers with a suffix identifying their meaning.
+     * The values, and suffixes, must be in the sequence year, month, day, hour, minute, second.
+     * Any of the number/suffix pairs may be omitted providing at least one is present.
+     * If the period is zero, the value is normally represented as {@code PT0S}.
+     * The numbers must consist of ASCII digits.
+     * Any of the numbers may be negative. Negative zero is not accepted.
+     * The number of nanoseconds is expressed as an optional fraction of the seconds.
+     * 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 will all be accepted in upper or lower case.
+     * The decimal point may be either a dot or a comma.
+     *
+     * @param text  the text to parse, not null
+     * @return the parsed period, not null
+     * @throws DateTimeParseException if the text cannot be parsed to a period
+     */
+    public static Period parse(final CharSequence text) {
+        Objects.requireNonNull(text, "text");
+        return new PeriodParser(text).parse();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Creates an instance.
+     *
+     * @param years  the amount
+     * @param months  the amount
+     * @param days  the amount
+     * @param nanos  the amount
+     */
+    private static Period create(int years, int months, int days, long nanos) {
+        if ((years | months | days | nanos) == 0) {
+            return ZERO;
+        }
+        return new Period(years, months, days, nanos);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param years  the amount
+     * @param months  the amount
+     * @param days  the amount
+     * @param nanos  the amount
+     */
+    private Period(int years, int months, int days, long nanos) {
+        this.years = years;
+        this.months = months;
+        this.days = days;
+        this.nanos = nanos;
+    }
+
+    /**
+     * Resolves singletons.
+     *
+     * @return the resolved instance
+     */
+    private Object readResolve() {
+        if ((years | months | days | nanos) == 0) {
+            return ZERO;
+        }
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this period is zero-length.
+     *
+     * @return true if this period is zero-length
+     */
+    public boolean isZero() {
+        return (this == ZERO);
+    }
+
+    /**
+     * Checks if this period is fully positive, excluding zero.
+     * <p>
+     * This checks whether all the amounts in the period are positive,
+     * defined as greater than zero.
+     *
+     * @return true if this period is fully positive excluding zero
+     */
+    public boolean isPositive() {
+        return ((years | months | days | nanos) > 0);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the amount of years of this period.
+     *
+     * @return the amount of years of this period
+     */
+    public int getYears() {
+        return years;
+    }
+
+    /**
+     * Gets the amount of months of this period.
+     *
+     * @return the amount of months of this period
+     */
+    public int getMonths() {
+        return months;
+    }
+
+    /**
+     * Gets the amount of days of this period.
+     *
+     * @return the amount of days of this period
+     */
+    public int getDays() {
+        return days;
+    }
+
+    /**
+     * Gets the amount of hours of this period.
+     * <p>
+     * Within a period, the time fields are always normalized.
+     *
+     * @return the amount of hours of this period
+     */
+    public int getHours() {
+        return (int) (nanos / NANOS_PER_HOUR);
+    }
+
+    /**
+     * Gets the amount of minutes within an hour of this period.
+     * <p>
+     * Within a period, the time fields are always normalized.
+     *
+     * @return the amount of minutes within an hour of this period
+     */
+    public int getMinutes() {
+        return (int) ((nanos / NANOS_PER_MINUTE) % 60);
+    }
+
+    /**
+     * Gets the amount of seconds within a minute of this period.
+     * <p>
+     * Within a period, the time fields are always normalized.
+     *
+     * @return the amount of seconds within a minute of this period
+     */
+    public int getSeconds() {
+        return (int) ((nanos / NANOS_PER_SECOND) % 60);
+    }
+
+    /**
+     * Gets the amount of nanoseconds within a second of this period.
+     * <p>
+     * Within a period, the time fields are always normalized.
+     *
+     * @return the amount of nanoseconds within a second of this period
+     */
+    public int getNanos() {
+        return (int) (nanos % NANOS_PER_SECOND);  // safe from overflow
+    }
+
+    /**
+     * Gets the total amount of the time units of this period, measured in nanoseconds.
+     * <p>
+     * Within a period, the time fields are always normalized.
+     *
+     * @return the total amount of time unit nanoseconds of this period
+     */
+    public long getTimeNanos() {
+        return nanos;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this period with the specified amount of years.
+     * <p>
+     * This method will only affect the years field.
+     * All other units are unaffected.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param years  the years to represent
+     * @return a {@code Period} based on this period with the requested years, not null
+     */
+    public Period withYears(int years) {
+        if (years == this.years) {
+            return this;
+        }
+        return create(years, months, days, nanos);
+    }
+
+    /**
+     * Returns a copy of this period with the specified amount of months.
+     * <p>
+     * This method will only affect the months field.
+     * All other units are unaffected.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param months  the months to represent
+     * @return a {@code Period} based on this period with the requested months, not null
+     */
+    public Period withMonths(int months) {
+        if (months == this.months) {
+            return this;
+        }
+        return create(years, months, days, nanos);
+    }
+
+    /**
+     * Returns a copy of this period with the specified amount of days.
+     * <p>
+     * This method will only affect the days field.
+     * All other units are unaffected.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param days  the days to represent
+     * @return a {@code Period} based on this period with the requested days, not null
+     */
+    public Period withDays(int days) {
+        if (days == this.days) {
+            return this;
+        }
+        return create(years, months, days, nanos);
+    }
+
+    /**
+     * Returns a copy of this period with the specified total amount of time units
+     * expressed in nanoseconds.
+     * <p>
+     * Within a period, the time fields are always normalized.
+     * This method will affect all the time units - hours, minutes, seconds and nanos.
+     * The date units are unaffected.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanos  the nanoseconds to represent
+     * @return a {@code Period} based on this period with the requested nanoseconds, not null
+     */
+    public Period withTimeNanos(long nanos) {
+        if (nanos == this.nanos) {
+            return this;
+        }
+        return create(years, months, days, nanos);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this period with the specified period added.
+     * <p>
+     * This operates separately on the years, months, days and the normalized time.
+     * There is no further normalization beyond the normalized time.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param other  the period to add, not null
+     * @return a {@code Period} based on this period with the requested period added, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Period plus(Period other) {
+        return create(
+                Math.addExact(years, other.years),
+                Math.addExact(months, other.months),
+                Math.addExact(days, other.days),
+                Math.addExact(nanos, other.nanos));
+    }
+
+    /**
+     * Returns a copy of this period with the specified period added.
+     * <p>
+     * The specified unit must be one of the supported units from {@link ChronoUnit},
+     * {@code YEARS}, {@code MONTHS} or {@code DAYS} or be a time unit with an
+     * {@linkplain TemporalUnit#isDurationEstimated() exact duration}.
+     * Other units throw an exception.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amount  the amount to add, positive or negative
+     * @param unit  the unit that the amount is expressed in, not null
+     * @return a {@code Period} based on this period with the requested amount added, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Period plus(long amount, TemporalUnit unit) {
+        Objects.requireNonNull(unit, "unit");
+        if (unit instanceof ChronoUnit) {
+            if (unit == YEARS || unit == MONTHS || unit == DAYS || unit.isDurationEstimated() == false) {
+                if (amount == 0) {
+                    return this;
+                }
+                switch((ChronoUnit) unit) {
+                    case NANOS: return plusNanos(amount);
+                    case MICROS: return plusNanos(Math.multiplyExact(amount, 1000L));
+                    case MILLIS: return plusNanos(Math.multiplyExact(amount, 1000_000L));
+                    case SECONDS: return plusSeconds(amount);
+                    case MINUTES: return plusMinutes(amount);
+                    case HOURS: return plusHours(amount);
+                    case HALF_DAYS: return plusNanos(Math.multiplyExact(amount, 12 * NANOS_PER_HOUR));
+                    case DAYS: return plusDays(amount);
+                    case MONTHS: return plusMonths(amount);
+                    case YEARS: return plusYears(amount);
+                    default: throw new DateTimeException("Unsupported unit: " + unit.getName());
+                }
+            }
+        }
+        if (unit.isDurationEstimated()) {
+            throw new DateTimeException("Unsupported unit: " + unit.getName());
+        }
+        return plusNanos(Duration.of(amount, unit).toNanos());
+    }
+
+    public Period plusYears(long amount) {
+        return create(Math.toIntExact(Math.addExact(years, amount)), months, days, nanos);
+    }
+
+    public Period plusMonths(long amount) {
+        return create(years, Math.toIntExact(Math.addExact(months, amount)), days, nanos);
+    }
+
+    public Period plusDays(long amount) {
+        return create(years, months, Math.toIntExact(Math.addExact(days, amount)), nanos);
+    }
+
+    public Period plusHours(long amount) {
+        return plusNanos(Math.multiplyExact(amount, NANOS_PER_HOUR));
+    }
+
+    public Period plusMinutes(long amount) {
+        return plusNanos(Math.multiplyExact(amount, NANOS_PER_MINUTE));
+    }
+
+    public Period plusSeconds(long amount) {
+        return plusNanos(Math.multiplyExact(amount, NANOS_PER_SECOND));
+    }
+
+    public Period plusNanos(long amount) {
+        return create(years, months, days, Math.addExact(nanos,  amount));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this period with the specified period subtracted.
+     * <p>
+     * This operates separately on the years, months, days and the normalized time.
+     * There is no further normalization beyond the normalized time.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param other  the period to subtract, not null
+     * @return a {@code Period} based on this period with the requested period subtracted, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Period minus(Period other) {
+        return create(
+                Math.subtractExact(years, other.years),
+                Math.subtractExact(months, other.months),
+                Math.subtractExact(days, other.days),
+                Math.subtractExact(nanos, other.nanos));
+    }
+
+    /**
+     * Returns a copy of this period with the specified period subtracted.
+     * <p>
+     * The specified unit must be one of the supported units from {@link ChronoUnit},
+     * {@code YEARS}, {@code MONTHS} or {@code DAYS} or be a time unit with an
+     * {@linkplain TemporalUnit#isDurationEstimated() exact duration}.
+     * Other units throw an exception.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amount  the amount to subtract, positive or negative
+     * @param unit  the unit that the amount is expressed in, not null
+     * @return a {@code Period} based on this period with the requested amount subtracted, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Period minus(long amount, TemporalUnit unit) {
+        return (amount == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amount, unit));
+    }
+
+    public Period minusYears(long amount) {
+        return (amount == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-amount));
+    }
+
+    public Period minusMonths(long amount) {
+        return (amount == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-amount));
+    }
+
+    public Period minusDays(long amount) {
+        return (amount == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-amount));
+    }
+
+    public Period minusHours(long amount) {
+        return (amount == Long.MIN_VALUE ? plusHours(Long.MAX_VALUE).plusHours(1) : plusHours(-amount));
+    }
+
+    public Period minusMinutes(long amount) {
+        return (amount == Long.MIN_VALUE ? plusMinutes(Long.MAX_VALUE).plusMinutes(1) : plusMinutes(-amount));
+    }
+
+    public Period minusSeconds(long amount) {
+        return (amount == Long.MIN_VALUE ? plusSeconds(Long.MAX_VALUE).plusSeconds(1) : plusSeconds(-amount));
+    }
+
+    public Period minusNanos(long amount) {
+        return (amount == Long.MIN_VALUE ? plusNanos(Long.MAX_VALUE).plusNanos(1) : plusNanos(-amount));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a new instance with each element in this period multiplied
+     * by the specified scalar.
+     * <p>
+     * This simply multiplies each field, years, months, days and normalized time,
+     * by the scalar. No normalization is performed.
+     *
+     * @param scalar  the scalar to multiply by, not null
+     * @return a {@code Period} based on this period with the amounts multiplied by the scalar, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Period multipliedBy(int scalar) {
+        if (this == ZERO || scalar == 1) {
+            return this;
+        }
+        return create(
+                Math.multiplyExact(years, scalar),
+                Math.multiplyExact(months, scalar),
+                Math.multiplyExact(days, scalar),
+                Math.multiplyExact(nanos, scalar));
+    }
+
+    /**
+     * Returns a new instance with each amount in this period negated.
+     *
+     * @return a {@code Period} based on this period with the amounts negated, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Period negated() {
+        return multipliedBy(-1);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this period with the days and hours normalized using a 24 hour day.
+     * <p>
+     * This normalizes the days and hours units, leaving years and months unchanged.
+     * The hours unit is adjusted to have an absolute value less than 23,
+     * with the days unit being adjusted to compensate.
+     * For example, a period of {@code P1DT27H} will be normalized to {@code P2DT3H}.
+     * <p>
+     * The sign of the days and hours units will be the same after normalization.
+     * For example, a period of {@code P1DT-51H} will be normalized to {@code P-1DT-3H}.
+     * Since all time units are always normalized, if the hours units changes sign then
+     * other time units will also be affected.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @return a {@code Period} based on this period with excess hours normalized to days, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Period normalizedHoursToDays() {
+        // logic uses if statements to normalize signs to avoid unnecessary overflows
+        long totalDays = (nanos / NANOS_PER_DAY) + days;  // no overflow
+        long splitNanos = nanos % NANOS_PER_DAY;
+        if (totalDays > 0 && splitNanos < 0) {
+            splitNanos += NANOS_PER_DAY;
+            totalDays--;
+        } else if (totalDays < 0 && splitNanos > 0) {
+            splitNanos -= NANOS_PER_DAY;
+            totalDays++;
+        }
+        if (totalDays == days && splitNanos == nanos) {
+            return this;
+        }
+        return create(years, months, Math.toIntExact(totalDays), splitNanos);
+    }
+
+    /**
+     * Returns a copy of this period with any days converted to hours using a 24 hour day.
+     * <p>
+     * The days unit is reduced to zero, with the hours unit increased by 24 times the
+     * days unit to compensate. Other units are unaffected.
+     * For example, a period of {@code P2DT4H} will be normalized to {@code PT52H}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @return a {@code Period} based on this period with days normalized to hours, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Period normalizedDaysToHours() {
+        if (days == 0) {
+            return this;
+        }
+        return create(years, months, 0, Math.addExact(Math.multiplyExact(days, NANOS_PER_DAY), nanos));
+    }
+
+    /**
+     * Returns a copy of this period with the years and months normalized using a 12 month year.
+     * <p>
+     * This normalizes the years and months units, leaving other units unchanged.
+     * The months unit is adjusted to have an absolute value less than 11,
+     * with the years unit being adjusted to compensate.
+     * For example, a period of {@code P1Y15M} will be normalized to {@code P2Y3M}.
+     * <p>
+     * The sign of the years and months units will be the same after normalization.
+     * For example, a period of {@code P1Y-25M} will be normalized to {@code P-1Y-1M}.
+     * <p>
+     * This normalization uses a 12 month year it is not valid for all calendar systems.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @return a {@code Period} based on this period with years and months normalized, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Period normalizedMonthsISO() {
+        long totalMonths = years * 12L + months;  // no overflow
+        long splitYears = totalMonths / 12;
+        int splitMonths = (int) (totalMonths % 12);  // no overflow
+        if (splitYears == years && splitMonths == months) {
+            return this;
+        }
+        return create(Math.toIntExact(splitYears), splitMonths, days, nanos);
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Converts this period to one that only has date units.
+     * <p>
+     * The resulting period will have the same years, months and days as this period
+     * but the time units will all be zero. No normalization occurs in the calculation.
+     * For example, a period of {@code P1Y3MT12H} will be converted to {@code P1Y3M}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @return a {@code Period} based on this period with the time units set to zero, not null
+     */
+    public Period toDateOnly() {
+        if (nanos == 0) {
+            return this;
+        }
+        return create(years, months, days, 0);
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Adds this period to the specified temporal object.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with this period added.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#plus(TemporalAdder)}.
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   dateTime = thisPeriod.addTo(dateTime);
+     *   dateTime = dateTime.plus(thisPeriod);
+     * </pre>
+     * <p>
+     * The calculation will add the years, then months, then days, then nanos.
+     * Only non-zero amounts will be added.
+     * If the date-time has a calendar system with a fixed number of months in a
+     * year, then the years and months will be combined before being added.
+     * <p>
+     * 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) {
+        Objects.requireNonNull(temporal, "temporal");
+        if ((years | months) != 0) {
+            ValueRange startRange = Chrono.from(temporal).range(MONTH_OF_YEAR);
+            if (startRange.isFixed() && startRange.isIntValue()) {
+                long monthCount = startRange.getMaximum() - startRange.getMinimum() + 1;
+                temporal = temporal.plus(years * monthCount + months, MONTHS);
+            } else {
+                if (years != 0) {
+                    temporal = temporal.plus(years, YEARS);
+                }
+                if (months != 0) {
+                    temporal = temporal.plus(months, MONTHS);
+                }
+            }
+        }
+        if (days != 0) {
+            temporal = temporal.plus(days, DAYS);
+        }
+        if (nanos != 0) {
+            temporal = temporal.plus(nanos, NANOS);
+        }
+        return temporal;
+    }
+
+    /**
+     * Subtracts this period from the specified temporal object.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with this period subtracted.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#minus(TemporalSubtractor)}.
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   dateTime = thisPeriod.subtractFrom(dateTime);
+     *   dateTime = dateTime.minus(thisPeriod);
+     * </pre>
+     * <p>
+     * The calculation will subtract the years, then months, then days, then nanos.
+     * Only non-zero amounts will be subtracted.
+     * If the date-time has a calendar system with a fixed number of months in a
+     * year, then the years and months will be combined before being subtracted.
+     * <p>
+     * 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) {
+        Objects.requireNonNull(temporal, "temporal");
+        if ((years | months) != 0) {
+            ValueRange startRange = Chrono.from(temporal).range(MONTH_OF_YEAR);
+            if (startRange.isFixed() && startRange.isIntValue()) {
+                long monthCount = startRange.getMaximum() - startRange.getMinimum() + 1;
+                temporal = temporal.minus(years * monthCount + months, MONTHS);
+            } else {
+                if (years != 0) {
+                    temporal = temporal.minus(years, YEARS);
+                }
+                if (months != 0) {
+                    temporal = temporal.minus(months, MONTHS);
+                }
+            }
+        }
+        if (days != 0) {
+            temporal = temporal.minus(days, DAYS);
+        }
+        if (nanos != 0) {
+            temporal = temporal.minus(nanos, NANOS);
+        }
+        return temporal;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Converts this period to one that only has time units.
+     * <p>
+     * The resulting period will have the same time units as this period
+     * but the date units will all be zero. No normalization occurs in the calculation.
+     * For example, a period of {@code P1Y3MT12H} will be converted to {@code PT12H}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @return a {@code Period} based on this period with the date units set to zero, not null
+     */
+    public Period toTimeOnly() {
+        if ((years | months | days) == 0) {
+            return this;
+        }
+        return create(0, 0, 0, nanos);
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Calculates the duration of this period.
+     * <p>
+     * The calculation uses the hours, minutes, seconds and nanoseconds fields.
+     * If years, months or days are present an exception is thrown.
+     * See {@link #toTimeOnly()} for a way to remove the date units and
+     * {@link #normalizedDaysToHours()} for a way to convert days to hours.
+     *
+     * @return a {@code Duration} equivalent to this period, not null
+     * @throws DateTimeException if the period cannot be converted as it contains years, months or days
+     */
+    public Duration toDuration() {
+        if ((years | months | days) != 0) {
+            throw new DateTimeException("Unable to convert period to duration as years/months/days are present: " + this);
+        }
+        return Duration.ofNanos(nanos);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this period is equal to another period.
+     * <p>
+     * The comparison is based on the amounts held in the period.
+     * To be equal, the years, months, days and normalized time fields must be equal.
+     *
+     * @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 Period) {
+            Period other = (Period) obj;
+            return years == other.years && months == other.months &&
+                    days == other.days && nanos == other.nanos;
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this period.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        // ordered such that overflow from one field doesn't immediately affect the next field
+        return ((years << 27) | (years >>> 5)) ^
+                ((days << 21) | (days >>> 11)) ^
+                ((months << 17) | (months >>> 15)) ^
+                ((int) (nanos ^ (nanos >>> 32)));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this period as a {@code String}, such as {@code P6Y3M1DT12H}.
+     * <p>
+     * The output will be in the ISO-8601 period format.
+     *
+     * @return a string representation of this period, not null
+     */
+    @Override
+    public String toString() {
+        if (this == ZERO) {
+            return "PT0S";
+        } else {
+            StringBuilder buf = new StringBuilder();
+            buf.append('P');
+            if (years != 0) {
+                buf.append(years).append('Y');
+            }
+            if (months != 0) {
+                buf.append(months).append('M');
+            }
+            if (days != 0) {
+                buf.append(days).append('D');
+            }
+            if (nanos != 0) {
+                buf.append('T');
+                if (getHours() != 0) {
+                    buf.append(getHours()).append('H');
+                }
+                if (getMinutes() != 0) {
+                    buf.append(getMinutes()).append('M');
+                }
+                int secondPart = getSeconds();
+                int nanoPart = getNanos();
+                int secsNanosOr = secondPart | nanoPart;
+                if (secsNanosOr != 0) {  // if either non-zero
+                    if ((secsNanosOr & Integer.MIN_VALUE) != 0) {  // if either less than zero
+                        buf.append('-');
+                        secondPart = Math.abs(secondPart);
+                        nanoPart = Math.abs(nanoPart);
+                    }
+                    buf.append(secondPart);
+                    if (nanoPart != 0) {
+                        int dotPos = buf.length();
+                        nanoPart += 1000_000_000;
+                        while (nanoPart % 10 == 0) {
+                            nanoPart /= 10;
+                        }
+                        buf.append(nanoPart);
+                        buf.setCharAt(dotPos, '.');
+                    }
+                    buf.append('S');
+                }
+            }
+            return buf.toString();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/PeriodParser.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import java.time.format.DateTimeParseException;
+
+/**
+ * A period parser that creates an instance of {@code Period} from a string.
+ * This parses the ISO-8601 period format {@code PnYnMnDTnHnMn.nS}.
+ * <p>
+ * This class is mutable and intended for use by a single thread.
+ *
+ * @since 1.8
+ */
+final class PeriodParser {
+
+    /**
+     * Used to validate the correct sequence of tokens.
+     */
+    private static final String TOKEN_SEQUENCE = "PYMDTHMS";
+    /**
+     * The standard string representing a zero period.
+     */
+    private static final String ZERO = "PT0S";
+
+    /**
+     * The number of years.
+     */
+    private int years;
+    /**
+     * The number of months.
+     */
+    private int months;
+    /**
+     * The number of days.
+     */
+    private int days;
+    /**
+     * The number of hours.
+     */
+    private int hours;
+    /**
+     * The number of minutes.
+     */
+    private int minutes;
+    /**
+     * The number of seconds.
+     */
+    private int seconds;
+    /**
+     * The number of nanoseconds.
+     */
+    private long nanos;
+    /**
+     * Whether the seconds were negative.
+     */
+    private boolean negativeSecs;
+    /**
+     * Parser position index.
+     */
+    private int index;
+    /**
+     * Original text.
+     */
+    private CharSequence text;
+
+    /**
+     * Constructor.
+     *
+     * @param text  the text to parse, not null
+     */
+    PeriodParser(CharSequence text) {
+        this.text = text;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Performs the parse.
+     * <p>
+     * This parses the text set in the constructor in the format PnYnMnDTnHnMn.nS.
+     *
+     * @return the created Period, not null
+     * @throws DateTimeParseException if the text cannot be parsed to a Period
+     */
+    Period parse() {
+        // force to upper case and coerce the comma to dot
+
+        String s = text.toString().toUpperCase().replace(',', '.');
+        // check for zero and skip parse
+        if (ZERO.equals(s)) {
+            return Period.ZERO;
+        }
+        if (s.length() < 3 || s.charAt(0) != 'P') {
+            throw new DateTimeParseException("Period could not be parsed: " + text, text, 0);
+        }
+        validateCharactersAndOrdering(s, text);
+
+        // strip off the leading P
+        String[] datetime = s.substring(1).split("T");
+        switch (datetime.length) {
+            case 2:
+                parseDate(datetime[0], 1);
+                parseTime(datetime[1], datetime[0].length() + 2);
+                break;
+            case 1:
+                parseDate(datetime[0], 1);
+                break;
+        }
+        return toPeriod();
+    }
+
+    private void parseDate(String s, int baseIndex) {
+        index = 0;
+        while (index < s.length()) {
+            String value = parseNumber(s);
+            if (index < s.length()) {
+                char c = s.charAt(index);
+                switch(c) {
+                    case 'Y': years = parseInt(value, baseIndex) ; break;
+                    case 'M': months = parseInt(value, baseIndex) ; break;
+                    case 'D': days = parseInt(value, baseIndex) ; break;
+                    default:
+                        throw new DateTimeParseException("Period could not be parsed, unrecognized letter '" +
+                                c + ": " + text, text, baseIndex + index);
+                }
+                index++;
+            }
+        }
+    }
+
+    private void parseTime(String s, int baseIndex) {
+        index = 0;
+        s = prepareTime(s, baseIndex);
+        while (index < s.length()) {
+            String value = parseNumber(s);
+            if (index < s.length()) {
+                char c = s.charAt(index);
+                switch(c) {
+                    case 'H': hours = parseInt(value, baseIndex) ; break;
+                    case 'M': minutes = parseInt(value, baseIndex) ; break;
+                    case 'S': seconds = parseInt(value, baseIndex) ; break;
+                    case 'N': nanos = parseNanos(value, baseIndex); break;
+                    default:
+                        throw new DateTimeParseException("Period could not be parsed, unrecognized letter '" +
+                                c + "': " + text, text, baseIndex + index);
+                }
+                index++;
+            }
+        }
+    }
+
+    private long parseNanos(String s, int baseIndex) {
+        if (s.length() > 9) {
+            throw new DateTimeParseException("Period could not be parsed, nanosecond range exceeded: " +
+                    text, text, baseIndex + index - s.length());
+        }
+        // pad to the right to create 10**9, then trim
+        return Long.parseLong((s + "000000000").substring(0, 9));
+    }
+
+    private String prepareTime(String s, int baseIndex) {
+        if (s.contains(".")) {
+            int i = s.indexOf(".") + 1;
+
+            // verify that the first character after the dot is a digit
+            if (Character.isDigit(s.charAt(i))) {
+                i++;
+            } else {
+                throw new DateTimeParseException("Period could not be parsed, invalid decimal number: " +
+                        text, text, baseIndex + index);
+            }
+
+            // verify that only digits follow the decimal point followed by an S
+            while (i < s.length()) {
+                // || !Character.isDigit(s.charAt(i))
+                char c = s.charAt(i);
+                if (Character.isDigit(c) || c == 'S') {
+                    i++;
+                } else {
+                    throw new DateTimeParseException("Period could not be parsed, invalid decimal number: " +
+                            text, text, baseIndex + index);
+                }
+            }
+            s = s.replace('S', 'N').replace('.', 'S');
+            if (s.contains("-0S")) {
+                negativeSecs = true;
+                s = s.replace("-0S", "0S");
+            }
+        }
+        return s;
+    }
+
+    private int parseInt(String s, int baseIndex) {
+        try {
+            int value = Integer.parseInt(s);
+            if (s.charAt(0) == '-' && value == 0) {
+                throw new DateTimeParseException("Period could not be parsed, invalid number '" +
+                        s + "': " + text, text, baseIndex + index - s.length());
+            }
+            return value;
+        } catch (NumberFormatException ex) {
+            throw new DateTimeParseException("Period could not be parsed, invalid number '" +
+                    s + "': " + text, text, baseIndex + index - s.length());
+        }
+    }
+
+    private String parseNumber(String s) {
+        int start = index;
+        while (index < s.length()) {
+            char c = s.charAt(index);
+            if ((c < '0' || c > '9') && c != '-') {
+                break;
+            }
+            index++;
+        }
+        return s.substring(start, index);
+    }
+
+    private void validateCharactersAndOrdering(String s, CharSequence text) {
+        char[] chars = s.toCharArray();
+        int tokenPos = 0;
+        boolean lastLetter = false;
+        for (int i = 0; i < chars.length; i++) {
+            if (tokenPos >= TOKEN_SEQUENCE.length()) {
+                throw new DateTimeParseException("Period could not be parsed, characters after last 'S': " + text, text, i);
+            }
+            char c = chars[i];
+            if ((c < '0' || c > '9') && c != '-' && c != '.') {
+                tokenPos = TOKEN_SEQUENCE.indexOf(c, tokenPos);
+                if (tokenPos < 0) {
+                    throw new DateTimeParseException("Period could not be parsed, invalid character '" + c + "': " + text, text, i);
+                }
+                tokenPos++;
+                lastLetter = true;
+            } else {
+                lastLetter = false;
+            }
+        }
+        if (lastLetter == false) {
+            throw new DateTimeParseException("Period could not be parsed, invalid last character: " + text, text, s.length() - 1);
+        }
+    }
+
+    private Period toPeriod() {
+        return Period.of(years, months, days, hours, minutes, seconds, negativeSecs || seconds < 0 ? -nanos : nanos);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/Ser.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,211 @@
+/*
+ * 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;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.InvalidClassException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.StreamCorruptedException;
+
+/**
+ * The shared serialization delegate for this package.
+ *
+ * <h3>Implementation notes</h3>
+ * 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 LOCAL_DATE_TYPE_VERSION_2 = 21}.
+ * <p>
+ * 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.
+ * <p>
+ * 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.
+ * <p>
+ * 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 = -7683839454370182990L;
+
+    static final byte DURATION_TYPE = 1;
+    static final byte INSTANT_TYPE = 2;
+    static final byte LOCAL_DATE_TYPE = 3;
+    static final byte LOCAL_TIME_TYPE = 4;
+    static final byte LOCAL_DATE_TIME_TYPE = 5;
+    static final byte ZONE_DATE_TIME_TYPE = 6;
+    static final byte ZONE_REGION_TYPE = 7;
+    static final byte ZONE_OFFSET_TYPE = 8;
+
+    /** The type being serialized. */
+    private byte type;
+    /** The object being serialized. */
+    private Object object;
+
+    /**
+     * Constructor for deserialization.
+     */
+    public Ser() {
+    }
+
+    /**
+     * Creates an instance for serialization.
+     *
+     * @param type  the type
+     * @param object  the object
+     */
+    Ser(byte type, Object object) {
+        this.type = type;
+        this.object = object;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Implements the {@code Externalizable} interface to write the object.
+     *
+     * @param out  the data stream to write to, not null
+     */
+    public void writeExternal(ObjectOutput out) throws IOException {
+        writeInternal(type, object, out);
+    }
+
+    static void writeInternal(byte type, Object object, DataOutput out) throws IOException {
+        out.writeByte(type);
+        switch (type) {
+            case DURATION_TYPE:
+                ((Duration) object).writeExternal(out);
+                break;
+            case INSTANT_TYPE:
+                ((Instant) object).writeExternal(out);
+                break;
+            case LOCAL_DATE_TYPE:
+                ((LocalDate) object).writeExternal(out);
+                break;
+            case LOCAL_DATE_TIME_TYPE:
+                ((LocalDateTime) object).writeExternal(out);
+                break;
+            case LOCAL_TIME_TYPE:
+                ((LocalTime) object).writeExternal(out);
+                break;
+            case ZONE_REGION_TYPE:
+                ((ZoneRegion) object).writeExternal(out);
+                break;
+            case ZONE_OFFSET_TYPE:
+                ((ZoneOffset) object).writeExternal(out);
+                break;
+            case ZONE_DATE_TIME_TYPE:
+                ((ZonedDateTime) object).writeExternal(out);
+                break;
+            default:
+                throw new InvalidClassException("Unknown serialized type");
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Implements the {@code Externalizable} interface to read the object.
+     *
+     * @param in  the data to read, not null
+     */
+    public void readExternal(ObjectInput in) throws IOException {
+        type = in.readByte();
+        object = readInternal(type, in);
+    }
+
+    static Object read(DataInput in) throws IOException {
+        byte type = in.readByte();
+        return readInternal(type, in);
+    }
+
+    private static Object readInternal(byte type, DataInput in) throws IOException {
+        switch (type) {
+            case DURATION_TYPE: return Duration.readExternal(in);
+            case INSTANT_TYPE: return Instant.readExternal(in);
+            case LOCAL_DATE_TYPE: return LocalDate.readExternal(in);
+            case LOCAL_DATE_TIME_TYPE: return LocalDateTime.readExternal(in);
+            case LOCAL_TIME_TYPE: return LocalTime.readExternal(in);
+            case ZONE_DATE_TIME_TYPE: return ZonedDateTime.readExternal(in);
+            case ZONE_OFFSET_TYPE: return ZoneOffset.readExternal(in);
+            case ZONE_REGION_TYPE: return ZoneRegion.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;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/ZoneId.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,518 @@
+/*
+ * 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;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.Serializable;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.TextStyle;
+import java.time.temporal.Queries;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQuery;
+import java.time.zone.ZoneRules;
+import java.time.zone.ZoneRulesProvider;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Objects;
+import java.util.TimeZone;
+
+/**
+ * A time-zone ID, such as {@code Europe/Paris}.
+ * <p>
+ * A {@code ZoneId} is used to identify the rules used to convert between
+ * an {@link Instant} and a {@link LocalDateTime}.
+ * There are two distinct types of ID:
+ * <p><ul>
+ * <li>Fixed offsets - a fully resolved offset from UTC/Greenwich, that uses
+ *  the same offset for all local date-times
+ * <li>Geographical regions - an area where a specific set of rules for finding
+ *  the offset from UTC/Greenwich apply
+ * </ul><p>
+ * Most fixed offsets are represented by {@link ZoneOffset}.
+ * <p>
+ * The actual rules, describing when and how the offset changes, are defined by {@link ZoneRules}.
+ * This class is simply an ID used to obtain the underlying rules.
+ * This approach is taken because rules are defined by governments and change
+ * frequently, whereas the ID is stable.
+ * <p>
+ * The distinction has other effects. Serializing the {@code ZoneId} will only send
+ * the ID, whereas serializing the rules sends the entire data set.
+ * Similarly, a comparison of two IDs only examines the ID, whereas
+ * a comparison of two rules examines the entire data set.
+ * <p>
+ * The code supports loading a {@code ZoneId} on a JVM which does not have available rules
+ * for that ID. This allows the date-time object, such as {@link ZonedDateTime},
+ * to still be queried.
+ *
+ * <h3>Time-zone IDs</h3>
+ * The ID is unique within the system.
+ * The formats for offset and region IDs differ.
+ * <p>
+ * An ID is parsed as an offset ID if it starts with 'UTC', 'GMT', '+' or '-', or
+ * is a single letter.
+ * For example, 'Z', '+02:00', '-05:00', 'UTC+05' and 'GMT-6' are all valid offset IDs.
+ * Note that some IDs, such as 'D' or '+ABC' meet the criteria, but are invalid.
+ * <p>
+ * All other IDs are considered to be region IDs.
+ * <p>
+ * Region IDs are defined by configuration, which can be thought of as a {@code Map}
+ * from region ID to {@code ZoneRules}, see {@link ZoneRulesProvider}.
+ * <p>
+ * Time-zones are defined by governments and change frequently. There are a number of
+ * organizations, known here as groups, that monitor time-zone changes and collate them.
+ * The default group is the IANA Time Zone Database (TZDB).
+ * Other organizations include IATA (the airline industry body) and Microsoft.
+ * <p>
+ * Each group defines its own format for region ID.
+ * The TZDB group defines IDs such as 'Europe/London' or 'America/New_York'.
+ * TZDB IDs take precedence over other groups.
+ * <p>
+ * It is strongly recommended that the group name is included in all Ids supplied by
+ * groups other than TZDB to avoid conflicts. For example, IATA airline time-zone
+ * region IDs are typically the same as the three letter airport code.
+ * However, the airport of Utrecht has the code 'UTC', which is obviously a conflict.
+ * The recommended format for region IDs from groups other than TZDB is 'group~region'.
+ * Thus if IATA data were defined, Utrecht airport would be 'IATA~UTC'.
+ *
+ * <h3>Specification for implementors</h3>
+ * This abstract class has two implementations, both of which are immutable and thread-safe.
+ * One implementation models region-based IDs, the other is {@code ZoneOffset} modelling
+ * offset-based IDs.
+ *
+ * @since 1.8
+ */
+public abstract class ZoneId implements Serializable {
+
+    /**
+     * A map of zone overrides to enable the older US time-zone names to be used.
+     * <p>
+     * This maps as follows:
+     * <p><ul>
+     * <li>EST - America/Indianapolis</li>
+     * <li>MST - America/Phoenix</li>
+     * <li>HST - Pacific/Honolulu</li>
+     * <li>ACT - Australia/Darwin</li>
+     * <li>AET - Australia/Sydney</li>
+     * <li>AGT - America/Argentina/Buenos_Aires</li>
+     * <li>ART - Africa/Cairo</li>
+     * <li>AST - America/Anchorage</li>
+     * <li>BET - America/Sao_Paulo</li>
+     * <li>BST - Asia/Dhaka</li>
+     * <li>CAT - Africa/Harare</li>
+     * <li>CNT - America/St_Johns</li>
+     * <li>CST - America/Chicago</li>
+     * <li>CTT - Asia/Shanghai</li>
+     * <li>EAT - Africa/Addis_Ababa</li>
+     * <li>ECT - Europe/Paris</li>
+     * <li>IET - America/Indiana/Indianapolis</li>
+     * <li>IST - Asia/Kolkata</li>
+     * <li>JST - Asia/Tokyo</li>
+     * <li>MIT - Pacific/Apia</li>
+     * <li>NET - Asia/Yerevan</li>
+     * <li>NST - Pacific/Auckland</li>
+     * <li>PLT - Asia/Karachi</li>
+     * <li>PNT - America/Phoenix</li>
+     * <li>PRT - America/Puerto_Rico</li>
+     * <li>PST - America/Los_Angeles</li>
+     * <li>SST - Pacific/Guadalcanal</li>
+     * <li>VST - Asia/Ho_Chi_Minh</li>
+     * </ul><p>
+     * The map is unmodifiable.
+     */
+    public static final Map<String, String> OLD_IDS_PRE_2005;
+    /**
+     * A map of zone overrides to enable the older US time-zone names to be used.
+     * <p>
+     * This maps as follows:
+     * <p><ul>
+     * <li>EST - -05:00</li>
+     * <li>HST - -10:00</li>
+     * <li>MST - -07:00</li>
+     * <li>ACT - Australia/Darwin</li>
+     * <li>AET - Australia/Sydney</li>
+     * <li>AGT - America/Argentina/Buenos_Aires</li>
+     * <li>ART - Africa/Cairo</li>
+     * <li>AST - America/Anchorage</li>
+     * <li>BET - America/Sao_Paulo</li>
+     * <li>BST - Asia/Dhaka</li>
+     * <li>CAT - Africa/Harare</li>
+     * <li>CNT - America/St_Johns</li>
+     * <li>CST - America/Chicago</li>
+     * <li>CTT - Asia/Shanghai</li>
+     * <li>EAT - Africa/Addis_Ababa</li>
+     * <li>ECT - Europe/Paris</li>
+     * <li>IET - America/Indiana/Indianapolis</li>
+     * <li>IST - Asia/Kolkata</li>
+     * <li>JST - Asia/Tokyo</li>
+     * <li>MIT - Pacific/Apia</li>
+     * <li>NET - Asia/Yerevan</li>
+     * <li>NST - Pacific/Auckland</li>
+     * <li>PLT - Asia/Karachi</li>
+     * <li>PNT - America/Phoenix</li>
+     * <li>PRT - America/Puerto_Rico</li>
+     * <li>PST - America/Los_Angeles</li>
+     * <li>SST - Pacific/Guadalcanal</li>
+     * <li>VST - Asia/Ho_Chi_Minh</li>
+     * </ul><p>
+     * The map is unmodifiable.
+     */
+    public static final Map<String, String> OLD_IDS_POST_2005;
+    static {
+        Map<String, String> base = new HashMap<>();
+        base.put("ACT", "Australia/Darwin");
+        base.put("AET", "Australia/Sydney");
+        base.put("AGT", "America/Argentina/Buenos_Aires");
+        base.put("ART", "Africa/Cairo");
+        base.put("AST", "America/Anchorage");
+        base.put("BET", "America/Sao_Paulo");
+        base.put("BST", "Asia/Dhaka");
+        base.put("CAT", "Africa/Harare");
+        base.put("CNT", "America/St_Johns");
+        base.put("CST", "America/Chicago");
+        base.put("CTT", "Asia/Shanghai");
+        base.put("EAT", "Africa/Addis_Ababa");
+        base.put("ECT", "Europe/Paris");
+        base.put("IET", "America/Indiana/Indianapolis");
+        base.put("IST", "Asia/Kolkata");
+        base.put("JST", "Asia/Tokyo");
+        base.put("MIT", "Pacific/Apia");
+        base.put("NET", "Asia/Yerevan");
+        base.put("NST", "Pacific/Auckland");
+        base.put("PLT", "Asia/Karachi");
+        base.put("PNT", "America/Phoenix");
+        base.put("PRT", "America/Puerto_Rico");
+        base.put("PST", "America/Los_Angeles");
+        base.put("SST", "Pacific/Guadalcanal");
+        base.put("VST", "Asia/Ho_Chi_Minh");
+        Map<String, String> pre = new HashMap<>(base);
+        pre.put("EST", "America/Indianapolis");
+        pre.put("MST", "America/Phoenix");
+        pre.put("HST", "Pacific/Honolulu");
+        OLD_IDS_PRE_2005 = Collections.unmodifiableMap(pre);
+        Map<String, String> post = new HashMap<>(base);
+        post.put("EST", "-05:00");
+        post.put("MST", "-07:00");
+        post.put("HST", "-10:00");
+        OLD_IDS_POST_2005 = Collections.unmodifiableMap(post);
+    }
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 8352817235686L;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the system default time-zone.
+     * <p>
+     * This queries {@link TimeZone#getDefault()} to find the default time-zone
+     * and converts it to a {@code ZoneId}. If the system default time-zone is changed,
+     * then the result of this method will also change.
+     *
+     * @return the zone ID, not null
+     * @throws DateTimeException if the converted zone ID has an invalid format
+     * @throws java.time.zone.ZoneRulesException if the converted zone region ID cannot be found
+     */
+    public static ZoneId systemDefault() {
+        return ZoneId.of(TimeZone.getDefault().getID(), OLD_IDS_POST_2005);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ZoneId} using its ID using a map
+     * of aliases to supplement the standard zone IDs.
+     * <p>
+     * Many users of time-zones use short abbreviations, such as PST for
+     * 'Pacific Standard Time' and PDT for 'Pacific Daylight Time'.
+     * These abbreviations are not unique, and so cannot be used as IDs.
+     * This method allows a map of string to time-zone to be setup and reused
+     * within an application.
+     *
+     * @param zoneId  the time-zone ID, not null
+     * @param aliasMap  a map of alias zone IDs (typically abbreviations) to real zone IDs, not null
+     * @return the zone ID, not null
+     * @throws DateTimeException if the zone ID has an invalid format
+     * @throws java.time.zone.ZoneRulesException if the zone region ID cannot be found
+     */
+    public static ZoneId of(String zoneId, Map<String, String> aliasMap) {
+        Objects.requireNonNull(zoneId, "zoneId");
+        Objects.requireNonNull(aliasMap, "aliasMap");
+        String id = aliasMap.get(zoneId);
+        id = (id != null ? id : zoneId);
+        return of(id);
+    }
+
+    /**
+     * Obtains an instance of {@code ZoneId} from an ID ensuring that the
+     * ID is valid and available for use.
+     * <p>
+     * This method parses the ID, applies any appropriate normalization, and validates it
+     * against the known set of IDs for which rules are available.
+     * <p>
+     * An ID is parsed as though it is an offset ID if it starts with 'UTC', 'GMT', '+'
+     * or '-', or if it has less then two letters.
+     * The offset of {@link ZoneOffset#UTC zero} may be represented in multiple ways,
+     * including 'Z', 'UTC', 'GMT', 'UTC0' 'GMT0', '+00:00', '-00:00' and 'UTC+00:00'.
+     * <p>
+     * Eight forms of ID are recognized, where '{offset}' means to parse using {@link ZoneOffset#of(String)}:
+     * <p><ul>
+     * <li><code>{offset}</code> - a {@link ZoneOffset} ID, such as 'Z' or '+02:00'
+     * <li><code>UTC</code> - alternate form of a {@code ZoneOffset} ID equal to 'Z'
+     * <li><code>UTC0</code> - alternate form of a {@code ZoneOffset} ID equal to 'Z'
+     * <li><code>UTC{offset}</code> - alternate form of a {@code ZoneOffset} ID equal to '{offset}'
+     * <li><code>GMT</code> - alternate form of a {@code ZoneOffset} ID equal to 'Z'
+     * <li><code>GMT0</code> - alternate form of a {@code ZoneOffset} ID equal to 'Z'
+     * <li><code>GMT{offset}</code> - alternate form of a {@code ZoneOffset} ID equal to '{offset}'r
+     * <li><code>{regionID}</code> - full region ID, loaded from configuration
+     * </ul><p>
+     * Region IDs must match the regular expression <code>[A-Za-z][A-Za-z0-9~/._+-]+</code>.
+     * <p>
+     * The detailed format of the region ID depends on the group supplying the data.
+     * The default set of data is supplied by the IANA Time Zone Database (TZDB)
+     * This has region IDs of the form '{area}/{city}', such as 'Europe/Paris' or 'America/New_York'.
+     * This is compatible with most IDs from {@link java.util.TimeZone}.
+     *
+     * @param zoneId  the time-zone ID, not null
+     * @return the zone ID, not null
+     * @throws DateTimeException if the zone ID has an invalid format
+     * @throws java.time.zone.ZoneRulesException if the zone region ID cannot be found
+     */
+    public static ZoneId of(String zoneId) {
+        Objects.requireNonNull(zoneId, "zoneId");
+        if (zoneId.length() <= 1 || zoneId.startsWith("+") || zoneId.startsWith("-")) {
+            return ZoneOffset.of(zoneId);
+        } else if (zoneId.startsWith("UTC") || zoneId.startsWith("GMT")) {
+            if (zoneId.length() == 3 || (zoneId.length() == 4 && zoneId.charAt(3) == '0')) {
+                return ZoneOffset.UTC;
+            }
+            return ZoneOffset.of(zoneId.substring(3));
+        }
+        return ZoneRegion.ofId(zoneId, true);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ZoneId} from a temporal object.
+     * <p>
+     * A {@code TemporalAccessor} represents some form of date and time information.
+     * This factory converts the arbitrary temporal object to an instance of {@code ZoneId}.
+     * <p>
+     * The conversion will try to obtain the zone in a way that favours region-based
+     * zones over offset-based zones using {@link Queries#zone()}.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used in queries via method reference, {@code ZoneId::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the zone ID, not null
+     * @throws DateTimeException if unable to convert to a {@code ZoneId}
+     */
+    public static ZoneId from(TemporalAccessor temporal) {
+        ZoneId obj = temporal.query(Queries.zone());
+        if (obj == null) {
+            throw new DateTimeException("Unable to obtain ZoneId from TemporalAccessor: " + temporal.getClass());
+        }
+        return obj;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructor only accessible within the package.
+     */
+    ZoneId() {
+        if (getClass() != ZoneOffset.class && getClass() != ZoneRegion.class) {
+            throw new AssertionError("Invalid subclass");
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the unique time-zone ID.
+     * <p>
+     * This ID uniquely defines this object.
+     * The format of an offset based ID is defined by {@link ZoneOffset#getId()}.
+     *
+     * @return the time-zone unique ID, not null
+     */
+    public abstract String getId();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the time-zone rules for this ID allowing calculations to be performed.
+     * <p>
+     * The rules provide the functionality associated with a time-zone,
+     * such as finding the offset for a given instant or local date-time.
+     * <p>
+     * A time-zone can be invalid if it is deserialized in a JVM which does not
+     * have the same rules loaded as the JVM that stored it. In this case, calling
+     * this method will throw an exception.
+     * <p>
+     * The rules are supplied by {@link ZoneRulesProvider}. An advanced provider may
+     * support dynamic updates to the rules without restarting the JVM.
+     * If so, then the result of this method may change over time.
+     * Each individual call will be still remain thread-safe.
+     * <p>
+     * {@link ZoneOffset} will always return a set of rules where the offset never changes.
+     *
+     * @return the rules, not null
+     * @throws DateTimeException if no rules are available for this ID
+     */
+    public abstract ZoneRules getRules();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the textual representation of the zone, such as 'British Time' or
+     * '+02:00'.
+     * <p>
+     * This returns a textual description for the time-zone ID.
+     * <p>
+     * If no textual mapping is found then the {@link #getId() full ID} is returned.
+     *
+     * @param style  the length of the text required, not null
+     * @param locale  the locale to use, not null
+     * @return the text value of the zone, not null
+     */
+    public String getText(TextStyle style, Locale locale) {
+        return new DateTimeFormatterBuilder().appendZoneText(style).toFormatter(locale).print(new TemporalAccessor() {
+            @Override
+            public boolean isSupported(TemporalField field) {
+                return false;
+            }
+            @Override
+            public long getLong(TemporalField field) {
+                throw new DateTimeException("Unsupported field: " + field);
+            }
+            @SuppressWarnings("unchecked")
+            @Override
+            public <R> R query(TemporalQuery<R> query) {
+                if (query == Queries.zoneId()) {
+                    return (R) ZoneId.this;
+                }
+                return TemporalAccessor.super.query(query);
+            }
+        });
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this time-zone ID is equal to another time-zone ID.
+     * <p>
+     * The comparison is based on the ID.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other time-zone ID
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+           return true;
+        }
+        if (obj instanceof ZoneId) {
+            ZoneId other = (ZoneId) obj;
+            return getId().equals(other.getId());
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this time-zone ID.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return getId().hashCode();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this zone as a {@code String}, using the ID.
+     *
+     * @return a string representation of this time-zone ID, not null
+     */
+    @Override
+    public String toString() {
+        return getId();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * <pre>
+     *  out.writeByte(7);  // identifies this as a ZoneId (not ZoneOffset)
+     *  out.writeUTF(zoneId);
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    // this is here for serialization Javadoc
+    private Object writeReplace() {
+        return new Ser(Ser.ZONE_REGION_TYPE, this);
+    }
+
+    abstract void write(DataOutput out) throws IOException;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/ZoneOffset.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,789 @@
+/*
+ * 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;
+
+import static java.time.temporal.ChronoField.OFFSET_SECONDS;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.time.temporal.ChronoField;
+import java.time.temporal.Queries;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.ValueRange;
+import java.time.zone.ZoneRules;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * A time-zone offset from Greenwich/UTC, such as {@code +02:00}.
+ * <p>
+ * A time-zone offset is the period of time that a time-zone differs from Greenwich/UTC.
+ * This is usually a fixed number of hours and minutes.
+ * <p>
+ * Different parts of the world have different time-zone offsets.
+ * The rules for how offsets vary by place and time of year are captured in the
+ * {@link ZoneId} class.
+ * <p>
+ * For example, Paris is one hour ahead of Greenwich/UTC in winter and two hours
+ * ahead in summer. The {@code ZoneId} instance for Paris will reference two
+ * {@code ZoneOffset} instances - a {@code +01:00} instance for winter,
+ * and a {@code +02:00} instance for summer.
+ * <p>
+ * In 2008, time-zone offsets around the world extended from -12:00 to +14:00.
+ * To prevent any problems with that range being extended, yet still provide
+ * validation, the range of offsets is restricted to -18:00 to 18:00 inclusive.
+ * <p>
+ * This class is designed for use with the ISO calendar system.
+ * The fields of hours, minutes and seconds make assumptions that are valid for the
+ * standard ISO definitions of those fields. This class may be used with other
+ * calendar systems providing the definition of the time fields matches those
+ * of the ISO calendar system.
+ * <p>
+ * Instances of {@code ZoneOffset} must be compared using {@link #equals}.
+ * Implementations may choose to cache certain common offsets, however
+ * applications must not rely on such caching.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class ZoneOffset
+        extends ZoneId
+        implements TemporalAccessor, TemporalAdjuster, Comparable<ZoneOffset>, Serializable {
+
+    /** Cache of time-zone offset by offset in seconds. */
+    private static final ConcurrentMap<Integer, ZoneOffset> SECONDS_CACHE = new ConcurrentHashMap<>(16, 0.75f, 4);
+    /** Cache of time-zone offset by ID. */
+    private static final ConcurrentMap<String, ZoneOffset> ID_CACHE = new ConcurrentHashMap<>(16, 0.75f, 4);
+
+    /**
+     * The number of seconds per hour.
+     */
+    private static final int SECONDS_PER_HOUR = 60 * 60;
+    /**
+     * The number of seconds per minute.
+     */
+    private static final int SECONDS_PER_MINUTE = 60;
+    /**
+     * The number of minutes per hour.
+     */
+    private static final int MINUTES_PER_HOUR = 60;
+    /**
+     * The abs maximum seconds.
+     */
+    private static final int MAX_SECONDS = 18 * SECONDS_PER_HOUR;
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 2357656521762053153L;
+
+    /**
+     * The time-zone offset for UTC, with an ID of 'Z'.
+     */
+    public static final ZoneOffset UTC = ZoneOffset.ofTotalSeconds(0);
+    /**
+     * Constant for the maximum supported offset.
+     */
+    public static final ZoneOffset MIN = ZoneOffset.ofTotalSeconds(-MAX_SECONDS);
+    /**
+     * Constant for the maximum supported offset.
+     */
+    public static final ZoneOffset MAX = ZoneOffset.ofTotalSeconds(MAX_SECONDS);
+
+    /**
+     * The total offset in seconds.
+     */
+    private final int totalSeconds;
+    /**
+     * The string form of the time-zone offset.
+     */
+    private final transient String id;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ZoneOffset} using the ID.
+     * <p>
+     * This method parses the string ID of a {@code ZoneOffset} to
+     * return an instance. The parsing accepts all the formats generated by
+     * {@link #getId()}, plus some additional formats:
+     * <p><ul>
+     * <li>{@code Z} - for UTC
+     * <li>{@code +h}
+     * <li>{@code +hh}
+     * <li>{@code +hh:mm}
+     * <li>{@code -hh:mm}
+     * <li>{@code +hhmm}
+     * <li>{@code -hhmm}
+     * <li>{@code +hh:mm:ss}
+     * <li>{@code -hh:mm:ss}
+     * <li>{@code +hhmmss}
+     * <li>{@code -hhmmss}
+     * </ul><p>
+     * Note that &plusmn; means either the plus or minus symbol.
+     * <p>
+     * The ID of the returned offset will be normalized to one of the formats
+     * described by {@link #getId()}.
+     * <p>
+     * The maximum supported range is from +18:00 to -18:00 inclusive.
+     *
+     * @param offsetId  the offset ID, not null
+     * @return the zone-offset, not null
+     * @throws DateTimeException if the offset ID is invalid
+     */
+    @SuppressWarnings("fallthrough")
+    public static ZoneOffset of(String offsetId) {
+        Objects.requireNonNull(offsetId, "offsetId");
+        // "Z" is always in the cache
+        ZoneOffset offset = ID_CACHE.get(offsetId);
+        if (offset != null) {
+            return offset;
+        }
+
+        // parse - +h, +hh, +hhmm, +hh:mm, +hhmmss, +hh:mm:ss
+        final int hours, minutes, seconds;
+        switch (offsetId.length()) {
+            case 2:
+                offsetId = offsetId.charAt(0) + "0" + offsetId.charAt(1);  // fallthru
+            case 3:
+                hours = parseNumber(offsetId, 1, false);
+                minutes = 0;
+                seconds = 0;
+                break;
+            case 5:
+                hours = parseNumber(offsetId, 1, false);
+                minutes = parseNumber(offsetId, 3, false);
+                seconds = 0;
+                break;
+            case 6:
+                hours = parseNumber(offsetId, 1, false);
+                minutes = parseNumber(offsetId, 4, true);
+                seconds = 0;
+                break;
+            case 7:
+                hours = parseNumber(offsetId, 1, false);
+                minutes = parseNumber(offsetId, 3, false);
+                seconds = parseNumber(offsetId, 5, false);
+                break;
+            case 9:
+                hours = parseNumber(offsetId, 1, false);
+                minutes = parseNumber(offsetId, 4, true);
+                seconds = parseNumber(offsetId, 7, true);
+                break;
+            default:
+                throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid");
+        }
+        char first = offsetId.charAt(0);
+        if (first != '+' && first != '-') {
+            throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid: Plus/minus not found when expected");
+        }
+        if (first == '-') {
+            return ofHoursMinutesSeconds(-hours, -minutes, -seconds);
+        } else {
+            return ofHoursMinutesSeconds(hours, minutes, seconds);
+        }
+    }
+
+    /**
+     * Parse a two digit zero-prefixed number.
+     *
+     * @param offsetId  the offset ID, not null
+     * @param pos  the position to parse, valid
+     * @param precededByColon  should this number be prefixed by a precededByColon
+     * @return the parsed number, from 0 to 99
+     */
+    private static int parseNumber(CharSequence offsetId, int pos, boolean precededByColon) {
+        if (precededByColon && offsetId.charAt(pos - 1) != ':') {
+            throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid: Colon not found when expected");
+        }
+        char ch1 = offsetId.charAt(pos);
+        char ch2 = offsetId.charAt(pos + 1);
+        if (ch1 < '0' || ch1 > '9' || ch2 < '0' || ch2 > '9') {
+            throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid: Non numeric characters found");
+        }
+        return (ch1 - 48) * 10 + (ch2 - 48);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ZoneOffset} using an offset in hours.
+     *
+     * @param hours  the time-zone offset in hours, from -18 to +18
+     * @return the zone-offset, not null
+     * @throws DateTimeException if the offset is not in the required range
+     */
+    public static ZoneOffset ofHours(int hours) {
+        return ofHoursMinutesSeconds(hours, 0, 0);
+    }
+
+    /**
+     * Obtains an instance of {@code ZoneOffset} using an offset in
+     * hours and minutes.
+     * <p>
+     * The sign of the hours and minutes components must match.
+     * Thus, if the hours is negative, the minutes must be negative or zero.
+     * If the hours is zero, the minutes may be positive, negative or zero.
+     *
+     * @param hours  the time-zone offset in hours, from -18 to +18
+     * @param minutes  the time-zone offset in minutes, from 0 to &plusmn;59, sign matches hours
+     * @return the zone-offset, not null
+     * @throws DateTimeException if the offset is not in the required range
+     */
+    public static ZoneOffset ofHoursMinutes(int hours, int minutes) {
+        return ofHoursMinutesSeconds(hours, minutes, 0);
+    }
+
+    /**
+     * Obtains an instance of {@code ZoneOffset} using an offset in
+     * hours, minutes and seconds.
+     * <p>
+     * The sign of the hours, minutes and seconds components must match.
+     * Thus, if the hours is negative, the minutes and seconds must be negative or zero.
+     *
+     * @param hours  the time-zone offset in hours, from -18 to +18
+     * @param minutes  the time-zone offset in minutes, from 0 to &plusmn;59, sign matches hours and seconds
+     * @param seconds  the time-zone offset in seconds, from 0 to &plusmn;59, sign matches hours and minutes
+     * @return the zone-offset, not null
+     * @throws DateTimeException if the offset is not in the required range
+     */
+    public static ZoneOffset ofHoursMinutesSeconds(int hours, int minutes, int seconds) {
+        validate(hours, minutes, seconds);
+        int totalSeconds = totalSeconds(hours, minutes, seconds);
+        return ofTotalSeconds(totalSeconds);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ZoneOffset} from a temporal object.
+     * <p>
+     * A {@code TemporalAccessor} represents some form of date and time information.
+     * This factory converts the arbitrary temporal object to an instance of {@code ZoneOffset}.
+     * <p>
+     * The conversion extracts the {@link ChronoField#OFFSET_SECONDS offset-seconds} field.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used in queries via method reference, {@code ZoneOffset::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the zone-offset, not null
+     * @throws DateTimeException if unable to convert to an {@code ZoneOffset}
+     */
+    public static ZoneOffset from(TemporalAccessor temporal) {
+        if (temporal instanceof ZoneOffset) {
+            return (ZoneOffset) temporal;
+        }
+        try {
+            return ofTotalSeconds(temporal.get(OFFSET_SECONDS));
+        } catch (DateTimeException ex) {
+            throw new DateTimeException("Unable to obtain ZoneOffset from TemporalAccessor: " + temporal.getClass(), ex);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Validates the offset fields.
+     *
+     * @param hours  the time-zone offset in hours, from -18 to +18
+     * @param minutes  the time-zone offset in minutes, from 0 to &plusmn;59
+     * @param seconds  the time-zone offset in seconds, from 0 to &plusmn;59
+     * @throws DateTimeException if the offset is not in the required range
+     */
+    private static void validate(int hours, int minutes, int seconds) {
+        if (hours < -18 || hours > 18) {
+            throw new DateTimeException("Zone offset hours not in valid range: value " + hours +
+                    " is not in the range -18 to 18");
+        }
+        if (hours > 0) {
+            if (minutes < 0 || seconds < 0) {
+                throw new DateTimeException("Zone offset minutes and seconds must be positive because hours is positive");
+            }
+        } else if (hours < 0) {
+            if (minutes > 0 || seconds > 0) {
+                throw new DateTimeException("Zone offset minutes and seconds must be negative because hours is negative");
+            }
+        } else if ((minutes > 0 && seconds < 0) || (minutes < 0 && seconds > 0)) {
+            throw new DateTimeException("Zone offset minutes and seconds must have the same sign");
+        }
+        if (Math.abs(minutes) > 59) {
+            throw new DateTimeException("Zone offset minutes not in valid range: abs(value) " +
+                    Math.abs(minutes) + " is not in the range 0 to 59");
+        }
+        if (Math.abs(seconds) > 59) {
+            throw new DateTimeException("Zone offset seconds not in valid range: abs(value) " +
+                    Math.abs(seconds) + " is not in the range 0 to 59");
+        }
+        if (Math.abs(hours) == 18 && (Math.abs(minutes) > 0 || Math.abs(seconds) > 0)) {
+            throw new DateTimeException("Zone offset not in valid range: -18:00 to +18:00");
+        }
+    }
+
+    /**
+     * Calculates the total offset in seconds.
+     *
+     * @param hours  the time-zone offset in hours, from -18 to +18
+     * @param minutes  the time-zone offset in minutes, from 0 to &plusmn;59, sign matches hours and seconds
+     * @param seconds  the time-zone offset in seconds, from 0 to &plusmn;59, sign matches hours and minutes
+     * @return the total in seconds
+     */
+    private static int totalSeconds(int hours, int minutes, int seconds) {
+        return hours * SECONDS_PER_HOUR + minutes * SECONDS_PER_MINUTE + seconds;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ZoneOffset} specifying the total offset in seconds
+     * <p>
+     * The offset must be in the range {@code -18:00} to {@code +18:00}, which corresponds to -64800 to +64800.
+     *
+     * @param totalSeconds  the total time-zone offset in seconds, from -64800 to +64800
+     * @return the ZoneOffset, not null
+     * @throws DateTimeException if the offset is not in the required range
+     */
+    public static ZoneOffset ofTotalSeconds(int totalSeconds) {
+        if (Math.abs(totalSeconds) > MAX_SECONDS) {
+            throw new DateTimeException("Zone offset not in valid range: -18:00 to +18:00");
+        }
+        if (totalSeconds % (15 * SECONDS_PER_MINUTE) == 0) {
+            Integer totalSecs = totalSeconds;
+            ZoneOffset result = SECONDS_CACHE.get(totalSecs);
+            if (result == null) {
+                result = new ZoneOffset(totalSeconds);
+                SECONDS_CACHE.putIfAbsent(totalSecs, result);
+                result = SECONDS_CACHE.get(totalSecs);
+                ID_CACHE.putIfAbsent(result.getId(), result);
+            }
+            return result;
+        } else {
+            return new ZoneOffset(totalSeconds);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructor.
+     *
+     * @param totalSeconds  the total time-zone offset in seconds, from -64800 to +64800
+     */
+    private ZoneOffset(int totalSeconds) {
+        super();
+        this.totalSeconds = totalSeconds;
+        id = buildId(totalSeconds);
+    }
+
+    private static String buildId(int totalSeconds) {
+        if (totalSeconds == 0) {
+            return "Z";
+        } else {
+            int absTotalSeconds = Math.abs(totalSeconds);
+            StringBuilder buf = new StringBuilder();
+            int absHours = absTotalSeconds / SECONDS_PER_HOUR;
+            int absMinutes = (absTotalSeconds / SECONDS_PER_MINUTE) % MINUTES_PER_HOUR;
+            buf.append(totalSeconds < 0 ? "-" : "+")
+                .append(absHours < 10 ? "0" : "").append(absHours)
+                .append(absMinutes < 10 ? ":0" : ":").append(absMinutes);
+            int absSeconds = absTotalSeconds % SECONDS_PER_MINUTE;
+            if (absSeconds != 0) {
+                buf.append(absSeconds < 10 ? ":0" : ":").append(absSeconds);
+            }
+            return buf.toString();
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the total zone offset in seconds.
+     * <p>
+     * This is the primary way to access the offset amount.
+     * It returns the total of the hours, minutes and seconds fields as a
+     * single offset that can be added to a time.
+     *
+     * @return the total zone offset amount in seconds
+     */
+    public int getTotalSeconds() {
+        return totalSeconds;
+    }
+
+    /**
+     * Gets the normalized zone offset ID.
+     * <p>
+     * The ID is minor variation to the standard ISO-8601 formatted string
+     * for the offset. There are three formats:
+     * <p><ul>
+     * <li>{@code Z} - for UTC (ISO-8601)
+     * <li>{@code +hh:mm} or {@code -hh:mm} - if the seconds are zero (ISO-8601)
+     * <li>{@code +hh:mm:ss} or {@code -hh:mm:ss} - if the seconds are non-zero (not ISO-8601)
+     * </ul><p>
+     *
+     * @return the zone offset ID, not null
+     */
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    /**
+     * Gets the associated time-zone rules.
+     * <p>
+     * The rules will always return this offset when queried.
+     * The implementation class is immutable, thread-safe and serializable.
+     *
+     * @return the rules, not null
+     */
+    @Override
+    public ZoneRules getRules() {
+        return ZoneRules.of(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if this offset 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.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@code OFFSET_SECONDS} field returns true.
+     * All other {@code ChronoField} instances will return false.
+     * <p>
+     * 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 offset, false if not
+     */
+    @Override
+    public boolean isSupported(TemporalField field) {
+        if (field instanceof ChronoField) {
+            return field == OFFSET_SECONDS;
+        }
+        return field != null && field.doIsSupported(this);
+    }
+
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * The range object expresses the minimum and maximum valid values for a field.
+     * This offset 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.
+     * <p>
+     * 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}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the range can be obtained is determined by the field.
+     *
+     * @param field  the field to query the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     */
+    @Override  // override for Javadoc
+    public ValueRange range(TemporalField field) {
+        return TemporalAccessor.super.range(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this offset as an {@code int}.
+     * <p>
+     * This queries this offset 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.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@code OFFSET_SECONDS} field returns the value of the offset.
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override  // override for Javadoc and performance
+    public int get(TemporalField field) {
+        if (field == OFFSET_SECONDS) {
+            return totalSeconds;
+        } else if (field instanceof ChronoField) {
+            throw new DateTimeException("Unsupported field: " + field.getName());
+        }
+        return range(field).checkValidIntValue(getLong(field), field);
+    }
+
+    /**
+     * Gets the value of the specified field from this offset as a {@code long}.
+     * <p>
+     * This queries this offset 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.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@code OFFSET_SECONDS} field returns the value of the offset.
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * 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 == OFFSET_SECONDS) {
+            return totalSeconds;
+        } else if (field instanceof ChronoField) {
+            throw new DateTimeException("Unsupported field: " + field.getName());
+        }
+        return field.doGet(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this offset using the specified query.
+     * <p>
+     * This queries this offset 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.
+     * <p>
+     * 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 <R> 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> R query(TemporalQuery<R> query) {
+        if (query == Queries.offset() || query == Queries.zone()) {
+            return (R) this;
+        }
+        return TemporalAccessor.super.query(query);
+    }
+
+    /**
+     * Adjusts the specified temporal object to have the same offset as this object.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with the offset changed to be the same as this.
+     * <p>
+     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+     * passing {@link ChronoField#OFFSET_SECONDS} as the field.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisOffset.adjustInto(temporal);
+     *   temporal = temporal.with(thisOffset);
+     * </pre>
+     * <p>
+     * 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, totalSeconds);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this offset to another offset in descending order.
+     * <p>
+     * The offsets are compared in the order that they occur for the same time
+     * of day around the world. Thus, an offset of {@code +10:00} comes before an
+     * offset of {@code +09:00} and so on down to {@code -18:00}.
+     * <p>
+     * The comparison is "consistent with equals", as defined by {@link Comparable}.
+     *
+     * @param other  the other date to compare to, not null
+     * @return the comparator value, negative if less, postive if greater
+     * @throws NullPointerException if {@code other} is null
+     */
+    @Override
+    public int compareTo(ZoneOffset other) {
+        return other.totalSeconds - totalSeconds;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this offset is equal to another offset.
+     * <p>
+     * The comparison is based on the amount of the offset in seconds.
+     * This is equivalent to a comparison by ID.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other offset
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+           return true;
+        }
+        if (obj instanceof ZoneOffset) {
+            return totalSeconds == ((ZoneOffset) obj).totalSeconds;
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this offset.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return totalSeconds;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this offset as a {@code String}, using the normalized ID.
+     *
+     * @return a string representation of this offset, not null
+     */
+    @Override
+    public String toString() {
+        return id;
+    }
+
+    // -----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * <pre>
+     *  out.writeByte(8);  // identifies this as a ZoneOffset
+     *  int offsetByte = totalSeconds % 900 == 0 ? totalSeconds / 900 : 127;
+     *  out.writeByte(offsetByte);
+     *  if (offsetByte == 127) {
+     *    out.writeInt(totalSeconds);
+     *  }
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.ZONE_OFFSET_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     * @return never
+     * @throws InvalidObjectException always
+     */
+    private Object readResolve() throws ObjectStreamException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    @Override
+    void write(DataOutput out) throws IOException {
+        out.writeByte(Ser.ZONE_OFFSET_TYPE);
+        writeExternal(out);
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        final int offsetSecs = totalSeconds;
+        int offsetByte = offsetSecs % 900 == 0 ? offsetSecs / 900 : 127;  // compress to -72 to +72
+        out.writeByte(offsetByte);
+        if (offsetByte == 127) {
+            out.writeInt(offsetSecs);
+        }
+    }
+
+    static ZoneOffset readExternal(DataInput in) throws IOException {
+        int offsetByte = in.readByte();
+        return (offsetByte == 127 ? ZoneOffset.ofTotalSeconds(in.readInt()) : ZoneOffset.ofTotalSeconds(offsetByte * 900));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/ZoneRegion.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,222 @@
+/*
+ * 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) 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;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.time.zone.ZoneRules;
+import java.time.zone.ZoneRulesException;
+import java.time.zone.ZoneRulesProvider;
+import java.util.Objects;
+import java.util.regex.Pattern;
+
+/**
+ * A geographical region where the same time-zone rules apply.
+ * <p>
+ * Time-zone information is categorized as a set of rules defining when and
+ * how the offset from UTC/Greenwich changes. These rules are accessed using
+ * identifiers based on geographical regions, such as countries or states.
+ * The most common region classification is the Time Zone Database (TZDB),
+ * which defines regions such as 'Europe/Paris' and 'Asia/Tokyo'.
+ * <p>
+ * The region identifier, modeled by this class, is distinct from the
+ * underlying rules, modeled by {@link ZoneRules}.
+ * The rules are defined by governments and change frequently.
+ * By contrast, the region identifier is well-defined and long-lived.
+ * This separation also allows rules to be shared between regions if appropriate.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+final class ZoneRegion extends ZoneId implements Serializable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 8386373296231747096L;
+    /**
+     * The regex pattern for region IDs.
+     */
+    private static final Pattern PATTERN = Pattern.compile("[A-Za-z][A-Za-z0-9~/._+-]+");
+
+    /**
+     * The time-zone ID, not null.
+     */
+    private final String id;
+    /**
+     * The time-zone rules, null if zone ID was loaded leniently.
+     */
+    private final transient ZoneRules rules;
+
+    /**
+     * Obtains an instance of {@code ZoneRegion} from an identifier without checking
+     * if the time-zone has available rules.
+     * <p>
+     * This method parses the ID and applies any appropriate normalization.
+     * It does not validate the ID against the known set of IDsfor which rules are available.
+     * <p>
+     * This method is intended for advanced use cases.
+     * For example, consider a system that always retrieves time-zone rules from a remote server.
+     * Using this factory would allow a {@code ZoneRegion}, and thus a {@code ZonedDateTime},
+     * to be created without loading the rules from the remote server.
+     *
+     * @param zoneId  the time-zone ID, not null
+     * @return the zone ID, not null
+     * @throws DateTimeException if the ID format is invalid
+     */
+    private static ZoneRegion ofLenient(String zoneId) {
+        return ofId(zoneId, false);
+    }
+
+    /**
+     * Obtains an instance of {@code ZoneId} from an identifier.
+     *
+     * @param zoneId  the time-zone ID, not null
+     * @param checkAvailable  whether to check if the zone ID is available
+     * @return the zone ID, not null
+     * @throws DateTimeException if the ID format is invalid
+     * @throws DateTimeException if checking availability and the ID cannot be found
+     */
+    static ZoneRegion ofId(String zoneId, boolean checkAvailable) {
+        Objects.requireNonNull(zoneId, "zoneId");
+        if (zoneId.length() < 2 || zoneId.startsWith("UTC") ||
+                zoneId.startsWith("GMT") || (PATTERN.matcher(zoneId).matches() == false)) {
+            throw new DateTimeException("ZoneId format is not a valid region format");
+        }
+        ZoneRules rules = null;
+        try {
+            // always attempt load for better behavior after deserialization
+            rules = ZoneRulesProvider.getRules(zoneId);
+        } catch (ZoneRulesException ex) {
+            if (checkAvailable) {
+                throw ex;
+            }
+        }
+        return new ZoneRegion(zoneId, rules);
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Constructor.
+     *
+     * @param id  the time-zone ID, not null
+     * @param rules  the rules, null for lazy lookup
+     */
+    ZoneRegion(String id, ZoneRules rules) {
+        this.id = id;
+        this.rules = rules;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public ZoneRules getRules() {
+        // additional query for group provider when null allows for possibility
+        // that the provider was added after the ZoneId was created
+        return (rules != null ? rules : ZoneRulesProvider.getRules(id));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * <pre>
+     *  out.writeByte(7);  // identifies this as a ZoneId (not ZoneOffset)
+     *  out.writeUTF(zoneId);
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.ZONE_REGION_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     * @return never
+     * @throws InvalidObjectException always
+     */
+    private Object readResolve() throws ObjectStreamException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    @Override
+    void write(DataOutput out) throws IOException {
+        out.writeByte(Ser.ZONE_REGION_TYPE);
+        writeExternal(out);
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        out.writeUTF(id);
+    }
+
+    static ZoneId readExternal(DataInput in) throws IOException {
+        String id = in.readUTF();
+        return ofLenient(id);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/ZonedDateTime.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,2071 @@
+/*
+ * 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;
+
+import static java.time.temporal.ChronoField.INSTANT_SECONDS;
+import static java.time.temporal.ChronoField.NANO_OF_SECOND;
+import static java.time.temporal.ChronoField.OFFSET_SECONDS;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatters;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.ChronoZonedDateTime;
+import java.time.temporal.ISOChrono;
+import java.time.temporal.OffsetDateTime;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdder;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.TemporalSubtractor;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.ValueRange;
+import java.time.zone.ZoneOffsetTransition;
+import java.time.zone.ZoneRules;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A date-time with a time-zone in the ISO-8601 calendar system,
+ * such as {@code 2007-12-03T10:15:30+01:00 Europe/Paris}.
+ * <p>
+ * {@code ZonedDateTime} is an immutable representation of a date-time with a time-zone.
+ * This class stores all date and time fields, to a precision of nanoseconds,
+ * and a time-zone, with a zone offset used to handle ambiguous local date-times.
+ * For example, the value
+ * "2nd October 2007 at 13:45.30.123456789 +02:00 in the Europe/Paris time-zone"
+ * can be stored in a {@code ZonedDateTime}.
+ * <p>
+ * This class handles conversion from the local time-line of {@code LocalDateTime}
+ * to the instant time-line of {@code Instant}.
+ * The difference between the two time-lines is the offset from UTC/Greenwich,
+ * represented by a {@code ZoneOffset}.
+ * <p>
+ * Converting between the two time-lines involves calculating the offset using the
+ * {@link ZoneRules rules} accessed from the {@code ZoneId}.
+ * Obtaining the offset for an instant is simple, as there is exactly one valid
+ * offset for each instant. By contrast, obtaining the offset for a local date-time
+ * is not straightforward. There are three cases:
+ * <p><ul>
+ * <li>Normal, with one valid offset. For the vast majority of the year, the normal
+ *  case applies, where there is a single valid offset for the local date-time.</li>
+ * <li>Gap, with zero valid offsets. This is when clocks jump forward typically
+ *  due to the spring daylight savings change from "winter" to "summer".
+ *  In a gap there are local date-time values with no valid offset.</li>
+ * <li>Overlap, with two valid offsets. This is when clocks are set back typically
+ *  due to the autumn daylight savings change from "summer" to "winter".
+ *  In an overlap there are local date-time values with two valid offsets.</li>
+ * </ul><p>
+ * <p>
+ * Any method that converts directly or implicitly from a local date-time to an
+ * instant by obtaining the offset has the potential to be complicated.
+ * <p>
+ * For Gaps, the general strategy is that if the local date-time falls in the
+ * middle of a Gap, then the resulting zoned date-time will have a local date-time
+ * shifted forwards by the length of the Gap, resulting in a date-time in the later
+ * offset, typically "summer" time.
+ * <p>
+ * For Overlaps, the general strategy is that if the local date-time falls in the
+ * middle of an Overlap, then the previous offset will be retained. If there is no
+ * previous offset, or the previous offset is invalid, then the earlier offset is
+ * used, typically "summer" time.. Two additional methods,
+ * {@link #withEarlierOffsetAtOverlap()} and {@link #withLaterOffsetAtOverlap()},
+ * help manage the case of an overlap.
+ *
+ * <h3>Specification for implementors</h3>
+ * A {@code ZonedDateTime} holds state equivalent to three separate objects,
+ * a {@code LocalDateTime}, a {@code ZoneId} and the resolved {@code ZoneOffset}.
+ * The offset and local date-time are used to define an instant when necessary.
+ * The zone ID is used to obtain the rules for how and when the offset changes.
+ * The offset cannot be freely set, as the zone controls which offsets are valid.
+ * <p>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class ZonedDateTime
+        implements Temporal, ChronoZonedDateTime<ISOChrono>, Serializable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -6260982410461394882L;
+
+    /**
+     * The local date-time.
+     */
+    private final LocalDateTime dateTime;
+    /**
+     * The offset from UTC/Greenwich.
+     */
+    private final ZoneOffset offset;
+    /**
+     * The time-zone.
+     */
+    private final ZoneId zone;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains the current date-time from the system clock in the default time-zone.
+     * <p>
+     * This will query the {@link Clock#systemDefaultZone() system clock} in the default
+     * time-zone to obtain the current date-time.
+     * The zone and offset will be set based on the time-zone in the clock.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @return the current date-time using the system clock, not null
+     */
+    public static ZonedDateTime now() {
+        return now(Clock.systemDefaultZone());
+    }
+
+    /**
+     * Obtains the current date-time from the system clock in the specified time-zone.
+     * <p>
+     * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date-time.
+     * Specifying the time-zone avoids dependence on the default time-zone.
+     * The offset will be calculated from the specified time-zone.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @param zone  the zone ID to use, not null
+     * @return the current date-time using the system clock, not null
+     */
+    public static ZonedDateTime now(ZoneId zone) {
+        return now(Clock.system(zone));
+    }
+
+    /**
+     * Obtains the current date-time from the specified clock.
+     * <p>
+     * This will query the specified clock to obtain the current date-time.
+     * The zone and offset will be set based on the time-zone in the clock.
+     * <p>
+     * Using this method allows the use of an alternate clock for testing.
+     * The alternate clock may be introduced using {@link Clock dependency injection}.
+     *
+     * @param clock  the clock to use, not null
+     * @return the current date-time, not null
+     */
+    public static ZonedDateTime now(Clock clock) {
+        Objects.requireNonNull(clock, "clock");
+        final Instant now = clock.instant();  // called once
+        return ofInstant(now, clock.getZone());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ZonedDateTime} from a local date-time.
+     * <p>
+     * This creates a zoned date-time matching the input local date-time as closely as possible.
+     * Time-zone rules, such as daylight savings, mean that not every local date-time
+     * is valid for the specified zone, thus the local date-time may be adjusted.
+     * <p>
+     * The local date-time is resolved to a single instant on the time-line.
+     * This is achieved by finding a valid offset from UTC/Greenwich for the local
+     * date-time as defined by the {@link ZoneRules rules} of the zone ID.
+     *<p>
+     * In most cases, there is only one valid offset for a local date-time.
+     * In the case of an overlap, when clocks are set back, there are two valid offsets.
+     * This method uses the earlier offset typically corresponding to "summer".
+     * <p>
+     * In the case of a gap, when clocks jump forward, there is no valid offset.
+     * Instead, the local date-time is adjusted to be later by the length of the gap.
+     * For a typical one hour daylight savings change, the local date-time will be
+     * moved one hour later into the offset typically corresponding to "summer".
+     *
+     * @param localDateTime  the local date-time, not null
+     * @param zone  the time-zone, not null
+     * @return the zoned date-time, not null
+     */
+    public static ZonedDateTime of(LocalDateTime localDateTime, ZoneId zone) {
+        return ofLocal(localDateTime, zone, null);
+    }
+
+    /**
+     * Obtains an instance of {@code ZonedDateTime} from a local date-time
+     * using the preferred offset if possible.
+     * <p>
+     * The local date-time is resolved to a single instant on the time-line.
+     * This is achieved by finding a valid offset from UTC/Greenwich for the local
+     * date-time as defined by the {@link ZoneRules rules} of the zone ID.
+     *<p>
+     * In most cases, there is only one valid offset for a local date-time.
+     * In the case of an overlap, where clocks are set back, there are two valid offsets.
+     * If the preferred offset is one of the valid offsets then it is used.
+     * Otherwise the earlier valid offset is used, typically corresponding to "summer".
+     * <p>
+     * In the case of a gap, where clocks jump forward, there is no valid offset.
+     * Instead, the local date-time is adjusted to be later by the length of the gap.
+     * For a typical one hour daylight savings change, the local date-time will be
+     * moved one hour later into the offset typically corresponding to "summer".
+     *
+     * @param localDateTime  the local date-time, not null
+     * @param zone  the time-zone, not null
+     * @param preferredOffset  the zone offset, null if no preference
+     * @return the zoned date-time, not null
+     */
+    public static ZonedDateTime ofLocal(LocalDateTime localDateTime, ZoneId zone, ZoneOffset preferredOffset) {
+        Objects.requireNonNull(localDateTime, "localDateTime");
+        Objects.requireNonNull(zone, "zone");
+        if (zone instanceof ZoneOffset) {
+            return new ZonedDateTime(localDateTime, (ZoneOffset) zone, zone);
+        }
+        ZoneRules rules = zone.getRules();
+        List<ZoneOffset> validOffsets = rules.getValidOffsets(localDateTime);
+        ZoneOffset offset;
+        if (validOffsets.size() == 1) {
+            offset = validOffsets.get(0);
+        } else if (validOffsets.size() == 0) {
+            ZoneOffsetTransition trans = rules.getTransition(localDateTime);
+            localDateTime = localDateTime.plusSeconds(trans.getDuration().getSeconds());
+            offset = trans.getOffsetAfter();
+        } else {
+            if (preferredOffset != null && validOffsets.contains(preferredOffset)) {
+                offset = preferredOffset;
+            } else {
+                offset = Objects.requireNonNull(validOffsets.get(0), "offset");  // protect against bad ZoneRules
+            }
+        }
+        return new ZonedDateTime(localDateTime, offset, zone);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ZonedDateTime} from an {@code Instant}.
+     * <p>
+     * This creates a zoned date-time with the same instant as that specified.
+     * Calling {@link #toInstant()} will return an instant equal to the one used here.
+     * <p>
+     * Converting an instant to a zoned date-time is simple as there is only one valid
+     * offset for each instant.
+     *
+     * @param instant  the instant to create the date-time from, not null
+     * @param zone  the time-zone, not null
+     * @return the zoned date-time, not null
+     * @throws DateTimeException if the result exceeds the supported range
+     */
+    public static ZonedDateTime ofInstant(Instant instant, ZoneId zone) {
+        Objects.requireNonNull(instant, "instant");
+        Objects.requireNonNull(zone, "zone");
+        return create(instant.getEpochSecond(), instant.getNano(), zone);
+    }
+
+    /**
+     * Obtains an instance of {@code ZonedDateTime} from the instant formed by combining
+     * the local date-time and offset.
+     * <p>
+     * This creates a zoned date-time by {@link LocalDateTime#toInstant(ZoneOffset) combining}
+     * the {@code LocalDateTime} and {@code ZoneOffset}.
+     * This combination uniquely specifies an instant without ambiguity.
+     * <p>
+     * Converting an instant to a zoned date-time is simple as there is only one valid
+     * offset for each instant. If the valid offset is different to the offset specified,
+     * the the date-time and offset of the zoned date-time will differ from those specified.
+     * <p>
+     * If the {@code ZoneId} to be used is a {@code ZoneOffset}, this method is equivalent
+     * to {@link #of(LocalDateTime, ZoneId)}.
+     *
+     * @param localDateTime  the local date-time, not null
+     * @param offset  the zone offset, not null
+     * @param zone  the time-zone, not null
+     * @return the zoned date-time, not null
+     */
+    public static ZonedDateTime ofInstant(LocalDateTime localDateTime, ZoneOffset offset, ZoneId zone) {
+        Objects.requireNonNull(localDateTime, "localDateTime");
+        Objects.requireNonNull(offset, "offset");
+        Objects.requireNonNull(zone, "zone");
+        return create(localDateTime.toEpochSecond(offset), localDateTime.getNano(), zone);
+    }
+
+    /**
+     * Obtains an instance of {@code ZonedDateTime} using seconds from the
+     * epoch of 1970-01-01T00:00:00Z.
+     *
+     * @param epochSecond  the number of seconds from the epoch of 1970-01-01T00:00:00Z
+     * @param nanoOfSecond  the nanosecond within the second, from 0 to 999,999,999
+     * @param zone  the time-zone, not null
+     * @return the zoned date-time, not null
+     * @throws DateTimeException if the result exceeds the supported range
+     */
+    private static ZonedDateTime create(long epochSecond, int nanoOfSecond, ZoneId zone) {
+        ZoneRules rules = zone.getRules();
+        Instant instant = Instant.ofEpochSecond(epochSecond, nanoOfSecond);  // TODO: rules should be queryable by epochSeconds
+        ZoneOffset offset = rules.getOffset(instant);
+        LocalDateTime ldt = LocalDateTime.ofEpochSecond(epochSecond, nanoOfSecond, offset);
+        return new ZonedDateTime(ldt, offset, zone);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ZonedDateTime} strictly validating the
+     * combination of local date-time, offset and zone ID.
+     * <p>
+     * This creates a zoned date-time ensuring that the offset is valid for the
+     * local date-time according to the rules of the specified zone.
+     * If the offset is invalid, an exception is thrown.
+     *
+     * @param localDateTime  the local date-time, not null
+     * @param offset  the zone offset, not null
+     * @param zone  the time-zone, not null
+     * @return the zoned date-time, not null
+     */
+    public static ZonedDateTime ofStrict(LocalDateTime localDateTime, ZoneOffset offset, ZoneId zone) {
+        Objects.requireNonNull(localDateTime, "localDateTime");
+        Objects.requireNonNull(offset, "offset");
+        Objects.requireNonNull(zone, "zone");
+        ZoneRules rules = zone.getRules();
+        if (rules.isValidOffset(localDateTime, offset) == false) {
+            ZoneOffsetTransition trans = rules.getTransition(localDateTime);
+            if (trans != null && trans.isGap()) {
+                // error message says daylight savings for simplicity
+                // even though there are other kinds of gaps
+                throw new DateTimeException("LocalDateTime '" + localDateTime +
+                        "' does not exist in zone '" + zone +
+                        "' due to a gap in the local time-line, typically caused by daylight savings");
+            }
+            throw new DateTimeException("ZoneOffset '" + offset + "' is not valid for LocalDateTime '" +
+                    localDateTime + "' in zone '" + zone + "'");
+        }
+        return new ZonedDateTime(localDateTime, offset, zone);
+    }
+
+    /**
+     * Obtains an instance of {@code ZonedDateTime} leniently, for advanced use cases,
+     * allowing any combination of local date-time, offset and zone ID.
+     * <p>
+     * This creates a zoned date-time with no checks other than no nulls.
+     * This means that the resulting zoned date-time may have an offset that is in conflict
+     * with the zone ID.
+     * <p>
+     * This method is intended for advanced use cases.
+     * For example, consider the case where a zoned date-time with valid fields is created
+     * and then stored in a database or serialization-based store. At some later point,
+     * the object is then re-loaded. However, between those points in time, the government
+     * that defined the time-zone has changed the rules, such that the originally stored
+     * local date-time now does not occur. This method can be used to create the object
+     * in an "invalid" state, despite the change in rules.
+     *
+     * @param localDateTime  the local date-time, not null
+     * @param offset  the zone offset, not null
+     * @param zone  the time-zone, not null
+     * @return the zoned date-time, not null
+     */
+    private static ZonedDateTime ofLenient(LocalDateTime localDateTime, ZoneOffset offset, ZoneId zone) {
+        Objects.requireNonNull(localDateTime, "localDateTime");
+        Objects.requireNonNull(offset, "offset");
+        Objects.requireNonNull(zone, "zone");
+        if (zone instanceof ZoneOffset && offset.equals(zone) == false) {
+            throw new IllegalArgumentException("ZoneId must match ZoneOffset");
+        }
+        return new ZonedDateTime(localDateTime, offset, zone);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ZonedDateTime} from a temporal object.
+     * <p>
+     * A {@code TemporalAccessor} represents some form of date and time information.
+     * This factory converts the arbitrary temporal object to an instance of {@code ZonedDateTime}.
+     * <p>
+     * The conversion will first obtain a {@code ZoneId}. It will then try to obtain an instant.
+     * If that fails it will try to obtain a local date-time.
+     * The zoned date time will either be a combination of {@code ZoneId} and instant,
+     * or {@code ZoneId} and local date-time.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used in queries via method reference, {@code ZonedDateTime::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the zoned date-time, not null
+     * @throws DateTimeException if unable to convert to an {@code ZonedDateTime}
+     */
+    public static ZonedDateTime from(TemporalAccessor temporal) {
+        if (temporal instanceof ZonedDateTime) {
+            return (ZonedDateTime) temporal;
+        }
+        try {
+            ZoneId zone = ZoneId.from(temporal);
+            try {
+                long epochSecond = temporal.getLong(INSTANT_SECONDS);
+                int nanoOfSecond = temporal.get(NANO_OF_SECOND);
+                return create(epochSecond, nanoOfSecond, zone);
+
+            } catch (DateTimeException ex1) {
+                LocalDateTime ldt = LocalDateTime.from(temporal);
+                return of(ldt, zone);
+            }
+        } catch (DateTimeException ex) {
+            throw new DateTimeException("Unable to create ZonedDateTime from TemporalAccessor: " + temporal.getClass(), ex);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ZonedDateTime} from a text string such as
+     * {@code 2007-12-03T10:15:30+01:00[Europe/Paris]}.
+     * <p>
+     * The string must represent a valid date-time and is parsed using
+     * {@link java.time.format.DateTimeFormatters#isoZonedDateTime()}.
+     *
+     * @param text  the text to parse such as "2007-12-03T10:15:30+01:00[Europe/Paris]", not null
+     * @return the parsed zoned date-time, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static ZonedDateTime parse(CharSequence text) {
+        return parse(text, DateTimeFormatters.isoZonedDateTime());
+    }
+
+    /**
+     * Obtains an instance of {@code ZonedDateTime} from a text string using a specific formatter.
+     * <p>
+     * The text is parsed using the formatter, returning a date-time.
+     *
+     * @param text  the text to parse, not null
+     * @param formatter  the formatter to use, not null
+     * @return the parsed zoned date-time, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static ZonedDateTime parse(CharSequence text, DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.parse(text, ZonedDateTime::from);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructor.
+     *
+     * @param dateTime  the date-time, validated as not null
+     * @param offset  the zone offset, validated as not null
+     * @param zone  the time-zone, validated as not null
+     */
+    private ZonedDateTime(LocalDateTime dateTime, ZoneOffset offset, ZoneId zone) {
+        this.dateTime = dateTime;
+        this.offset = offset;
+        this.zone = zone;
+    }
+
+    /**
+     * Resolves the new local date-time using this zone ID, retaining the offset if possible.
+     *
+     * @param newDateTime  the new local date-time, not null
+     * @return the zoned date-time, not null
+     */
+    private ZonedDateTime resolveLocal(LocalDateTime newDateTime) {
+        return ofLocal(newDateTime, zone, offset);
+    }
+
+    /**
+     * Resolves the new local date-time using the offset to identify the instant.
+     *
+     * @param newDateTime  the new local date-time, not null
+     * @return the zoned date-time, not null
+     */
+    private ZonedDateTime resolveInstant(LocalDateTime newDateTime) {
+        return ofInstant(newDateTime, offset, zone);
+    }
+
+    /**
+     * Resolves the offset into this zoned date-time.
+     * <p>
+     * This will use the new offset to find the instant, which is then looked up
+     * using the zone ID to find the actual offset to use.
+     *
+     * @param offset  the offset, not null
+     * @return the zoned date-time, not null
+     */
+    private ZonedDateTime resolveOffset(ZoneOffset offset) {
+        long epSec = dateTime.toEpochSecond(offset);
+        return create(epSec, dateTime.getNano(), zone);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if this date-time can be queried for the specified field.
+     * If false, then calling the {@link #range(TemporalField) range} and
+     * {@link #get(TemporalField) get} methods will throw an exception.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The supported fields are:
+     * <ul>
+     * <li>{@code NANO_OF_SECOND}
+     * <li>{@code NANO_OF_DAY}
+     * <li>{@code MICRO_OF_SECOND}
+     * <li>{@code MICRO_OF_DAY}
+     * <li>{@code MILLI_OF_SECOND}
+     * <li>{@code MILLI_OF_DAY}
+     * <li>{@code SECOND_OF_MINUTE}
+     * <li>{@code SECOND_OF_DAY}
+     * <li>{@code MINUTE_OF_HOUR}
+     * <li>{@code MINUTE_OF_DAY}
+     * <li>{@code HOUR_OF_AMPM}
+     * <li>{@code CLOCK_HOUR_OF_AMPM}
+     * <li>{@code HOUR_OF_DAY}
+     * <li>{@code CLOCK_HOUR_OF_DAY}
+     * <li>{@code AMPM_OF_DAY}
+     * <li>{@code DAY_OF_WEEK}
+     * <li>{@code ALIGNED_DAY_OF_WEEK_IN_MONTH}
+     * <li>{@code ALIGNED_DAY_OF_WEEK_IN_YEAR}
+     * <li>{@code DAY_OF_MONTH}
+     * <li>{@code DAY_OF_YEAR}
+     * <li>{@code EPOCH_DAY}
+     * <li>{@code ALIGNED_WEEK_OF_MONTH}
+     * <li>{@code ALIGNED_WEEK_OF_YEAR}
+     * <li>{@code MONTH_OF_YEAR}
+     * <li>{@code EPOCH_MONTH}
+     * <li>{@code YEAR_OF_ERA}
+     * <li>{@code YEAR}
+     * <li>{@code ERA}
+     * <li>{@code INSTANT_SECONDS}
+     * <li>{@code OFFSET_SECONDS}
+     * </ul>
+     * All other {@code ChronoField} instances will return false.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the field is supported is determined by the field.
+     *
+     * @param field  the field to check, null returns false
+     * @return true if the field is supported on this date-time, false if not
+     */
+    @Override
+    public boolean isSupported(TemporalField field) {
+        return field instanceof ChronoField || (field != null && field.doIsSupported(this));
+    }
+
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * The range object expresses the minimum and maximum valid values for a field.
+     * This date-time is used to enhance the accuracy of the returned range.
+     * If it is not possible to return the range, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * 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}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the range can be obtained is determined by the field.
+     *
+     * @param field  the field to query the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     */
+    @Override
+    public ValueRange range(TemporalField field) {
+        if (field instanceof ChronoField) {
+            if (field == INSTANT_SECONDS || field == OFFSET_SECONDS) {
+                return field.range();
+            }
+            return dateTime.range(field);
+        }
+        return field.doRange(this);
+    }
+
+    /**
+     * Gets the value of the specified field from this date-time as an {@code int}.
+     * <p>
+     * This queries this date-time for the value for the specified field.
+     * The returned value will always be within the valid range of values for the field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this date-time, except {@code NANO_OF_DAY}, {@code MICRO_OF_DAY},
+     * {@code EPOCH_DAY}, {@code EPOCH_MONTH} and {@code INSTANT_SECONDS} which are too
+     * large to fit in an {@code int} and throw a {@code DateTimeException}.
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override  // override for Javadoc and performance
+    public int get(TemporalField field) {
+        if (field instanceof ChronoField) {
+            switch ((ChronoField) field) {
+                case INSTANT_SECONDS: throw new DateTimeException("Field too large for an int: " + field);
+                case OFFSET_SECONDS: return getOffset().getTotalSeconds();
+            }
+            return dateTime.get(field);
+        }
+        return ChronoZonedDateTime.super.get(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this date-time as a {@code long}.
+     * <p>
+     * This queries this date-time for the value for the specified field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this date-time.
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long getLong(TemporalField field) {
+        if (field instanceof ChronoField) {
+            switch ((ChronoField) field) {
+                case INSTANT_SECONDS: return toEpochSecond();
+                case OFFSET_SECONDS: return getOffset().getTotalSeconds();
+            }
+            return dateTime.getLong(field);
+        }
+        return field.doGet(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the zone offset, such as '+01:00'.
+     * <p>
+     * This is the offset of the local date-time from UTC/Greenwich.
+     *
+     * @return the zone offset, not null
+     */
+    @Override
+    public ZoneOffset getOffset() {
+        return offset;
+    }
+
+    /**
+     * Returns a copy of this date-time changing the zone offset to the
+     * earlier of the two valid offsets at a local time-line overlap.
+     * <p>
+     * This method only has any effect when the local time-line overlaps, such as
+     * at an autumn daylight savings cutover. In this scenario, there are two
+     * valid offsets for the local date-time. Calling this method will return
+     * a zoned date-time with the earlier of the two selected.
+     * <p>
+     * If this method is called when it is not an overlap, {@code this}
+     * is returned.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @return a {@code ZonedDateTime} based on this date-time with the earlier offset, not null
+     */
+    @Override
+    public ZonedDateTime withEarlierOffsetAtOverlap() {
+        ZoneOffsetTransition trans = getZone().getRules().getTransition(dateTime);
+        if (trans != null && trans.isOverlap()) {
+            ZoneOffset earlierOffset = trans.getOffsetBefore();
+            if (earlierOffset.equals(offset) == false) {
+                return new ZonedDateTime(dateTime, earlierOffset, zone);
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Returns a copy of this date-time changing the zone offset to the
+     * later of the two valid offsets at a local time-line overlap.
+     * <p>
+     * This method only has any effect when the local time-line overlaps, such as
+     * at an autumn daylight savings cutover. In this scenario, there are two
+     * valid offsets for the local date-time. Calling this method will return
+     * a zoned date-time with the later of the two selected.
+     * <p>
+     * If this method is called when it is not an overlap, {@code this}
+     * is returned.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @return a {@code ZonedDateTime} based on this date-time with the later offset, not null
+     */
+    @Override
+    public ZonedDateTime withLaterOffsetAtOverlap() {
+        ZoneOffsetTransition trans = getZone().getRules().getTransition(getDateTime());
+        if (trans != null) {
+            ZoneOffset laterOffset = trans.getOffsetAfter();
+            if (laterOffset.equals(offset) == false) {
+                return new ZonedDateTime(dateTime, laterOffset, zone);
+            }
+        }
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the time-zone, such as 'Europe/Paris'.
+     * <p>
+     * This returns the zone ID. This identifies the time-zone {@link ZoneRules rules}
+     * that determine when and how the offset from UTC/Greenwich changes.
+     * <p>
+     * The zone ID may be same as the {@linkplain #getOffset() offset}.
+     * If this is true, then any future calculations, such as addition or subtraction,
+     * have no complex edge cases due to time-zone rules.
+     * See also {@link #withFixedOffsetZone()}.
+     *
+     * @return the time-zone, not null
+     */
+    @Override
+    public ZoneId getZone() {
+        return zone;
+    }
+
+    /**
+     * Returns a copy of this date-time with a different time-zone,
+     * retaining the local date-time if possible.
+     * <p>
+     * This method changes the time-zone and retains the local date-time.
+     * The local date-time is only changed if it is invalid for the new zone,
+     * determined using the same approach as
+     * {@link #ofLocal(LocalDateTime, ZoneId, ZoneOffset)}.
+     * <p>
+     * To change the zone and adjust the local date-time,
+     * use {@link #withZoneSameInstant(ZoneId)}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param zone  the time-zone to change to, not null
+     * @return a {@code ZonedDateTime} based on this date-time with the requested zone, not null
+     */
+    @Override
+    public ZonedDateTime withZoneSameLocal(ZoneId zone) {
+        Objects.requireNonNull(zone, "zone");
+        return this.zone.equals(zone) ? this : ofLocal(dateTime, zone, offset);
+    }
+
+    /**
+     * Returns a copy of this date-time with a different time-zone,
+     * retaining the instant.
+     * <p>
+     * This method changes the time-zone and retains the instant.
+     * This normally results in a change to the local date-time.
+     * <p>
+     * This method is based on retaining the same instant, thus gaps and overlaps
+     * in the local time-line have no effect on the result.
+     * <p>
+     * To change the offset while keeping the local time,
+     * use {@link #withZoneSameLocal(ZoneId)}.
+     *
+     * @param zone  the time-zone to change to, not null
+     * @return a {@code ZonedDateTime} based on this date-time with the requested zone, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    @Override
+    public ZonedDateTime withZoneSameInstant(ZoneId zone) {
+        Objects.requireNonNull(zone, "zone");
+        return this.zone.equals(zone) ? this :
+            create(dateTime.toEpochSecond(offset), dateTime.getNano(), zone);
+    }
+
+    /**
+     * Returns a copy of this date-time with the zone ID set to the offset.
+     * <p>
+     * This returns a zoned date-time where the zone ID is the same as {@link #getOffset()}.
+     * The local date-time, offset and instant of the result will be the same as in this date-time.
+     * <p>
+     * Setting the date-time to a fixed single offset means that any future
+     * calculations, such as addition or subtraction, have no complex edge cases
+     * due to time-zone rules.
+     * This might also be useful when sending a zoned date-time across a network,
+     * as most protocols, such as ISO-8601, only handle offsets,
+     * and not region-based zone IDs.
+     * <p>
+     * This is equivalent to {@code ZonedDateTime.of(zdt.getDateTime(), zdt.getOffset())}.
+     *
+     * @return a {@code ZonedDateTime} with the zone ID set to the offset, not null
+     */
+    public ZonedDateTime withFixedOffsetZone() {
+        return this.zone.equals(offset) ? this : new ZonedDateTime(dateTime, offset, offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the {@code LocalDateTime} part of this date-time.
+     * <p>
+     * This returns a {@code LocalDateTime} with the same year, month, day and time
+     * as this date-time.
+     *
+     * @return the local date-time part of this date-time, not null
+     */
+    @Override  // override for return type
+    public LocalDateTime getDateTime() {
+        return dateTime;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the {@code LocalDate} part of this date-time.
+     * <p>
+     * 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
+     */
+    @Override  // override for return type
+    public LocalDate getDate() {
+        return dateTime.getDate();
+    }
+
+    /**
+     * Gets the year field.
+     * <p>
+     * This method returns the primitive {@code int} value for the year.
+     * <p>
+     * The year returned by this method is proleptic as per {@code get(YEAR)}.
+     * To obtain the year-of-era, use {@code get(YEAR_OF_ERA}.
+     *
+     * @return the year, from MIN_YEAR to MAX_YEAR
+     */
+    public int getYear() {
+        return dateTime.getYear();
+    }
+
+    /**
+     * Gets the month-of-year field from 1 to 12.
+     * <p>
+     * This method returns the month as an {@code int} from 1 to 12.
+     * Application code is frequently clearer if the enum {@link Month}
+     * is used by calling {@link #getMonth()}.
+     *
+     * @return the month-of-year, from 1 to 12
+     * @see #getMonth()
+     */
+    public int getMonthValue() {
+        return dateTime.getMonthValue();
+    }
+
+    /**
+     * Gets the month-of-year field using the {@code Month} enum.
+     * <p>
+     * This method returns the enum {@link Month} for the month.
+     * This avoids confusion as to what {@code int} values mean.
+     * If you need access to the primitive {@code int} value then the enum
+     * provides the {@link Month#getValue() int value}.
+     *
+     * @return the month-of-year, not null
+     * @see #getMonthValue()
+     */
+    public Month getMonth() {
+        return dateTime.getMonth();
+    }
+
+    /**
+     * Gets the day-of-month field.
+     * <p>
+     * This method returns the primitive {@code int} value for the day-of-month.
+     *
+     * @return the day-of-month, from 1 to 31
+     */
+    public int getDayOfMonth() {
+        return dateTime.getDayOfMonth();
+    }
+
+    /**
+     * Gets the day-of-year field.
+     * <p>
+     * This method returns the primitive {@code int} value for the day-of-year.
+     *
+     * @return the day-of-year, from 1 to 365, or 366 in a leap year
+     */
+    public int getDayOfYear() {
+        return dateTime.getDayOfYear();
+    }
+
+    /**
+     * Gets the day-of-week field, which is an enum {@code DayOfWeek}.
+     * <p>
+     * This method returns the enum {@link 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 DayOfWeek#getValue() int value}.
+     * <p>
+     * Additional information can be obtained from the {@code DayOfWeek}.
+     * This includes textual names of the values.
+     *
+     * @return the day-of-week, not null
+     */
+    public DayOfWeek getDayOfWeek() {
+        return dateTime.getDayOfWeek();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the {@code LocalTime} part of this date-time.
+     * <p>
+     * This returns a {@code LocalTime} with the same hour, minute, second and
+     * nanosecond as this date-time.
+     *
+     * @return the time part of this date-time, not null
+     */
+    @Override  // override for Javadoc and performance
+    public LocalTime getTime() {
+        return dateTime.getTime();
+    }
+
+    /**
+     * Gets the hour-of-day field.
+     *
+     * @return the hour-of-day, from 0 to 23
+     */
+    public int getHour() {
+        return dateTime.getHour();
+    }
+
+    /**
+     * Gets the minute-of-hour field.
+     *
+     * @return the minute-of-hour, from 0 to 59
+     */
+    public int getMinute() {
+        return dateTime.getMinute();
+    }
+
+    /**
+     * Gets the second-of-minute field.
+     *
+     * @return the second-of-minute, from 0 to 59
+     */
+    public int getSecond() {
+        return dateTime.getSecond();
+    }
+
+    /**
+     * Gets the nano-of-second field.
+     *
+     * @return the nano-of-second, from 0 to 999,999,999
+     */
+    public int getNano() {
+        return dateTime.getNano();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns an adjusted copy of this date-time.
+     * <p>
+     * This returns a new {@code ZonedDateTime}, based on this one, with the date-time adjusted.
+     * The adjustment takes place using the specified adjuster strategy object.
+     * Read the documentation of the adjuster to understand what adjustment will be made.
+     * <p>
+     * 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.
+     * <p>
+     * For example this code returns a date on the last day of July:
+     * <pre>
+     *  import static java.time.Month.*;
+     *  import static java.time.temporal.Adjusters.*;
+     *
+     *  result = zonedDateTime.with(JULY).with(lastDayOfMonth());
+     * </pre>
+     * <p>
+     * The classes {@link LocalDate} and {@link LocalTime} implement {@code TemporalAdjuster},
+     * thus this method can be used to change the date, time or offset:
+     * <pre>
+     *  result = zonedDateTime.with(date);
+     *  result = zonedDateTime.with(time);
+     * </pre>
+     * <p>
+     * {@link ZoneOffset} also implements {@code TemporalAdjuster} however it is less likely
+     * that setting the offset will have the effect you expect. When an offset is passed in,
+     * the local date-time is combined with the new offset to form an {@code Instant}.
+     * The instant and original zone are then used to create the result.
+     * This algorithm means that it is quite likely that the output has a different offset
+     * to the specified offset. It will however work correctly when passing in the offset
+     * applicable for the instant of the zoned date-time, and will work correctly if passing
+     * one of the two valid offsets during a daylight savings overlap when the same local time
+     * occurs twice.
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param adjuster the adjuster to use, not null
+     * @return a {@code ZonedDateTime} 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 ZonedDateTime with(TemporalAdjuster adjuster) {
+        // optimizations
+        if (adjuster instanceof LocalDate) {
+            return resolveLocal(LocalDateTime.of((LocalDate) adjuster, dateTime.getTime()));
+        } else if (adjuster instanceof LocalTime) {
+            return resolveLocal(LocalDateTime.of(dateTime.getDate(), (LocalTime) adjuster));
+        } else if (adjuster instanceof LocalDateTime) {
+            return resolveLocal((LocalDateTime) adjuster);
+        } else if (adjuster instanceof Instant) {
+            Instant instant = (Instant) adjuster;
+            return create(instant.getEpochSecond(), instant.getNano(), zone);
+        } else if (adjuster instanceof ZoneOffset) {
+            return resolveOffset((ZoneOffset) adjuster);
+        }
+        return (ZonedDateTime) adjuster.adjustInto(this);
+    }
+
+    /**
+     * Returns a copy of this date-time with the specified field set to a new value.
+     * <p>
+     * This returns a new {@code ZonedDateTime}, 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.
+     * <p>
+     * In some cases, changing the specified field can cause the resulting date-time to become invalid,
+     * such as changing the month from 31st January to February would make the day-of-month invalid.
+     * In cases like this, the field is responsible for resolving the date. Typically it will choose
+     * the previous valid date, which would be the last valid day of February in this example.
+     * <p>
+     * If the field is a {@link ChronoField} then the adjustment is implemented here.
+     * <p>
+     * The {@code INSTANT_SECONDS} field will return a date-time with the specified instant.
+     * The zone and nano-of-second are unchanged.
+     * The result will have an offset derived from the new instant and original zone.
+     * If the new instant value is outside the valid range then a {@code DateTimeException} will be thrown.
+     * <p>
+     * The {@code OFFSET_SECONDS} field will return a date-time calculated using the specified offset.
+     * The local date-time is combined with the new offset to form an {@code Instant}.
+     * The instant and original zone are then used to create the result.
+     * This algorithm means that it is quite likely that the output has a different offset
+     * to the specified offset. It will however work correctly when passing in the offset
+     * applicable for the instant of the zoned date-time, and will work correctly if passing
+     * one of the two valid offsets during a daylight savings overlap when the same local time
+     * occurs twice. If the new offset value is outside the valid range then a
+     * {@code DateTimeException} will be thrown.
+     * <p>
+     * The other {@link #isSupported(TemporalField) supported fields} will behave as per
+     * the matching method on {@link LocalDateTime#with(TemporalField, long) LocalDateTime}.
+     * The zone is not part of the calculation and will be unchanged.
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param field  the field to set in the result, not null
+     * @param newValue  the new value of the field in the result
+     * @return a {@code ZonedDateTime} 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 ZonedDateTime with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            switch (f) {
+                case INSTANT_SECONDS: return create(newValue, getNano(), zone);
+                case OFFSET_SECONDS: {
+                    ZoneOffset offset = ZoneOffset.ofTotalSeconds(f.checkValidIntValue(newValue));
+                    return resolveOffset(offset);
+                }
+            }
+            return resolveLocal(dateTime.with(field, newValue));
+        }
+        return field.doWith(this, newValue);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the year value altered.
+     * <p>
+     * This operates on the local time-line,
+     * {@link LocalDateTime#withYear(int) changing the year} of the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * 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 a {@code ZonedDateTime} based on this date-time with the requested year, not null
+     * @throws DateTimeException if the year value is invalid
+     */
+    public ZonedDateTime withYear(int year) {
+        return resolveLocal(dateTime.withYear(year));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the month-of-year value altered.
+     * <p>
+     * This operates on the local time-line,
+     * {@link LocalDateTime#withMonth(int) changing the month} of the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * 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 a {@code ZonedDateTime} based on this date-time with the requested month, not null
+     * @throws DateTimeException if the month-of-year value is invalid
+     */
+    public ZonedDateTime withMonth(int month) {
+        return resolveLocal(dateTime.withMonth(month));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the day-of-month value altered.
+     * <p>
+     * This operates on the local time-line,
+     * {@link LocalDateTime#withDayOfMonth(int) changing the day-of-month} of the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * 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 a {@code ZonedDateTime} based on this date-time with the requested day, not null
+     * @throws DateTimeException if the day-of-month value is invalid
+     * @throws DateTimeException if the day-of-month is invalid for the month-year
+     */
+    public ZonedDateTime withDayOfMonth(int dayOfMonth) {
+        return resolveLocal(dateTime.withDayOfMonth(dayOfMonth));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the day-of-year altered.
+     * <p>
+     * This operates on the local time-line,
+     * {@link LocalDateTime#withDayOfYear(int) changing the day-of-year} of the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * 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 a {@code ZonedDateTime} 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 ZonedDateTime withDayOfYear(int dayOfYear) {
+        return resolveLocal(dateTime.withDayOfYear(dayOfYear));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the hour-of-day value altered.
+     * <p>
+     * This operates on the local time-line,
+     * {@linkplain LocalDateTime#withHour(int) changing the time} of the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hour  the hour-of-day to set in the result, from 0 to 23
+     * @return a {@code ZonedDateTime} based on this date-time with the requested hour, not null
+     * @throws DateTimeException if the hour value is invalid
+     */
+    public ZonedDateTime withHour(int hour) {
+        return resolveLocal(dateTime.withHour(hour));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the minute-of-hour value altered.
+     * <p>
+     * This operates on the local time-line,
+     * {@linkplain LocalDateTime#withMinute(int) changing the time} of the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minute  the minute-of-hour to set in the result, from 0 to 59
+     * @return a {@code ZonedDateTime} based on this date-time with the requested minute, not null
+     * @throws DateTimeException if the minute value is invalid
+     */
+    public ZonedDateTime withMinute(int minute) {
+        return resolveLocal(dateTime.withMinute(minute));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the second-of-minute value altered.
+     * <p>
+     * This operates on the local time-line,
+     * {@linkplain LocalDateTime#withSecond(int) changing the time} of the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param second  the second-of-minute to set in the result, from 0 to 59
+     * @return a {@code ZonedDateTime} based on this date-time with the requested second, not null
+     * @throws DateTimeException if the second value is invalid
+     */
+    public ZonedDateTime withSecond(int second) {
+        return resolveLocal(dateTime.withSecond(second));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the nano-of-second value altered.
+     * <p>
+     * This operates on the local time-line,
+     * {@linkplain LocalDateTime#withNano(int) changing the time} of the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanoOfSecond  the nano-of-second to set in the result, from 0 to 999,999,999
+     * @return a {@code ZonedDateTime} based on this date-time with the requested nanosecond, not null
+     * @throws DateTimeException if the nano value is invalid
+     */
+    public ZonedDateTime withNano(int nanoOfSecond) {
+        return resolveLocal(dateTime.withNano(nanoOfSecond));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the time truncated.
+     * <p>
+     * Truncation returns a copy of the original date-time with fields
+     * smaller than the specified unit set to zero.
+     * For example, truncating with the {@link ChronoUnit#MINUTES minutes} unit
+     * will set the second-of-minute and nano-of-second field to zero.
+     * <p>
+     * Not all units are accepted. The {@link ChronoUnit#DAYS days} unit and time
+     * units with an exact duration can be used, other units throw an exception.
+     * <p>
+     * This operates on the local time-line,
+     * {@link LocalDateTime#truncatedTo(java.time.temporal.TemporalUnit) truncating}
+     * the underlying local date-time. This is then converted back to a
+     * {@code ZonedDateTime}, using the zone ID to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param unit  the unit to truncate to, not null
+     * @return a {@code ZonedDateTime} based on this date-time with the time truncated, not null
+     * @throws DateTimeException if unable to truncate
+     */
+    public ZonedDateTime truncatedTo(TemporalUnit unit) {
+        return resolveLocal(dateTime.truncatedTo(unit));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this date-time with the specified period added.
+     * <p>
+     * This method returns a new date-time based on this time with the specified period added.
+     * The adder is typically {@link 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)}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param adder  the adder to use, not null
+     * @return a {@code ZonedDateTime} based on this date-time with the addition made, not null
+     * @throws DateTimeException if the addition cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public ZonedDateTime plus(TemporalAdder adder) {
+        return (ZonedDateTime) adder.addTo(this);
+    }
+
+    /**
+     * Returns a copy of this date-time with the specified period added.
+     * <p>
+     * This method returns a new date-time based on this date-time with the specified period added.
+     * This can be used to add any period that is defined by a unit, for example to add years, months or days.
+     * The unit is responsible for the details of the calculation, including the resolution
+     * of any edge cases in the calculation.
+     * <p>
+     * The calculation for date and time units differ.
+     * <p>
+     * Date units operate on the local time-line.
+     * The period is first added to the local date-time, then converted back
+     * to a zoned date-time using the zone ID.
+     * The conversion uses {@link #ofLocal(LocalDateTime, ZoneId, ZoneOffset)}
+     * with the offset before the addition.
+     * <p>
+     * Time units operate on the instant time-line.
+     * The period is first added to the local date-time, then converted back to
+     * a zoned date-time using the zone ID.
+     * The conversion uses {@link #ofInstant(LocalDateTime, ZoneOffset, ZoneId)}
+     * with the offset before the addition.
+     * <p>
+     * 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 a {@code ZonedDateTime} based on this date-time with the specified period added, not null
+     * @throws DateTimeException if the unit cannot be added to this type
+     */
+    @Override
+    public ZonedDateTime plus(long amountToAdd, TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            ChronoUnit u = (ChronoUnit) unit;
+            if (u.isDateUnit()) {
+                return resolveLocal(dateTime.plus(amountToAdd, unit));
+            } else {
+                return resolveInstant(dateTime.plus(amountToAdd, unit));
+            }
+        }
+        return unit.doPlus(this, amountToAdd);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified period in years added.
+     * <p>
+     * This operates on the local time-line,
+     * {@link LocalDateTime#plusYears(long) adding years} to the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param years  the years to add, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the years added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime plusYears(long years) {
+        return resolveLocal(dateTime.plusYears(years));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified period in months added.
+     * <p>
+     * This operates on the local time-line,
+     * {@link LocalDateTime#plusMonths(long) adding months} to the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param months  the months to add, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the months added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime plusMonths(long months) {
+        return resolveLocal(dateTime.plusMonths(months));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified period in weeks added.
+     * <p>
+     * This operates on the local time-line,
+     * {@link LocalDateTime#plusWeeks(long) adding weeks} to the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param weeks  the weeks to add, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the weeks added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime plusWeeks(long weeks) {
+        return resolveLocal(dateTime.plusWeeks(weeks));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified period in days added.
+     * <p>
+     * This operates on the local time-line,
+     * {@link LocalDateTime#plusDays(long) adding days} to the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param days  the days to add, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the days added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime plusDays(long days) {
+        return resolveLocal(dateTime.plusDays(days));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified period in hours added.
+     * <p>
+     * This operates on the instant time-line, such that adding one hour will
+     * always be a duration of one hour later.
+     * This may cause the local date-time to change by an amount other than one hour.
+     * Note that this is a different approach to that used by days, months and years,
+     * thus adding one day is not the same as adding 24 hours.
+     * <p>
+     * For example, consider a time-zone where the spring DST cutover means that the
+     * local times 01:00 to 01:59 occur twice changing from offset +02:00 to +01:00.
+     * <p><ul>
+     * <li>Adding one hour to 00:30+02:00 will result in 01:30+02:00
+     * <li>Adding one hour to 01:30+02:00 will result in 01:30+01:00
+     * <li>Adding one hour to 01:30+01:00 will result in 02:30+01:00
+     * <li>Adding three hours to 00:30+02:00 will result in 02:30+01:00
+     * </ul><p>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hours  the hours to add, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the hours added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime plusHours(long hours) {
+        return resolveInstant(dateTime.plusHours(hours));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified period in minutes added.
+     * <p>
+     * This operates on the instant time-line, such that adding one minute will
+     * always be a duration of one minute later.
+     * This may cause the local date-time to change by an amount other than one minute.
+     * Note that this is a different approach to that used by days, months and years.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minutes  the minutes to add, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the minutes added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime plusMinutes(long minutes) {
+        return resolveInstant(dateTime.plusMinutes(minutes));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified period in seconds added.
+     * <p>
+     * This operates on the instant time-line, such that adding one second will
+     * always be a duration of one second later.
+     * This may cause the local date-time to change by an amount other than one second.
+     * Note that this is a different approach to that used by days, months and years.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param seconds  the seconds to add, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the seconds added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime plusSeconds(long seconds) {
+        return resolveInstant(dateTime.plusSeconds(seconds));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified period in nanoseconds added.
+     * <p>
+     * This operates on the instant time-line, such that adding one nano will
+     * always be a duration of one nano later.
+     * This may cause the local date-time to change by an amount other than one nano.
+     * Note that this is a different approach to that used by days, months and years.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanos  the nanos to add, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the nanoseconds added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime plusNanos(long nanos) {
+        return resolveInstant(dateTime.plusNanos(nanos));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this date-time with the specified period subtracted.
+     * <p>
+     * This method returns a new date-time based on this time with the specified period subtracted.
+     * The subtractor is typically {@link 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)}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param subtractor  the subtractor to use, not null
+     * @return a {@code ZonedDateTime} based on this date-time with the subtraction made, not null
+     * @throws DateTimeException if the subtraction cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public ZonedDateTime minus(TemporalSubtractor subtractor) {
+        return (ZonedDateTime) subtractor.subtractFrom(this);
+    }
+
+    /**
+     * Returns a copy of this date-time with the specified period subtracted.
+     * <p>
+     * This method returns a new date-time based on this date-time with the specified period subtracted.
+     * This can be used to subtract any period that is defined by a unit, for example to subtract years, months or days.
+     * The unit is responsible for the details of the calculation, including the resolution
+     * of any edge cases in the calculation.
+     * <p>
+     * The calculation for date and time units differ.
+     * <p>
+     * Date units operate on the local time-line.
+     * The period is first subtracted from the local date-time, then converted back
+     * to a zoned date-time using the zone ID.
+     * The conversion uses {@link #ofLocal(LocalDateTime, ZoneId, ZoneOffset)}
+     * with the offset before the subtraction.
+     * <p>
+     * Time units operate on the instant time-line.
+     * The period is first subtracted from the local date-time, then converted back to
+     * a zoned date-time using the zone ID.
+     * The conversion uses {@link #ofInstant(LocalDateTime, ZoneOffset, ZoneId)}
+     * with the offset before the subtraction.
+     * <p>
+     * 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 a {@code ZonedDateTime} based on this date-time with the specified period subtracted, not null
+     * @throws DateTimeException if the unit cannot be added to this type
+     */
+    @Override
+    public ZonedDateTime 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 ZonedDateTime} with the specified period in years subtracted.
+     * <p>
+     * This operates on the local time-line,
+     * {@link LocalDateTime#minusYears(long) subtracting years} to the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param years  the years to subtract, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the years subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime minusYears(long years) {
+        return (years == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-years));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified period in months subtracted.
+     * <p>
+     * This operates on the local time-line,
+     * {@link LocalDateTime#minusMonths(long) subtracting months} to the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param months  the months to subtract, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the months subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime minusMonths(long months) {
+        return (months == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-months));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified period in weeks subtracted.
+     * <p>
+     * This operates on the local time-line,
+     * {@link LocalDateTime#minusWeeks(long) subtracting weeks} to the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param weeks  the weeks to subtract, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the weeks subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime minusWeeks(long weeks) {
+        return (weeks == Long.MIN_VALUE ? plusWeeks(Long.MAX_VALUE).plusWeeks(1) : plusWeeks(-weeks));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified period in days subtracted.
+     * <p>
+     * This operates on the local time-line,
+     * {@link LocalDateTime#minusDays(long) subtracting days} to the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param days  the days to subtract, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the days subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime minusDays(long days) {
+        return (days == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-days));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified period in hours subtracted.
+     * <p>
+     * This operates on the instant time-line, such that subtracting one hour will
+     * always be a duration of one hour earlier.
+     * This may cause the local date-time to change by an amount other than one hour.
+     * Note that this is a different approach to that used by days, months and years,
+     * thus subtracting one day is not the same as adding 24 hours.
+     * <p>
+     * For example, consider a time-zone where the spring DST cutover means that the
+     * local times 01:00 to 01:59 occur twice changing from offset +02:00 to +01:00.
+     * <p><ul>
+     * <li>Subtracting one hour from 02:30+01:00 will result in 01:30+02:00
+     * <li>Subtracting one hour from 01:30+01:00 will result in 01:30+02:00
+     * <li>Subtracting one hour from 01:30+02:00 will result in 00:30+01:00
+     * <li>Subtracting three hours from 02:30+01:00 will result in 00:30+02:00
+     * </ul><p>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hours  the hours to subtract, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the hours subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime minusHours(long hours) {
+        return (hours == Long.MIN_VALUE ? plusHours(Long.MAX_VALUE).plusHours(1) : plusHours(-hours));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified period in minutes subtracted.
+     * <p>
+     * This operates on the instant time-line, such that subtracting one minute will
+     * always be a duration of one minute earlier.
+     * This may cause the local date-time to change by an amount other than one minute.
+     * Note that this is a different approach to that used by days, months and years.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minutes  the minutes to subtract, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the minutes subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime minusMinutes(long minutes) {
+        return (minutes == Long.MIN_VALUE ? plusMinutes(Long.MAX_VALUE).plusMinutes(1) : plusMinutes(-minutes));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified period in seconds subtracted.
+     * <p>
+     * This operates on the instant time-line, such that subtracting one second will
+     * always be a duration of one second earlier.
+     * This may cause the local date-time to change by an amount other than one second.
+     * Note that this is a different approach to that used by days, months and years.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param seconds  the seconds to subtract, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the seconds subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime minusSeconds(long seconds) {
+        return (seconds == Long.MIN_VALUE ? plusSeconds(Long.MAX_VALUE).plusSeconds(1) : plusSeconds(-seconds));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified period in nanoseconds subtracted.
+     * <p>
+     * This operates on the instant time-line, such that subtracting one nano will
+     * always be a duration of one nano earlier.
+     * This may cause the local date-time to change by an amount other than one nano.
+     * Note that this is a different approach to that used by days, months and years.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanos  the nanos to subtract, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the nanoseconds subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime minusNanos(long nanos) {
+        return (nanos == Long.MIN_VALUE ? plusNanos(Long.MAX_VALUE).plusNanos(1) : plusNanos(-nanos));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this date-time using the specified query.
+     * <p>
+     * This queries this date-time using the specified query strategy object.
+     * The {@code TemporalQuery} object defines the logic to be used to
+     * obtain the result. Read the documentation of the query to understand
+     * what the result of this method will be.
+     * <p>
+     * The result of this method is obtained by invoking the
+     * {@link java.time.temporal.TemporalQuery#queryFrom(TemporalAccessor)} method on the
+     * specified query passing {@code this} as the argument.
+     *
+     * @param <R> 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)
+     */
+    @Override  // override for Javadoc
+    public <R> R query(TemporalQuery<R> query) {
+        return ChronoZonedDateTime.super.query(query);
+    }
+
+    /**
+     * Calculates the period between this date-time and another date-time in
+     * terms of the specified unit.
+     * <p>
+     * This calculates the period between two date-times in terms of a single unit.
+     * The start and end points are {@code this} and the specified date-time.
+     * The result will be negative if the end is before the start.
+     * For example, the period in days between two date-times can be calculated
+     * using {@code startDateTime.periodUntil(endDateTime, DAYS)}.
+     * <p>
+     * The {@code Temporal} passed to this method must be a {@code ZonedDateTime}.
+     * If the time-zone differs between the two zoned date-times, the specified
+     * end date-time is normalized to have the same zone as this date-time.
+     * <p>
+     * The calculation returns a whole number, representing the number of
+     * complete units between the two date-times.
+     * For example, the period in months between 2012-06-15T00:00Z and 2012-08-14T23:59Z
+     * will only be one month as it is one minute short of two months.
+     * <p>
+     * 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:
+     * <pre>
+     *   long period = start.periodUntil(end, MONTHS);   // this method
+     *   dateTime.plus(MONTHS.between(start, end));      // use in plus/minus
+     * </pre>
+     * <p>
+     * The calculation is implemented in this method for {@link ChronoUnit}.
+     * The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS},
+     * {@code MINUTES}, {@code HOURS} and {@code HALF_DAYS}, {@code DAYS},
+     * {@code WEEKS}, {@code MONTHS}, {@code YEARS}, {@code DECADES},
+     * {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS} are supported.
+     * Other {@code ChronoUnit} values will throw an exception.
+     * <p>
+     * The calculation for date and time units differ.
+     * <p>
+     * Date units operate on the local time-line, using the local date-time.
+     * For example, the period from noon on day 1 to noon the following day
+     * in days will always be counted as exactly one day, irrespective of whether
+     * there was a daylight savings change or not.
+     * <p>
+     * Time units operate on the instant time-line.
+     * The calculation effectively converts both zoned date-times to instants
+     * and then calculates the period between the instants.
+     * For example, the period from noon on day 1 to noon the following day
+     * in hours may be 23, 24 or 25 hours (or some other amount) depending on
+     * whether there was a daylight savings change or not.
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param endDateTime  the end date-time, which must be a {@code ZonedDateTime}, not null
+     * @param unit  the unit to measure the period in, not null
+     * @return the amount of the period between this date-time and the end date-time
+     * @throws DateTimeException if the period cannot be calculated
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long periodUntil(Temporal endDateTime, TemporalUnit unit) {
+        if (endDateTime instanceof ZonedDateTime == false) {
+            Objects.requireNonNull(endDateTime, "endDateTime");
+            throw new DateTimeException("Unable to calculate period between objects of two different types");
+        }
+        if (unit instanceof ChronoUnit) {
+            ZonedDateTime end = (ZonedDateTime) endDateTime;
+            end = end.withZoneSameInstant(zone);
+            ChronoUnit u = (ChronoUnit) unit;
+            if (u.isDateUnit()) {
+                return dateTime.periodUntil(end.dateTime, unit);
+            } else {
+                return toOffsetDateTime().periodUntil(end.toOffsetDateTime(), unit);
+            }
+        }
+        return unit.between(this, endDateTime).getAmount();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Converts this date-time to an {@code OffsetDateTime}.
+     * <p>
+     * This creates an offset date-time using the local date-time and offset.
+     * The zone ID is ignored.
+     *
+     * @return an offset date-time representing the same local date-time and offset, not null
+     */
+    public OffsetDateTime toOffsetDateTime() {
+        return OffsetDateTime.of(dateTime, offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this date-time is equal to another date-time.
+     * <p>
+     * The comparison is based on the offset date-time and the zone.
+     * Only objects of type {@code ZonedDateTime} are compared, other types return false.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other date-time
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof ZonedDateTime) {
+            ZonedDateTime other = (ZonedDateTime) obj;
+            return dateTime.equals(other.dateTime) &&
+                offset.equals(other.offset) &&
+                zone.equals(other.zone);
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this date-time.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return dateTime.hashCode() ^ offset.hashCode() ^ Integer.rotateLeft(zone.hashCode(), 3);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this date-time as a {@code String}, such as
+     * {@code 2007-12-03T10:15:30+01:00[Europe/Paris]}.
+     * <p>
+     * The format consists of the {@code LocalDateTime} followed by the {@code ZoneOffset}.
+     * If the {@code ZoneId} is not the same as the offset, then the ID is output.
+     * The output is compatible with ISO-8601 if the offset and ID are the same.
+     *
+     * @return a string representation of this date-time, not null
+     */
+    @Override  // override for Javadoc
+    public String toString() {
+        String str = dateTime.toString() + offset.toString();
+        if (offset != zone) {
+            str += '[' + zone.toString() + ']';
+        }
+        return str;
+    }
+
+    /**
+     * Outputs this date-time as a {@code String} using the formatter.
+     * <p>
+     * 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-time string, not null
+     * @throws DateTimeException if an error occurs during printing
+     */
+    @Override  // override for Javadoc
+    public String toString(DateTimeFormatter formatter) {
+        return ChronoZonedDateTime.super.toString(formatter);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * <pre>
+     *  out.writeByte(6);  // identifies this as a ZonedDateTime
+     *  // the <a href="../../serialized-form.html#java.time.LocalDateTime">date-time</a> excluding the one byte header
+     *  // the <a href="../../serialized-form.html#java.time.ZoneOffset">offset</a> excluding the one byte header
+     *  // the <a href="../../serialized-form.html#java.time.ZoneId">zone ID</a> excluding the one byte header
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.ZONE_DATE_TIME_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     * @return never
+     * @throws InvalidObjectException always
+     */
+    private Object readResolve() throws ObjectStreamException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        dateTime.writeExternal(out);
+        offset.writeExternal(out);
+        zone.write(out);
+    }
+
+    static ZonedDateTime readExternal(DataInput in) throws IOException {
+        LocalDateTime dateTime = LocalDateTime.readExternal(in);
+        ZoneOffset offset = ZoneOffset.readExternal(in);
+        ZoneId zone = (ZoneId) Ser.read(in);
+        return ZonedDateTime.ofLenient(dateTime, offset, zone);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/calendar/ChronoDateImpl.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.calendar;
+
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.ERA;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.YEAR_OF_ERA;
+
+import java.io.Serializable;
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.temporal.Chrono;
+import java.time.temporal.ChronoLocalDate;
+import java.time.temporal.ChronoLocalDateTime;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalUnit;
+
+/**
+ * A date expressed in terms of a standard year-month-day calendar system.
+ * <p>
+ * This class is used by applications seeking to handle dates in non-ISO calendar systems.
+ * For example, the Japanese, Minguo, Thai Buddhist and others.
+ * <p>
+ * {@code ChronoLocalDate} is built on the generic concepts of year, month and day.
+ * The calendar system, represented by a {@link java.time.temporal.Chrono}, expresses the relationship between
+ * the fields and this class allows the resulting date to be manipulated.
+ * <p>
+ * Note that not all calendar systems are suitable for use with this class.
+ * For example, the Mayan calendar uses a system that bears no relation to years, months and days.
+ * <p>
+ * The API design encourages the use of {@code LocalDate} for the majority of the application.
+ * This includes code to read and write from a persistent data store, such as a database,
+ * and to send dates and times across a network. The {@code ChronoLocalDate} instance is then used
+ * at the user interface level to deal with localized input/output.
+ *
+ * <P>Example: </p>
+ * <pre>
+ *        System.out.printf("Example()%n");
+ *        // Enumerate the list of available calendars and print today for each
+ *        Set&lt;Chrono&gt; chronos = Chrono.getAvailableChronologies();
+ *        for (Chrono chrono : chronos) {
+ *            ChronoLocalDate<?> date = chrono.dateNow();
+ *            System.out.printf("   %20s: %s%n", chrono.getID(), date.toString());
+ *        }
+ *
+ *        // Print the Hijrah date and calendar
+ *        ChronoLocalDate<?> date = Chrono.of("Hijrah").dateNow();
+ *        int day = date.get(ChronoField.DAY_OF_MONTH);
+ *        int dow = date.get(ChronoField.DAY_OF_WEEK);
+ *        int month = date.get(ChronoField.MONTH_OF_YEAR);
+ *        int year = date.get(ChronoField.YEAR);
+ *        System.out.printf("  Today is %s %s %d-%s-%d%n", date.getChrono().getID(),
+ *                dow, day, month, year);
+
+ *        // Print today's date and the last day of the year
+ *        ChronoLocalDate<?> now1 = Chrono.of("Hijrah").dateNow();
+ *        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("  Today is %s: start: %s; end: %s%n", last.getChrono().getID(),
+ *                first, last);
+ * </pre>
+ *
+ * <h3>Adding Calendars</h3>
+ * <p> The set of calendars is extensible by defining a subclass of {@link ChronoLocalDate}
+ * to represent a date instance and an implementation of {@code Chrono}
+ * to be the factory for the ChronoLocalDate subclass.
+ * </p>
+ * <p> To permit the discovery of the additional calendar types the implementation of
+ * {@code Chrono} must be registered as a Service implementing the {@code Chrono} interface
+ * in the {@code META-INF/Services} file as per the specification of {@link java.util.ServiceLoader}.
+ * The subclass must function according to the {@code Chrono} class description and must provide its
+ * {@link java.time.temporal.Chrono#getId() chronlogy ID} and {@link Chrono#getCalendarType() calendar type}. </p>
+ *
+ * <h3>Specification for implementors</h3>
+ * This abstract class must be implemented with care to ensure other classes operate correctly.
+ * All implementations that can be instantiated must be final, immutable and thread-safe.
+ * Subclasses should be Serializable wherever possible.
+ *
+ * @param <C> the chronology of this date
+ * @since 1.8
+ */
+abstract class ChronoDateImpl<C extends Chrono<C>>
+        implements ChronoLocalDate<C>, Temporal, TemporalAdjuster, Serializable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 6282433883239719096L;
+
+    /**
+     * Creates an instance.
+     */
+    ChronoDateImpl() {
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ChronoLocalDate<C> plus(long amountToAdd, TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            ChronoUnit f = (ChronoUnit) unit;
+            switch (f) {
+                case DAYS: return plusDays(amountToAdd);
+                case WEEKS: return plusDays(Math.multiplyExact(amountToAdd, 7));
+                case MONTHS: return plusMonths(amountToAdd);
+                case YEARS: return plusYears(amountToAdd);
+                case DECADES: return plusYears(Math.multiplyExact(amountToAdd, 10));
+                case CENTURIES: return plusYears(Math.multiplyExact(amountToAdd, 100));
+                case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000));
+                case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd));
+            }
+            throw new DateTimeException("Unsupported unit: " + unit.getName());
+        }
+        return ChronoLocalDate.super.plus(amountToAdd, unit);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this date with the specified period in years added.
+     * <p>
+     * This adds the specified period in years to the date.
+     * In some cases, adding years can cause the resulting date to become invalid.
+     * If this occurs, then other fields, typically the day-of-month, will be adjusted to ensure
+     * that the result is valid. Typically this will select the last valid day of the month.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param yearsToAdd  the years to add, may be negative
+     * @return a date based on this one with the years added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    abstract ChronoDateImpl<C> plusYears(long yearsToAdd);
+
+    /**
+     * Returns a copy of this date with the specified period in months added.
+     * <p>
+     * This adds the specified period in months to the date.
+     * In some cases, adding months can cause the resulting date to become invalid.
+     * If this occurs, then other fields, typically the day-of-month, will be adjusted to ensure
+     * that the result is valid. Typically this will select the last valid day of the month.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param monthsToAdd  the months to add, may be negative
+     * @return a date based on this one with the months added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    abstract ChronoDateImpl<C> plusMonths(long monthsToAdd);
+
+    /**
+     * Returns a copy of this date with the specified period in weeks added.
+     * <p>
+     * This adds the specified period in weeks to the date.
+     * In some cases, adding weeks can cause the resulting date to become invalid.
+     * If this occurs, then other fields will be adjusted to ensure that the result is valid.
+     * <p>
+     * The default implementation uses {@link #plusDays(long)} using a 7 day week.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param weeksToAdd  the weeks to add, may be negative
+     * @return a date based on this one with the weeks added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    ChronoDateImpl<C> plusWeeks(long weeksToAdd) {
+        return plusDays(Math.multiplyExact(weeksToAdd, 7));
+    }
+
+    /**
+     * Returns a copy of this date with the specified number of days added.
+     * <p>
+     * This adds the specified period in days to the date.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param daysToAdd  the days to add, may be negative
+     * @return a date based on this one with the days added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    abstract ChronoDateImpl<C> plusDays(long daysToAdd);
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this date with the specified period in years subtracted.
+     * <p>
+     * This subtracts the specified period in years to the date.
+     * In some cases, subtracting years can cause the resulting date to become invalid.
+     * If this occurs, then other fields, typically the day-of-month, will be adjusted to ensure
+     * that the result is valid. Typically this will select the last valid day of the month.
+     * <p>
+     * The default implementation uses {@link #plusYears(long)}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param yearsToSubtract  the years to subtract, may be negative
+     * @return a date based on this one with the years subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    ChronoDateImpl<C> minusYears(long yearsToSubtract) {
+        return (yearsToSubtract == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-yearsToSubtract));
+    }
+
+    /**
+     * Returns a copy of this date with the specified period in months subtracted.
+     * <p>
+     * This subtracts the specified period in months to the date.
+     * In some cases, subtracting months can cause the resulting date to become invalid.
+     * If this occurs, then other fields, typically the day-of-month, will be adjusted to ensure
+     * that the result is valid. Typically this will select the last valid day of the month.
+     * <p>
+     * The default implementation uses {@link #plusMonths(long)}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param monthsToSubtract  the months to subtract, may be negative
+     * @return a date based on this one with the months subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    ChronoDateImpl<C> minusMonths(long monthsToSubtract) {
+        return (monthsToSubtract == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-monthsToSubtract));
+    }
+
+    /**
+     * Returns a copy of this date with the specified period in weeks subtracted.
+     * <p>
+     * This subtracts the specified period in weeks to the date.
+     * In some cases, subtracting weeks can cause the resulting date to become invalid.
+     * If this occurs, then other fields will be adjusted to ensure that the result is valid.
+     * <p>
+     * The default implementation uses {@link #plusWeeks(long)}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param weeksToSubtract  the weeks to subtract, may be negative
+     * @return a date based on this one with the weeks subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    ChronoDateImpl<C> minusWeeks(long weeksToSubtract) {
+        return (weeksToSubtract == Long.MIN_VALUE ? plusWeeks(Long.MAX_VALUE).plusWeeks(1) : plusWeeks(-weeksToSubtract));
+    }
+
+    /**
+     * Returns a copy of this date with the specified number of days subtracted.
+     * <p>
+     * This subtracts the specified period in days to the date.
+     * <p>
+     * The default implementation uses {@link #plusDays(long)}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param daysToSubtract  the days to subtract, may be negative
+     * @return a date based on this one with the days subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    ChronoDateImpl<C> minusDays(long daysToSubtract) {
+        return (daysToSubtract == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-daysToSubtract));
+    }
+
+    @Override
+    public final ChronoLocalDateTime<C> atTime(LocalTime localTime) {
+        return Chrono.dateTime(this, localTime);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public long periodUntil(Temporal endDateTime, TemporalUnit unit) {
+        if (endDateTime instanceof ChronoLocalDate == false) {
+            throw new DateTimeException("Unable to calculate period between objects of two different types");
+        }
+        ChronoLocalDate<?> end = (ChronoLocalDate<?>) endDateTime;
+        if (getChrono().equals(end.getChrono()) == false) {
+            throw new DateTimeException("Unable to calculate period between two different chronologies");
+        }
+        if (unit instanceof ChronoUnit) {
+            return LocalDate.from(this).periodUntil(end, unit);  // TODO: this is wrong
+        }
+        return unit.between(this, endDateTime).getAmount();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof ChronoLocalDate) {
+            return compareTo((ChronoLocalDate<?>) obj) == 0;
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        long epDay = toEpochDay();
+        return getChrono().hashCode() ^ ((int) (epDay ^ (epDay >>> 32)));
+    }
+
+    @Override
+    public String toString() {
+        // getLong() reduces chances of exceptions in toString()
+        long yoe = getLong(YEAR_OF_ERA);
+        long moy = getLong(MONTH_OF_YEAR);
+        long dom = getLong(DAY_OF_MONTH);
+        StringBuilder buf = new StringBuilder(30);
+        buf.append(getChrono().toString())
+                .append(" ")
+                .append(getEra())
+                .append(" ")
+                .append(yoe)
+                .append(moy < 10 ? "-0" : "-").append(moy)
+                .append(dom < 10 ? "-0" : "-").append(dom);
+        return buf.toString();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/calendar/HijrahChrono.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,1341 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package java.time.calendar;
+
+import static java.time.temporal.ChronoField.EPOCH_DAY;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.text.ParseException;
+import java.time.DateTimeException;
+import java.time.temporal.Chrono;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoLocalDate;
+import java.time.temporal.Era;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.ValueRange;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * The Hijrah calendar system.
+ * <p>
+ * This chronology defines the rules of the Hijrah calendar system.
+ * <p>
+ * The implementation follows the Freeman-Grenville algorithm (*1) and has following features.
+ * <p><ul>
+ * <li>A year has 12 months.</li>
+ * <li>Over a cycle of 30 years there are 11 leap years.</li>
+ * <li>There are 30 days in month number 1, 3, 5, 7, 9, and 11,
+ * and 29 days in month number 2, 4, 6, 8, 10, and 12.</li>
+ * <li>In a leap year month 12 has 30 days.</li>
+ * <li>In a 30 year cycle, year 2, 5, 7, 10, 13, 16, 18, 21, 24,
+ * 26, and 29 are leap years.</li>
+ * <li>Total of 10631 days in a 30 years cycle.</li>
+ * </ul><p>
+ * <P>
+ * The table shows the features described above.
+ * <blockquote>
+ * <table border="1">
+ *   <caption>Hijrah Calendar Months</caption>
+ *   <tbody>
+ *     <tr>
+ *       <th># of month</th>
+ *       <th>Name of month</th>
+ *       <th>Number of days</th>
+ *     </tr>
+ *     <tr>
+ *       <td>1</td>
+ *       <td>Muharram</td>
+ *       <td>30</td>
+ *     </tr>
+ *     <tr>
+ *       <td>2</td>
+ *       <td>Safar</td>
+ *       <td>29</td>
+ *     </tr>
+ *     <tr>
+ *       <td>3</td>
+ *       <td>Rabi'al-Awwal</td>
+ *       <td>30</td>
+ *     </tr>
+ *     <tr>
+ *       <td>4</td>
+ *       <td>Rabi'ath-Thani</td>
+ *       <td>29</td>
+ *     </tr>
+ *     <tr>
+ *       <td>5</td>
+ *       <td>Jumada l-Ula</td>
+ *       <td>30</td>
+ *     </tr>
+ *     <tr>
+ *       <td>6</td>
+ *       <td>Jumada t-Tania</td>
+ *       <td>29</td>
+ *     </tr>
+ *     <tr>
+ *       <td>7</td>
+ *       <td>Rajab</td>
+ *       <td>30</td>
+ *     </tr>
+ *     <tr>
+ *       <td>8</td>
+ *       <td>Sha`ban</td>
+ *       <td>29</td>
+ *     </tr>
+ *     <tr>
+ *       <td>9</td>
+ *       <td>Ramadan</td>
+ *       <td>30</td>
+ *     </tr>
+ *     <tr>
+ *       <td>10</td>
+ *       <td>Shawwal</td>
+ *       <td>29</td>
+ *     </tr>
+ *     <tr>
+ *       <td>11</td>
+ *       <td>Dhu 'l-Qa`da</td>
+ *       <td>30</td>
+ *     </tr>
+ *     <tr>
+ *       <td>12</td>
+ *       <td>Dhu 'l-Hijja</td>
+ *       <td>29, but 30 days in years 2, 5, 7, 10,<br>
+ * 13, 16, 18, 21, 24, 26, and 29</td>
+ *     </tr>
+ *   </tbody>
+ * </table>
+ * </blockquote>
+ * <p>
+ * (*1) The algorithm is taken from the book,
+ * The Muslim and Christian Calendars by G.S.P. Freeman-Grenville.
+ * <p>
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class HijrahChrono extends Chrono<HijrahChrono> implements Serializable {
+
+    /**
+     * The Hijrah Calendar id.
+     */
+    private final String typeId;
+
+    /**
+     * The Hijrah calendarType.
+     */
+    private final String calendarType;
+
+    /**
+     * The singleton instance for the era before the current one - Before Hijrah -
+     * which has the value 0.
+     */
+    public static final Era<HijrahChrono> ERA_BEFORE_AH = HijrahEra.BEFORE_AH;
+    /**
+     * The singleton instance for the current era - Hijrah - which has the value 1.
+     */
+    public static final Era<HijrahChrono> ERA_AH = HijrahEra.AH;
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 3127340209035924785L;
+    /**
+     * The minimum valid year-of-era.
+     */
+    public static final int MIN_YEAR_OF_ERA = 1;
+    /**
+     * The maximum valid year-of-era.
+     * This is currently set to 9999 but may be changed to increase the valid range
+     * in a future version of the specification.
+     */
+    public static final int MAX_YEAR_OF_ERA = 9999;
+
+    /**
+     * Number of Gregorian day of July 19, year 622 (Gregorian), which is epoch day
+     * of Hijrah calendar.
+     */
+    private static final int HIJRAH_JAN_1_1_GREGORIAN_DAY = -492148;
+    /**
+     * 0-based, for number of day-of-year in the beginning of month in normal
+     * year.
+     */
+    private static final int NUM_DAYS[] =
+        {0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325};
+    /**
+     * 0-based, for number of day-of-year in the beginning of month in leap year.
+     */
+    private static final int LEAP_NUM_DAYS[] =
+        {0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325};
+    /**
+     * 0-based, for day-of-month in normal year.
+     */
+    private static final int MONTH_LENGTH[] =
+        {30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29};
+    /**
+     * 0-based, for day-of-month in leap year.
+     */
+    private static final int LEAP_MONTH_LENGTH[] =
+        {30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 30};
+
+    /**
+     * <pre>
+     *                            Greatest       Least
+     * Field name        Minimum   Minimum     Maximum     Maximum
+     * ----------        -------   -------     -------     -------
+     * ERA                     0         0           1           1
+     * YEAR_OF_ERA             1         1        9999        9999
+     * MONTH_OF_YEAR           1         1          12          12
+     * DAY_OF_MONTH            1         1          29          30
+     * DAY_OF_YEAR             1         1         354         355
+     * </pre>
+     *
+     * Minimum values.
+     */
+    private static final int MIN_VALUES[] =
+        {
+        0,
+        MIN_YEAR_OF_ERA,
+        0,
+        1,
+        0,
+        1,
+        1
+        };
+
+    /**
+     * Least maximum values.
+     */
+    private static final int LEAST_MAX_VALUES[] =
+        {
+        1,
+        MAX_YEAR_OF_ERA,
+        11,
+        51,
+        5,
+        29,
+        354
+        };
+
+    /**
+     * Maximum values.
+     */
+    private static final int MAX_VALUES[] =
+        {
+        1,
+        MAX_YEAR_OF_ERA,
+        11,
+        52,
+        6,
+        30,
+        355
+        };
+
+   /**
+     * Position of day-of-month. This value is used to get the min/max value
+     * from an array.
+     */
+    private static final int POSITION_DAY_OF_MONTH = 5;
+    /**
+     * Position of day-of-year. This value is used to get the min/max value from
+     * an array.
+     */
+    private static final int POSITION_DAY_OF_YEAR = 6;
+    /**
+     * Zero-based start date of cycle year.
+     */
+    private static final int CYCLEYEAR_START_DATE[] =
+        {
+        0,
+        354,
+        709,
+        1063,
+        1417,
+        1772,
+        2126,
+        2481,
+        2835,
+        3189,
+        3544,
+        3898,
+        4252,
+        4607,
+        4961,
+        5315,
+        5670,
+        6024,
+        6379,
+        6733,
+        7087,
+        7442,
+        7796,
+        8150,
+        8505,
+        8859,
+        9214,
+        9568,
+        9922,
+        10277
+        };
+
+    /**
+     * Holding the adjusted month days in year. The key is a year (Integer) and
+     * the value is the all the month days in year (int[]).
+     */
+    private final HashMap<Integer, int[]> ADJUSTED_MONTH_DAYS = new HashMap<>();
+    /**
+     * Holding the adjusted month length in year. The key is a year (Integer)
+     * and the value is the all the month length in year (int[]).
+     */
+    private final HashMap<Integer, int[]> ADJUSTED_MONTH_LENGTHS = new HashMap<>();
+    /**
+     * Holding the adjusted days in the 30 year cycle. The key is a cycle number
+     * (Integer) and the value is the all the starting days of the year in the
+     * cycle (int[]).
+     */
+    private final HashMap<Integer, int[]> ADJUSTED_CYCLE_YEARS = new HashMap<>();
+    /**
+     * Holding the adjusted cycle in the 1 - 30000 year. The key is the cycle
+     * number (Integer) and the value is the starting days in the cycle in the
+     * term.
+     */
+    private final long[] ADJUSTED_CYCLES;
+    /**
+     * Holding the adjusted min values.
+     */
+    private final int[] ADJUSTED_MIN_VALUES;
+    /**
+     * Holding the adjusted max least max values.
+     */
+    private final int[] ADJUSTED_LEAST_MAX_VALUES;
+    /**
+     * Holding adjusted max values.
+     */
+    private final int[] ADJUSTED_MAX_VALUES;
+    /**
+     * Holding the non-adjusted month days in year for non leap year.
+     */
+    private static final int[] DEFAULT_MONTH_DAYS;
+    /**
+     * Holding the non-adjusted month days in year for leap year.
+     */
+    private static final int[] DEFAULT_LEAP_MONTH_DAYS;
+    /**
+     * Holding the non-adjusted month length for non leap year.
+     */
+    private static final int[] DEFAULT_MONTH_LENGTHS;
+    /**
+     * Holding the non-adjusted month length for leap year.
+     */
+    private static final int[] DEFAULT_LEAP_MONTH_LENGTHS;
+    /**
+     * Holding the non-adjusted 30 year cycle starting day.
+     */
+    private static final int[] DEFAULT_CYCLE_YEARS;
+    /**
+     * number of 30-year cycles to hold the deviation data.
+     */
+    private static final int MAX_ADJUSTED_CYCLE = 334; // to support year 9999
+
+
+    /**
+     * Narrow names for eras.
+     */
+    private static final HashMap<String, String[]> ERA_NARROW_NAMES = new HashMap<>();
+    /**
+     * Short names for eras.
+     */
+    private static final HashMap<String, String[]> ERA_SHORT_NAMES = new HashMap<>();
+    /**
+     * Full names for eras.
+     */
+    private static final HashMap<String, String[]> ERA_FULL_NAMES = new HashMap<>();
+    /**
+     * Fallback language for the era names.
+     */
+    private static final String FALLBACK_LANGUAGE = "en";
+
+    /**
+     * Singleton instance of the Hijrah chronology.
+     * Must be initialized after the rest of the static initialization.
+     */
+    public static final HijrahChrono INSTANCE;
+
+    /**
+     * Name data.
+     */
+    static {
+        ERA_NARROW_NAMES.put(FALLBACK_LANGUAGE, new String[]{"BH", "HE"});
+        ERA_SHORT_NAMES.put(FALLBACK_LANGUAGE, new String[]{"B.H.", "H.E."});
+        ERA_FULL_NAMES.put(FALLBACK_LANGUAGE, new String[]{"Before Hijrah", "Hijrah Era"});
+
+        DEFAULT_MONTH_DAYS = Arrays.copyOf(NUM_DAYS, NUM_DAYS.length);
+
+        DEFAULT_LEAP_MONTH_DAYS = Arrays.copyOf(LEAP_NUM_DAYS, LEAP_NUM_DAYS.length);
+
+        DEFAULT_MONTH_LENGTHS = Arrays.copyOf(MONTH_LENGTH, MONTH_LENGTH.length);
+
+        DEFAULT_LEAP_MONTH_LENGTHS = Arrays.copyOf(LEAP_MONTH_LENGTH, LEAP_MONTH_LENGTH.length);
+
+        DEFAULT_CYCLE_YEARS = Arrays.copyOf(CYCLEYEAR_START_DATE, CYCLEYEAR_START_DATE.length);
+
+        INSTANCE = new HijrahChrono();
+
+        String extraCalendars = java.security.AccessController.doPrivileged(
+            new sun.security.action.GetPropertyAction("java.time.calendar.HijrahCalendars"));
+        if (extraCalendars != null) {
+            try {
+                // Split on whitespace
+                String[] splits = extraCalendars.split("\\s");
+                for (String cal : splits) {
+                    if (!cal.isEmpty()) {
+                        // Split on the delimiter between typeId "-" calendarType
+                        String[] type = cal.split("-");
+                        Chrono<?> cal2 = new HijrahChrono(type[0], type.length > 1 ? type[1] : type[0]);
+                    }
+                }
+            } catch (Exception ex) {
+                // Log the error
+                // ex.printStackTrace();
+            }
+        }
+    }
+
+    /**
+     * Restricted constructor.
+     */
+    private HijrahChrono() {
+        this("Hijrah", "islamicc");
+    }
+    /**
+     * Constructor for name and type HijrahChrono.
+     * @param id the id of the calendar
+     * @param calendarType the calendar type
+     */
+    private HijrahChrono(String id, String calendarType) {
+        this.typeId = id;
+        this.calendarType = calendarType;
+
+        ADJUSTED_CYCLES = new long[MAX_ADJUSTED_CYCLE];
+        for (int i = 0; i < ADJUSTED_CYCLES.length; i++) {
+            ADJUSTED_CYCLES[i] = (10631L * i);
+        }
+        // Initialize min values, least max values and max values.
+        ADJUSTED_MIN_VALUES = Arrays.copyOf(MIN_VALUES, MIN_VALUES.length);
+        ADJUSTED_LEAST_MAX_VALUES = Arrays.copyOf(LEAST_MAX_VALUES, LEAST_MAX_VALUES.length);
+        ADJUSTED_MAX_VALUES = Arrays.copyOf(MAX_VALUES,MAX_VALUES.length);
+
+        try {
+            // Implicitly reads deviation data for this HijrahChronology.
+            boolean any = HijrahDeviationReader.readDeviation(typeId, calendarType, this::addDeviationAsHijrah);
+        } catch (IOException | ParseException e) {
+            // do nothing. Log deviation config errors.
+            //e.printStackTrace();
+        }
+    }
+
+    /**
+     * Resolve singleton.
+     *
+     * @return the singleton instance, not null
+     */
+    private Object readResolve() {
+        return INSTANCE;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the ID of the chronology - 'Hijrah'.
+     * <p>
+     * The ID uniquely identifies the {@code Chrono}.
+     * It can be used to lookup the {@code Chrono} using {@link #of(String)}.
+     *
+     * @return the chronology ID - 'Hijrah'
+     * @see #getCalendarType()
+     */
+    @Override
+    public String getId() {
+        return typeId;
+    }
+
+    /**
+     * Gets the calendar type of the underlying calendar system - 'islamicc'.
+     * <p>
+     * The calendar type is an identifier defined by the
+     * <em>Unicode Locale Data Markup Language (LDML)</em> specification.
+     * It can be used to lookup the {@code Chrono} using {@link #of(String)}.
+     * It can also be used as part of a locale, accessible via
+     * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
+     *
+     * @return the calendar system type - 'islamicc'
+     * @see #getId()
+     */
+    @Override
+    public String getCalendarType() {
+        return calendarType;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ChronoLocalDate<HijrahChrono> date(int prolepticYear, int month, int dayOfMonth) {
+        return HijrahDate.of(this, prolepticYear, month, dayOfMonth);
+    }
+
+    @Override
+    public ChronoLocalDate<HijrahChrono> dateYearDay(int prolepticYear, int dayOfYear) {
+        return HijrahDate.of(this, prolepticYear, 1, 1).plusDays(dayOfYear - 1);  // TODO better
+    }
+
+    @Override
+    public ChronoLocalDate<HijrahChrono> date(TemporalAccessor temporal) {
+        if (temporal instanceof HijrahDate) {
+            return (HijrahDate) temporal;
+        }
+        return HijrahDate.ofEpochDay(this, temporal.getLong(EPOCH_DAY));
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public boolean isLeapYear(long prolepticYear) {
+        return isLeapYear0(prolepticYear);
+    }
+    /**
+     * Returns if the year is a leap year.
+     * @param prolepticYear he year to compute from
+     * @return {@code true} if the year is a leap year, otherwise {@code false}
+     */
+    private static boolean isLeapYear0(long prolepticYear) {
+        return (14 + 11 * (prolepticYear > 0 ? prolepticYear : -prolepticYear)) % 30 < 11;
+    }
+
+    @Override
+    public int prolepticYear(Era<HijrahChrono> era, int yearOfEra) {
+        if (era instanceof HijrahEra == false) {
+            throw new DateTimeException("Era must be HijrahEra");
+        }
+        return (era == HijrahEra.AH ? yearOfEra : 1 - yearOfEra);
+    }
+
+    @Override
+    public Era<HijrahChrono> eraOf(int eraValue) {
+        switch (eraValue) {
+            case 0:
+                return HijrahEra.BEFORE_AH;
+            case 1:
+                return HijrahEra.AH;
+            default:
+                throw new DateTimeException("invalid Hijrah era");
+        }
+    }
+
+    @Override
+    public List<Era<HijrahChrono>> eras() {
+        return Arrays.<Era<HijrahChrono>>asList(HijrahEra.values());
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ValueRange range(ChronoField field) {
+        return field.range();
+    }
+
+    /**
+     * Check the validity of a yearOfEra.
+     * @param yearOfEra the year to check
+     */
+    void checkValidYearOfEra(int yearOfEra) {
+         if (yearOfEra < MIN_YEAR_OF_ERA  ||
+                 yearOfEra > MAX_YEAR_OF_ERA) {
+             throw new DateTimeException("Invalid year of Hijrah Era");
+         }
+    }
+
+    void checkValidDayOfYear(int dayOfYear) {
+         if (dayOfYear < 1  ||
+                 dayOfYear > getMaximumDayOfYear()) {
+             throw new DateTimeException("Invalid day of year of Hijrah date");
+         }
+    }
+
+    void checkValidMonth(int month) {
+         if (month < 1 || month > 12) {
+             throw new DateTimeException("Invalid month of Hijrah date");
+         }
+    }
+
+    void checkValidDayOfMonth(int dayOfMonth) {
+         if (dayOfMonth < 1  ||
+                 dayOfMonth > getMaximumDayOfMonth()) {
+             throw new DateTimeException("Invalid day of month of Hijrah date, day "
+                     + dayOfMonth + " greater than " + getMaximumDayOfMonth() + " or less than 1");
+         }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns the int array containing the following field from the julian day.
+     *
+     * int[0] = ERA
+     * int[1] = YEAR
+     * int[2] = MONTH
+     * int[3] = DATE
+     * int[4] = DAY_OF_YEAR
+     * int[5] = DAY_OF_WEEK
+     *
+     * @param gregorianDays  a julian day.
+     */
+    int[] getHijrahDateInfo(long gregorianDays) {
+        int era, year, month, date, dayOfWeek, dayOfYear;
+
+        int cycleNumber, yearInCycle, dayOfCycle;
+
+        long epochDay = gregorianDays - HIJRAH_JAN_1_1_GREGORIAN_DAY;
+
+        if (epochDay >= 0) {
+            cycleNumber = getCycleNumber(epochDay); // 0 - 99.
+            dayOfCycle = getDayOfCycle(epochDay, cycleNumber); // 0 - 10631.
+            yearInCycle = getYearInCycle(cycleNumber, dayOfCycle); // 0 - 29.
+            dayOfYear = getDayOfYear(cycleNumber, dayOfCycle, yearInCycle);
+            // 0 - 354/355
+            year = cycleNumber * 30 + yearInCycle + 1; // 1-based year.
+            month = getMonthOfYear(dayOfYear, year); // 0-based month-of-year
+            date = getDayOfMonth(dayOfYear, month, year); // 0-based date
+            ++date; // Convert from 0-based to 1-based
+            era = HijrahEra.AH.getValue();
+        } else {
+            cycleNumber = (int) epochDay / 10631; // 0 or negative number.
+            dayOfCycle = (int) epochDay % 10631; // -10630 - 0.
+            if (dayOfCycle == 0) {
+                dayOfCycle = -10631;
+                cycleNumber++;
+            }
+            yearInCycle = getYearInCycle(cycleNumber, dayOfCycle); // 0 - 29.
+            dayOfYear = getDayOfYear(cycleNumber, dayOfCycle, yearInCycle);
+            year = cycleNumber * 30 - yearInCycle; // negative number.
+            year = 1 - year;
+            dayOfYear = (isLeapYear(year) ? (dayOfYear + 355)
+                    : (dayOfYear + 354));
+            month = getMonthOfYear(dayOfYear, year);
+            date = getDayOfMonth(dayOfYear, month, year);
+            ++date; // Convert from 0-based to 1-based
+            era = HijrahEra.BEFORE_AH.getValue();
+        }
+        // Hijrah day zero is a Friday
+        dayOfWeek = (int) ((epochDay + 5) % 7);
+        dayOfWeek += (dayOfWeek <= 0) ? 7 : 0;
+
+        int dateInfo[] = new int[6];
+        dateInfo[0] = era;
+        dateInfo[1] = year;
+        dateInfo[2] = month + 1; // change to 1-based.
+        dateInfo[3] = date;
+        dateInfo[4] = dayOfYear + 1; // change to 1-based.
+        dateInfo[5] = dayOfWeek;
+        return dateInfo;
+    }
+
+    /**
+     * Return Gregorian epoch day from Hijrah year, month, and day.
+     *
+     * @param prolepticYear  the year to represent, caller calculated
+     * @param monthOfYear  the month-of-year to represent, caller calculated
+     * @param dayOfMonth  the day-of-month to represent, caller calculated
+     * @return a julian day
+     */
+    long getGregorianEpochDay(int prolepticYear, int monthOfYear, int dayOfMonth) {
+        long day = yearToGregorianEpochDay(prolepticYear);
+        day += getMonthDays(monthOfYear - 1, prolepticYear);
+        day += dayOfMonth;
+        return day;
+    }
+
+    /**
+     * Returns the Gregorian epoch day from the proleptic year
+     * @param prolepticYear the proleptic year
+     * @return the Epoch day
+     */
+    private long yearToGregorianEpochDay(int prolepticYear) {
+
+        int cycleNumber = (prolepticYear - 1) / 30; // 0-based.
+        int yearInCycle = (prolepticYear - 1) % 30; // 0-based.
+
+        int dayInCycle = getAdjustedCycle(cycleNumber)[Math.abs(yearInCycle)]
+                ;
+
+        if (yearInCycle < 0) {
+            dayInCycle = -dayInCycle;
+        }
+
+        Long cycleDays;
+
+        try {
+            cycleDays = ADJUSTED_CYCLES[cycleNumber];
+        } catch (ArrayIndexOutOfBoundsException e) {
+            cycleDays = null;
+        }
+
+        if (cycleDays == null) {
+            cycleDays = new Long(cycleNumber * 10631);
+        }
+
+        return (cycleDays.longValue() + dayInCycle + HIJRAH_JAN_1_1_GREGORIAN_DAY - 1);
+    }
+
+    /**
+     * Returns the 30 year cycle number from the epoch day.
+     *
+     * @param epochDay  an epoch day
+     * @return a cycle number
+     */
+    private int getCycleNumber(long epochDay) {
+        long[] days = ADJUSTED_CYCLES;
+        int cycleNumber;
+        try {
+            for (int i = 0; i < days.length; i++) {
+                if (epochDay < days[i]) {
+                    return i - 1;
+                }
+            }
+            cycleNumber = (int) epochDay / 10631;
+        } catch (ArrayIndexOutOfBoundsException e) {
+            cycleNumber = (int) epochDay / 10631;
+        }
+        return cycleNumber;
+    }
+
+    /**
+     * Returns day of cycle from the epoch day and cycle number.
+     *
+     * @param epochDay  an epoch day
+     * @param cycleNumber  a cycle number
+     * @return a day of cycle
+     */
+    private int getDayOfCycle(long epochDay, int cycleNumber) {
+        Long day;
+
+        try {
+            day = ADJUSTED_CYCLES[cycleNumber];
+        } catch (ArrayIndexOutOfBoundsException e) {
+            day = null;
+        }
+        if (day == null) {
+            day = new Long(cycleNumber * 10631);
+        }
+        return (int) (epochDay - day.longValue());
+    }
+
+    /**
+     * Returns the year in cycle from the cycle number and day of cycle.
+     *
+     * @param cycleNumber  a cycle number
+     * @param dayOfCycle  day of cycle
+     * @return a year in cycle
+     */
+    private int getYearInCycle(int cycleNumber, long dayOfCycle) {
+        int[] cycles = getAdjustedCycle(cycleNumber);
+        if (dayOfCycle == 0) {
+            return 0;
+        }
+
+        if (dayOfCycle > 0) {
+            for (int i = 0; i < cycles.length; i++) {
+                if (dayOfCycle < cycles[i]) {
+                    return i - 1;
+                }
+            }
+            return 29;
+        } else {
+            dayOfCycle = -dayOfCycle;
+            for (int i = 0; i < cycles.length; i++) {
+                if (dayOfCycle <= cycles[i]) {
+                    return i - 1;
+                }
+            }
+            return 29;
+        }
+    }
+
+    /**
+     * Returns adjusted 30 year cycle starting day as Integer array from the
+     * cycle number specified.
+     *
+     * @param cycleNumber  a cycle number
+     * @return an Integer array
+     */
+    int[] getAdjustedCycle(int cycleNumber) {
+        int[] cycles;
+        try {
+            cycles = ADJUSTED_CYCLE_YEARS.get(cycleNumber);
+        } catch (ArrayIndexOutOfBoundsException e) {
+            cycles = null;
+        }
+        if (cycles == null) {
+            cycles = DEFAULT_CYCLE_YEARS;
+        }
+        return cycles;
+    }
+
+    /**
+     * Returns adjusted month days as Integer array form the year specified.
+     *
+     * @param year  a year
+     * @return an Integer array
+     */
+    int[] getAdjustedMonthDays(int year) {
+        int[] newMonths;
+        try {
+            newMonths = ADJUSTED_MONTH_DAYS.get(year);
+        } catch (ArrayIndexOutOfBoundsException e) {
+            newMonths = null;
+        }
+        if (newMonths == null) {
+            if (isLeapYear0(year)) {
+                newMonths = DEFAULT_LEAP_MONTH_DAYS;
+            } else {
+                newMonths = DEFAULT_MONTH_DAYS;
+            }
+        }
+        return newMonths;
+    }
+
+    /**
+     * Returns adjusted month length as Integer array form the year specified.
+     *
+     * @param year  a year
+     * @return an Integer array
+     */
+    int[] getAdjustedMonthLength(int year) {
+        int[] newMonths;
+        try {
+            newMonths = ADJUSTED_MONTH_LENGTHS.get(year);
+        } catch (ArrayIndexOutOfBoundsException e) {
+            newMonths = null;
+        }
+        if (newMonths == null) {
+            if (isLeapYear0(year)) {
+                newMonths = DEFAULT_LEAP_MONTH_LENGTHS;
+            } else {
+                newMonths = DEFAULT_MONTH_LENGTHS;
+            }
+        }
+        return newMonths;
+    }
+
+    /**
+     * Returns day-of-year.
+     *
+     * @param cycleNumber  a cycle number
+     * @param dayOfCycle  day of cycle
+     * @param yearInCycle  year in cycle
+     * @return day-of-year
+     */
+    private int getDayOfYear(int cycleNumber, int dayOfCycle, int yearInCycle) {
+        int[] cycles = getAdjustedCycle(cycleNumber);
+
+        if (dayOfCycle > 0) {
+            return dayOfCycle - cycles[yearInCycle];
+        } else {
+            return cycles[yearInCycle] + dayOfCycle;
+        }
+    }
+
+    /**
+     * Returns month-of-year. 0-based.
+     *
+     * @param dayOfYear  day-of-year
+     * @param year  a year
+     * @return month-of-year
+     */
+    private int getMonthOfYear(int dayOfYear, int year) {
+
+        int[] newMonths = getAdjustedMonthDays(year);
+
+        if (dayOfYear >= 0) {
+            for (int i = 0; i < newMonths.length; i++) {
+                if (dayOfYear < newMonths[i]) {
+                    return i - 1;
+                }
+            }
+            return 11;
+        } else {
+            dayOfYear = (isLeapYear0(year) ? (dayOfYear + 355)
+                    : (dayOfYear + 354));
+            for (int i = 0; i < newMonths.length; i++) {
+                if (dayOfYear < newMonths[i]) {
+                    return i - 1;
+                }
+            }
+            return 11;
+        }
+    }
+
+    /**
+     * Returns day-of-month.
+     *
+     * @param dayOfYear  day of  year
+     * @param month  month
+     * @param year  year
+     * @return day-of-month
+     */
+    private int getDayOfMonth(int dayOfYear, int month, int year) {
+
+        int[] newMonths = getAdjustedMonthDays(year);
+
+        if (dayOfYear >= 0) {
+            if (month > 0) {
+                return dayOfYear - newMonths[month];
+            } else {
+                return dayOfYear;
+            }
+        } else {
+            dayOfYear = (isLeapYear0(year) ? (dayOfYear + 355)
+                    : (dayOfYear + 354));
+            if (month > 0) {
+                return dayOfYear - newMonths[month];
+            } else {
+                return dayOfYear;
+            }
+        }
+    }
+
+
+    /**
+     * Returns month days from the beginning of year.
+     *
+     * @param month  month (0-based)
+     * @parma year  year
+     * @return month days from the beginning of year
+     */
+    private int getMonthDays(int month, int year) {
+        int[] newMonths = getAdjustedMonthDays(year);
+        return newMonths[month];
+    }
+
+    /**
+     * Returns month length.
+     *
+     * @param month  month (0-based)
+     * @param year  year
+     * @return month length
+     */
+    private int getMonthLength(int month, int year) {
+      int[] newMonths = getAdjustedMonthLength(year);
+      return newMonths[month];
+    }
+
+    /**
+     * Returns year length.
+     *
+     * @param year  year
+     * @return year length
+     */
+    int getYearLength(int year) {
+
+        int cycleNumber = (year - 1) / 30;
+        int[] cycleYears;
+        try {
+            cycleYears = ADJUSTED_CYCLE_YEARS.get(cycleNumber);
+        } catch (ArrayIndexOutOfBoundsException e) {
+            cycleYears = null;
+        }
+        if (cycleYears != null) {
+            int yearInCycle = (year - 1) % 30;
+            if (yearInCycle == 29) {
+                return (int)(ADJUSTED_CYCLES[cycleNumber + 1]
+                        - ADJUSTED_CYCLES[cycleNumber]
+                        - cycleYears[yearInCycle]);
+            }
+            return cycleYears[yearInCycle + 1]
+                    - cycleYears[yearInCycle];
+        } else {
+            return isLeapYear0(year) ? 355 : 354;
+        }
+    }
+
+
+    /**
+     * Returns maximum day-of-month.
+     *
+     * @return maximum day-of-month
+     */
+    int getMaximumDayOfMonth() {
+        return ADJUSTED_MAX_VALUES[POSITION_DAY_OF_MONTH];
+    }
+
+    /**
+     * Returns smallest maximum day-of-month.
+     *
+     * @return smallest maximum day-of-month
+     */
+    int getSmallestMaximumDayOfMonth() {
+        return ADJUSTED_LEAST_MAX_VALUES[POSITION_DAY_OF_MONTH];
+    }
+
+    /**
+     * Returns maximum day-of-year.
+     *
+     * @return maximum day-of-year
+     */
+    int getMaximumDayOfYear() {
+        return ADJUSTED_MAX_VALUES[POSITION_DAY_OF_YEAR];
+    }
+
+    /**
+     * Returns smallest maximum day-of-year.
+     *
+     * @return smallest maximum day-of-year
+     */
+    int getSmallestMaximumDayOfYear() {
+        return ADJUSTED_LEAST_MAX_VALUES[POSITION_DAY_OF_YEAR];
+    }
+
+    // ----- Deviation handling -----//
+
+    /**
+     * Adds deviation definition. The year and month specified should be the
+     * calculated Hijrah year and month. The month is 1 based. e.g. 9 for
+     * Ramadan (9th month) Addition of anything minus deviation days is
+     * calculated negatively in the case the user wants to subtract days from
+     * the calendar. For example, adding -1 days will subtract one day from the
+     * current date.
+     *
+     * @param startYear  start year, 1 origin
+     * @param startMonth  start month, 1 origin
+     * @param endYear  end year, 1 origin
+     * @param endMonth  end month, 1 origin
+     * @param offset  offset -2, -1, +1, +2
+     */
+    private void addDeviationAsHijrah(Deviation entry) {
+        int startYear = entry.startYear;
+        int startMonth = entry.startMonth - 1 ;
+        int endYear = entry.endYear;
+        int endMonth = entry.endMonth - 1;
+        int offset = entry.offset;
+
+        if (startYear < 1) {
+            throw new IllegalArgumentException("startYear < 1");
+        }
+        if (endYear < 1) {
+            throw new IllegalArgumentException("endYear < 1");
+        }
+        if (startMonth < 0 || startMonth > 11) {
+            throw new IllegalArgumentException(
+                    "startMonth < 0 || startMonth > 11");
+        }
+        if (endMonth < 0 || endMonth > 11) {
+            throw new IllegalArgumentException("endMonth < 0 || endMonth > 11");
+        }
+        if (endYear > 9999) {
+            throw new IllegalArgumentException("endYear > 9999");
+        }
+        if (endYear < startYear) {
+            throw new IllegalArgumentException("startYear > endYear");
+        }
+        if (endYear == startYear && endMonth < startMonth) {
+            throw new IllegalArgumentException(
+                    "startYear == endYear && endMonth < startMonth");
+        }
+
+        // Adjusting start year.
+        boolean isStartYLeap = isLeapYear0(startYear);
+
+        // Adjusting the number of month.
+        int[] orgStartMonthNums = ADJUSTED_MONTH_DAYS.get(startYear);
+        if (orgStartMonthNums == null) {
+            if (isStartYLeap) {
+                orgStartMonthNums = Arrays.copyOf(LEAP_NUM_DAYS, LEAP_NUM_DAYS.length);
+            } else {
+                orgStartMonthNums = Arrays.copyOf(NUM_DAYS, NUM_DAYS.length);
+            }
+        }
+
+        int[] newStartMonthNums = new int[orgStartMonthNums.length];
+
+        for (int month = 0; month < 12; month++) {
+            if (month > startMonth) {
+                newStartMonthNums[month] = (orgStartMonthNums[month] - offset);
+            } else {
+                newStartMonthNums[month] = (orgStartMonthNums[month]);
+            }
+        }
+
+        ADJUSTED_MONTH_DAYS.put(startYear, newStartMonthNums);
+
+        // Adjusting the days of month.
+
+        int[] orgStartMonthLengths = ADJUSTED_MONTH_LENGTHS.get(startYear);
+        if (orgStartMonthLengths == null) {
+            if (isStartYLeap) {
+                orgStartMonthLengths = Arrays.copyOf(LEAP_MONTH_LENGTH, LEAP_MONTH_LENGTH.length);
+            } else {
+                orgStartMonthLengths = Arrays.copyOf(MONTH_LENGTH, MONTH_LENGTH.length);
+            }
+        }
+
+        int[] newStartMonthLengths = new int[orgStartMonthLengths.length];
+
+        for (int month = 0; month < 12; month++) {
+            if (month == startMonth) {
+                newStartMonthLengths[month] = orgStartMonthLengths[month] - offset;
+            } else {
+                newStartMonthLengths[month] = orgStartMonthLengths[month];
+            }
+        }
+
+        ADJUSTED_MONTH_LENGTHS.put(startYear, newStartMonthLengths);
+
+        if (startYear != endYear) {
+            // System.out.println("over year");
+            // Adjusting starting 30 year cycle.
+            int sCycleNumber = (startYear - 1) / 30;
+            int sYearInCycle = (startYear - 1) % 30; // 0-based.
+            int[] startCycles = ADJUSTED_CYCLE_YEARS.get(sCycleNumber);
+            if (startCycles == null) {
+                startCycles = Arrays.copyOf(CYCLEYEAR_START_DATE, CYCLEYEAR_START_DATE.length);
+            }
+
+            for (int j = sYearInCycle + 1; j < CYCLEYEAR_START_DATE.length; j++) {
+                startCycles[j] = startCycles[j] - offset;
+            }
+
+            // System.out.println(sCycleNumber + ":" + sYearInCycle);
+            ADJUSTED_CYCLE_YEARS.put(sCycleNumber, startCycles);
+
+            int sYearInMaxY = (startYear - 1) / 30;
+            int sEndInMaxY = (endYear - 1) / 30;
+
+            if (sYearInMaxY != sEndInMaxY) {
+                // System.out.println("over 30");
+                // Adjusting starting 30 * MAX_ADJUSTED_CYCLE year cycle.
+                // System.out.println(sYearInMaxY);
+
+                for (int j = sYearInMaxY + 1; j < ADJUSTED_CYCLES.length; j++) {
+                    ADJUSTED_CYCLES[j] = ADJUSTED_CYCLES[j] - offset;
+                }
+
+                // Adjusting ending 30 * MAX_ADJUSTED_CYCLE year cycles.
+                for (int j = sEndInMaxY + 1; j < ADJUSTED_CYCLES.length; j++) {
+                    ADJUSTED_CYCLES[j] = ADJUSTED_CYCLES[j] + offset;
+                }
+            }
+
+            // Adjusting ending 30 year cycle.
+            int eCycleNumber = (endYear - 1) / 30;
+            int sEndInCycle = (endYear - 1) % 30; // 0-based.
+            int[] endCycles = ADJUSTED_CYCLE_YEARS.get(eCycleNumber);
+            if (endCycles == null) {
+                endCycles = Arrays.copyOf(CYCLEYEAR_START_DATE, CYCLEYEAR_START_DATE.length);
+            }
+            for (int j = sEndInCycle + 1; j < CYCLEYEAR_START_DATE.length; j++) {
+                endCycles[j] = endCycles[j] + offset;
+            }
+            ADJUSTED_CYCLE_YEARS.put(eCycleNumber, endCycles);
+        }
+
+        // Adjusting ending year.
+        boolean isEndYLeap = isLeapYear0(endYear);
+
+        int[] orgEndMonthDays = ADJUSTED_MONTH_DAYS.get(endYear);
+
+        if (orgEndMonthDays == null) {
+            if (isEndYLeap) {
+                orgEndMonthDays = Arrays.copyOf(LEAP_NUM_DAYS, LEAP_NUM_DAYS.length);
+            } else {
+                orgEndMonthDays = Arrays.copyOf(NUM_DAYS, NUM_DAYS.length);
+            }
+        }
+
+        int[] newEndMonthDays = new int[orgEndMonthDays.length];
+
+        for (int month = 0; month < 12; month++) {
+            if (month > endMonth) {
+                newEndMonthDays[month] = orgEndMonthDays[month] + offset;
+            } else {
+                newEndMonthDays[month] = orgEndMonthDays[month];
+            }
+        }
+
+        ADJUSTED_MONTH_DAYS.put(endYear, newEndMonthDays);
+
+        // Adjusting the days of month.
+        int[] orgEndMonthLengths = ADJUSTED_MONTH_LENGTHS.get(endYear);
+
+        if (orgEndMonthLengths == null) {
+            if (isEndYLeap) {
+                orgEndMonthLengths = Arrays.copyOf(LEAP_MONTH_LENGTH, LEAP_MONTH_LENGTH.length);
+            } else {
+                orgEndMonthLengths = Arrays.copyOf(MONTH_LENGTH, MONTH_LENGTH.length);
+            }
+        }
+
+        int[] newEndMonthLengths = new int[orgEndMonthLengths.length];
+
+        for (int month = 0; month < 12; month++) {
+            if (month == endMonth) {
+                newEndMonthLengths[month] = orgEndMonthLengths[month] + offset;
+            } else {
+                newEndMonthLengths[month] = orgEndMonthLengths[month];
+            }
+        }
+
+        ADJUSTED_MONTH_LENGTHS.put(endYear, newEndMonthLengths);
+
+        int[] startMonthLengths = ADJUSTED_MONTH_LENGTHS.get(startYear);
+        int[] endMonthLengths = ADJUSTED_MONTH_LENGTHS.get(endYear);
+        int[] startMonthDays = ADJUSTED_MONTH_DAYS.get(startYear);
+        int[] endMonthDays = ADJUSTED_MONTH_DAYS.get(endYear);
+
+        int startMonthLength = startMonthLengths[startMonth];
+        int endMonthLength = endMonthLengths[endMonth];
+        int startMonthDay = startMonthDays[11] + startMonthLengths[11];
+        int endMonthDay = endMonthDays[11] + endMonthLengths[11];
+
+        int maxMonthLength = ADJUSTED_MAX_VALUES[POSITION_DAY_OF_MONTH];
+        int leastMaxMonthLength = ADJUSTED_LEAST_MAX_VALUES[POSITION_DAY_OF_MONTH];
+
+        if (maxMonthLength < startMonthLength) {
+            maxMonthLength = startMonthLength;
+        }
+        if (maxMonthLength < endMonthLength) {
+            maxMonthLength = endMonthLength;
+        }
+        ADJUSTED_MAX_VALUES[POSITION_DAY_OF_MONTH] = maxMonthLength;
+
+        if (leastMaxMonthLength > startMonthLength) {
+            leastMaxMonthLength = startMonthLength;
+        }
+        if (leastMaxMonthLength > endMonthLength) {
+            leastMaxMonthLength = endMonthLength;
+        }
+        ADJUSTED_LEAST_MAX_VALUES[POSITION_DAY_OF_MONTH] = leastMaxMonthLength;
+
+        int maxMonthDay = ADJUSTED_MAX_VALUES[POSITION_DAY_OF_YEAR];
+        int leastMaxMonthDay = ADJUSTED_LEAST_MAX_VALUES[POSITION_DAY_OF_YEAR];
+
+        if (maxMonthDay < startMonthDay) {
+            maxMonthDay = startMonthDay;
+        }
+        if (maxMonthDay < endMonthDay) {
+            maxMonthDay = endMonthDay;
+        }
+
+        ADJUSTED_MAX_VALUES[POSITION_DAY_OF_YEAR] = maxMonthDay;
+
+        if (leastMaxMonthDay > startMonthDay) {
+            leastMaxMonthDay = startMonthDay;
+        }
+        if (leastMaxMonthDay > endMonthDay) {
+            leastMaxMonthDay = endMonthDay;
+        }
+        ADJUSTED_LEAST_MAX_VALUES[POSITION_DAY_OF_YEAR] = leastMaxMonthDay;
+    }
+
+    /**
+     * Package private Entry for suppling deviations from the Reader.
+     * Each entry consists of a range using the Hijrah calendar,
+     * start year, month, end year, end month, and an offset.
+     * The offset is used to modify the length of the month +2, +1, -1, -2.
+     */
+    static final class Deviation {
+
+        Deviation(int startYear, int startMonth, int endYear, int endMonth, int offset) {
+            this.startYear = startYear;
+            this.startMonth = startMonth;
+            this.endYear = endYear;
+            this.endMonth = endMonth;
+            this.offset = offset;
+        }
+
+        final int startYear;
+        final int startMonth;
+        final int endYear;
+        final int endMonth;
+        final int offset;
+
+        int getStartYear() {
+            return startYear;
+        }
+
+        int getStartMonth() {
+            return startMonth;
+        }
+
+        int getEndYear() {
+            return endYear;
+        }
+
+        int getEndMonth() {
+            return endMonth;
+        }
+
+        int getOffset() {
+            return offset;
+        }
+
+        @Override
+        public String toString() {
+            return String.format("[year: %4d, month: %2d, offset: %+d]", startYear, startMonth, offset);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/calendar/HijrahDate.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,445 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.calendar;
+
+import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH;
+import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR;
+import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH;
+import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR;
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.YEAR;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.Serializable;
+import java.time.DateTimeException;
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoLocalDate;
+import java.time.temporal.TemporalField;
+import java.time.temporal.ValueRange;
+import java.util.Objects;
+
+/**
+ * A date in the Hijrah calendar system.
+ * <p>
+ * This implements {@code ChronoLocalDate} for the {@link HijrahChrono Hijrah calendar}.
+ * <p>
+ * The Hijrah calendar has a different total of days in a year than
+ * Gregorian calendar, and a month is based on the period of a complete
+ * revolution of the moon around the earth (as between successive new moons).
+ * The calendar cycles becomes longer and unstable, and sometimes a manual
+ * adjustment (for entering deviation) is necessary for correctness
+ * because of the complex algorithm.
+ * <p>
+ * HijrahDate supports the manual adjustment feature by providing a configuration
+ * file. The configuration file contains the adjustment (deviation) data with following format.
+ * <pre>
+ *   StartYear/StartMonth(0-based)-EndYear/EndMonth(0-based):Deviation day (1, 2, -1, or -2)
+ *   Line separator or ";" is used for the separator of each deviation data.</pre>
+ *   Here is the example.
+ * <pre>
+ *     1429/0-1429/1:1
+ *     1429/2-1429/7:1;1429/6-1429/11:1
+ *     1429/11-9999/11:1</pre>
+ * The default location of the configuration file is:
+ * <pre>
+ *   $CLASSPATH/java/time/i18n</pre>
+ * And the default file name is:
+ * <pre>
+ *   hijrah_deviation.cfg</pre>
+ * The default location and file name can be overriden by setting
+ * following two Java's system property.
+ * <pre>
+ *   Location: java.time.i18n.HijrahDate.deviationConfigDir
+ *   File name: java.time.i18n.HijrahDate.deviationConfigFile</pre>
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+final class HijrahDate
+        extends ChronoDateImpl<HijrahChrono>
+        implements ChronoLocalDate<HijrahChrono>, Serializable {
+    // this class is package-scoped so that future conversion to public
+    // would not change serialization
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -5207853542612002020L;
+
+    /**
+     * The Chronology of this HijrahDate.
+     */
+    private final HijrahChrono chrono;
+    /**
+     * The era.
+     */
+    private final transient HijrahEra era;
+    /**
+     * The year.
+     */
+    private final transient int yearOfEra;
+    /**
+     * The month-of-year.
+     */
+    private final transient int monthOfYear;
+    /**
+     * The day-of-month.
+     */
+    private final transient int dayOfMonth;
+    /**
+     * The day-of-year.
+     */
+    private final transient int dayOfYear;
+    /**
+     * The day-of-week.
+     */
+    private final transient DayOfWeek dayOfWeek;
+    /**
+     * Gregorian days for this object. Holding number of days since 1970/01/01.
+     * The number of days are calculated with pure Gregorian calendar
+     * based.
+     */
+    private final long gregorianEpochDay;
+    /**
+     * True if year is leap year.
+     */
+    private final transient boolean isLeapYear;
+
+    //-------------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code HijrahDate} from the Hijrah era year,
+     * month-of-year and day-of-month. This uses the Hijrah era.
+     *
+     * @param prolepticYear  the proleptic year to represent in the Hijrah
+     * @param monthOfYear  the month-of-year to represent, from 1 to 12
+     * @param dayOfMonth  the day-of-month to represent, from 1 to 30
+     * @return the Hijrah date, never null
+     * @throws DateTimeException if the value of any field is out of range
+     */
+    static HijrahDate of(HijrahChrono chrono, int prolepticYear, int monthOfYear, int dayOfMonth) {
+        return (prolepticYear >= 1) ?
+            HijrahDate.of(chrono, HijrahEra.AH, prolepticYear, monthOfYear, dayOfMonth) :
+            HijrahDate.of(chrono, HijrahEra.BEFORE_AH, 1 - prolepticYear, monthOfYear, dayOfMonth);
+    }
+
+    /**
+     * Obtains an instance of {@code HijrahDate} from the era, year-of-era
+     * month-of-year and day-of-month.
+     *
+     * @param era  the era to represent, not null
+     * @param yearOfEra  the year-of-era to represent, from 1 to 9999
+     * @param monthOfYear  the month-of-year to represent, from 1 to 12
+     * @param dayOfMonth  the day-of-month to represent, from 1 to 31
+     * @return the Hijrah date, never null
+     * @throws DateTimeException if the value of any field is out of range
+     */
+    private static HijrahDate of(HijrahChrono chrono, HijrahEra era, int yearOfEra, int monthOfYear, int dayOfMonth) {
+        Objects.requireNonNull(era, "era");
+        chrono.checkValidYearOfEra(yearOfEra);
+        chrono.checkValidMonth(monthOfYear);
+        chrono.checkValidDayOfMonth(dayOfMonth);
+        long gregorianDays = chrono.getGregorianEpochDay(era.prolepticYear(yearOfEra), monthOfYear, dayOfMonth);
+        return new HijrahDate(chrono, gregorianDays);
+    }
+
+    /**
+     * Obtains an instance of {@code HijrahDate} from a date.
+     *
+     * @param date  the date to use, not null
+     * @return the Hijrah date, never null
+     * @throws DateTimeException if the year is invalid
+     */
+    private static HijrahDate of(HijrahChrono chrono, LocalDate date) {
+        long gregorianDays = date.toEpochDay();
+        return new HijrahDate(chrono, gregorianDays);
+    }
+
+    static HijrahDate ofEpochDay(HijrahChrono chrono, long epochDay) {
+        return new HijrahDate(chrono, epochDay);
+    }
+
+    /**
+     * Constructs an instance with the specified date.
+     *
+     * @param gregorianDay  the number of days from 0001/01/01 (Gregorian), caller calculated
+     */
+    private HijrahDate(HijrahChrono chrono, long gregorianDay) {
+        this.chrono = chrono;
+        int[] dateInfo = chrono.getHijrahDateInfo(gregorianDay);
+
+        chrono.checkValidYearOfEra(dateInfo[1]);
+        chrono.checkValidMonth(dateInfo[2]);
+        chrono.checkValidDayOfMonth(dateInfo[3]);
+        chrono.checkValidDayOfYear(dateInfo[4]);
+
+        this.era = HijrahEra.of(dateInfo[0]);
+        this.yearOfEra = dateInfo[1];
+        this.monthOfYear = dateInfo[2];
+        this.dayOfMonth = dateInfo[3];
+        this.dayOfYear = dateInfo[4];
+        this.dayOfWeek = DayOfWeek.of(dateInfo[5]);
+        this.gregorianEpochDay = gregorianDay;
+        this.isLeapYear = chrono.isLeapYear(this.yearOfEra);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public HijrahChrono getChrono() {
+        return chrono;
+    }
+
+    @Override
+    public ValueRange range(TemporalField field) {
+        if (field instanceof ChronoField) {
+            if (isSupported(field)) {
+                ChronoField f = (ChronoField) field;
+                switch (f) {
+                    case DAY_OF_MONTH: return ValueRange.of(1, lengthOfMonth());
+                    case DAY_OF_YEAR: return ValueRange.of(1, lengthOfYear());
+                    case ALIGNED_WEEK_OF_MONTH: return ValueRange.of(1, 5);  // TODO
+                    case YEAR_OF_ERA: return ValueRange.of(1, 1000);  // TODO
+                }
+                return getChrono().range(f);
+            }
+            throw new DateTimeException("Unsupported field: " + field.getName());
+        }
+        return field.doRange(this);
+    }
+
+    @Override
+    public long getLong(TemporalField field) {
+        if (field instanceof ChronoField) {
+            switch ((ChronoField) field) {
+                case DAY_OF_WEEK: return dayOfWeek.getValue();
+                case ALIGNED_DAY_OF_WEEK_IN_MONTH: return ((dayOfWeek.getValue() - 1) % 7) + 1;
+                case ALIGNED_DAY_OF_WEEK_IN_YEAR: return ((dayOfYear - 1) % 7) + 1;
+                case DAY_OF_MONTH: return this.dayOfMonth;
+                case DAY_OF_YEAR: return this.dayOfYear;
+                case EPOCH_DAY: return toEpochDay();
+                case ALIGNED_WEEK_OF_MONTH: return ((dayOfMonth - 1) / 7) + 1;
+                case ALIGNED_WEEK_OF_YEAR: return ((dayOfYear - 1) / 7) + 1;
+                case MONTH_OF_YEAR: return monthOfYear;
+                case YEAR_OF_ERA: return yearOfEra;
+                case YEAR: return yearOfEra;
+                case ERA: return era.getValue();
+            }
+            throw new DateTimeException("Unsupported field: " + field.getName());
+        }
+        return field.doGet(this);
+    }
+
+    @Override
+    public HijrahDate with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            f.checkValidValue(newValue);        // TODO: validate value
+            int nvalue = (int) newValue;
+            switch (f) {
+                case DAY_OF_WEEK: return plusDays(newValue - dayOfWeek.getValue());
+                case ALIGNED_DAY_OF_WEEK_IN_MONTH: return plusDays(newValue - getLong(ALIGNED_DAY_OF_WEEK_IN_MONTH));
+                case ALIGNED_DAY_OF_WEEK_IN_YEAR: return plusDays(newValue - getLong(ALIGNED_DAY_OF_WEEK_IN_YEAR));
+                case DAY_OF_MONTH: return resolvePreviousValid(yearOfEra, monthOfYear, nvalue);
+                case DAY_OF_YEAR: return resolvePreviousValid(yearOfEra, ((nvalue - 1) / 30) + 1, ((nvalue - 1) % 30) + 1);
+                case EPOCH_DAY: return new HijrahDate(chrono, nvalue);
+                case ALIGNED_WEEK_OF_MONTH: return plusDays((newValue - getLong(ALIGNED_WEEK_OF_MONTH)) * 7);
+                case ALIGNED_WEEK_OF_YEAR: return plusDays((newValue - getLong(ALIGNED_WEEK_OF_YEAR)) * 7);
+                case MONTH_OF_YEAR: return resolvePreviousValid(yearOfEra, nvalue, dayOfMonth);
+                case YEAR_OF_ERA: return resolvePreviousValid(yearOfEra >= 1 ? nvalue : 1 - nvalue, monthOfYear, dayOfMonth);
+                case YEAR: return resolvePreviousValid(nvalue, monthOfYear, dayOfMonth);
+                case ERA: return resolvePreviousValid(1 - yearOfEra, monthOfYear, dayOfMonth);
+            }
+            throw new DateTimeException("Unsupported field: " + field.getName());
+        }
+        return (HijrahDate) ChronoLocalDate.super.with(field, newValue);
+    }
+
+    private HijrahDate resolvePreviousValid(int yearOfEra, int month, int day) {
+        int monthDays = getMonthDays(month - 1, yearOfEra);
+        if (day > monthDays) {
+            day = monthDays;
+        }
+        return HijrahDate.of(chrono, yearOfEra, month, day);
+    }
+
+    @Override
+    public long toEpochDay() {
+         return chrono.getGregorianEpochDay(yearOfEra, monthOfYear, dayOfMonth);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public HijrahEra getEra() {
+        return this.era;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the year is a leap year, according to the Hijrah calendar system rules.
+     *
+     * @return true if this date is in a leap year
+     */
+    @Override
+    public boolean isLeapYear() {
+        return this.isLeapYear;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public HijrahDate plusYears(long years) {
+        if (years == 0) {
+            return this;
+        }
+        int newYear = Math.addExact(this.yearOfEra, (int)years);
+        return HijrahDate.of(chrono, this.era, newYear, this.monthOfYear, this.dayOfMonth);
+    }
+
+    @Override
+    public HijrahDate plusMonths(long months) {
+        if (months == 0) {
+            return this;
+        }
+        int newMonth = this.monthOfYear - 1;
+        newMonth = newMonth + (int)months;
+        int years = newMonth / 12;
+        newMonth = newMonth % 12;
+        while (newMonth < 0) {
+            newMonth += 12;
+            years = Math.subtractExact(years, 1);
+        }
+        int newYear = Math.addExact(this.yearOfEra, years);
+        return HijrahDate.of(chrono, this.era, newYear, newMonth + 1, this.dayOfMonth);
+    }
+
+    @Override
+    public HijrahDate plusDays(long days) {
+        return new HijrahDate(chrono, this.gregorianEpochDay + days);
+    }
+
+    /**
+     * Returns month days from the beginning of year.
+     *
+     * @param month  month (0-based)
+     * @parma year  year
+     * @return month days from the beginning of year
+     */
+    private int getMonthDays(int month, int year) {
+        int[] newMonths = chrono.getAdjustedMonthDays(year);
+        return newMonths[month];
+    }
+
+    /**
+     * Returns month length.
+     *
+     * @param month  month (0-based)
+     * @param year  year
+     * @return month length
+     */
+    private int getMonthLength(int month, int year) {
+      int[] newMonths = chrono.getAdjustedMonthLength(year);
+      return newMonths[month];
+    }
+
+    @Override
+    public int lengthOfMonth() {
+        return getMonthLength(monthOfYear - 1, yearOfEra);
+    }
+
+    @Override
+    public int lengthOfYear() {
+        return chrono.getYearLength(yearOfEra);  // TODO: proleptic year
+    }
+
+    //-----------------------------------------------------------------------
+    private Object writeReplace() {
+        return new Ser(Ser.HIJRAH_DATE_TYPE, this);
+    }
+
+    void writeExternal(ObjectOutput out) throws IOException {
+        // HijrahChrono is implicit in the Hijrah_DATE_TYPE
+        out.writeObject(chrono);
+        out.writeInt(get(YEAR));
+        out.writeByte(get(MONTH_OF_YEAR));
+        out.writeByte(get(DAY_OF_MONTH));
+    }
+
+    /**
+     * Replaces the date instance from the stream with a valid one.
+     * ReadExternal has already read the fields and created a new instance
+     * from the data.
+     *
+     * @return the resolved date, never null
+     */
+    private Object readResolve() {
+        return this;
+    }
+
+    static ChronoLocalDate<HijrahChrono> readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+        HijrahChrono chrono = (HijrahChrono)in.readObject();
+        int year = in.readInt();
+        int month = in.readByte();
+        int dayOfMonth = in.readByte();
+        return chrono.date(year, month, dayOfMonth);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/calendar/HijrahDeviationReader.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.calendar;
+
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.file.FileSystems;
+import java.security.AccessController;
+import java.text.ParseException;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatters;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoLocalDate;
+import java.util.Arrays;
+import java.util.function.Block;
+
+/**
+ * A reader for Hijrah Deviation files.
+ * <p>
+ * For each Hijrah calendar a deviation file is used
+ * to modify the initial Hijrah calendar by changing the length of
+ * individual months.
+ * <p>
+ * The default location of the deviation files is
+ * {@code <java.home> + FILE_SEP + "lib"}.
+ * The deviation files are named {@code "hijrah_" + ID}.
+ * <p>
+ * The deviation file for a calendar can be overridden by defining the
+ * property {@code java.time.calendar.HijrahChrono.File.hijrah_<ID>}
+ * with the full pathname of the deviation file.
+ * <p>
+ * The deviation file is read line by line:
+ * <ul>
+ * <li>The "#" character begins a comment -
+ *     all characters including and after the "#" on the line are ignored</li>
+ * <li>Valid lines contain two fields, separated by whitespace, whitespace
+ *     is otherwise ignored.</li>
+ * <li>The first field is a LocalDate using the format "MMM-dd-yyyy";
+ *     The LocalDate must be converted to a HijrahDate using
+ *     the {@code islamic} calendar.</li>
+ * <li>The second field is the offset, +2, +1, -1, -2 as parsed
+ *     by Integer.valueOf to modify the length of the Hijrah month.</li>
+ * <li>Empty lines are ignore.</li>
+ * <li>Exceptions are throw for invalid formatted dates and offset,
+ *     and other I/O errors on the file.
+ * </ul>
+ * <p>Example:</p>
+ * <pre># Deviation data for islamicc calendar
+ * Mar-23-2012 -1
+ * Apr-22-2012 +1
+ * May-21-2012 -1
+ * Dec-14-2012 +1
+ * </pre>
+ *
+ * @since 1.8
+ */
+final class HijrahDeviationReader {
+
+    /**
+     * Default prefix for name of deviation file; suffix is typeId.
+     */
+    private static final String DEFAULT_CONFIG_FILE_PREFIX = "hijrah_";
+
+    /**
+     * Read Hijrah_deviation.cfg file. The config file contains the deviation
+     * data with format defined in the class javadoc.
+     *
+     * @param typeId the name of the calendar
+     * @param calendarType the calendar type
+     * @return {@code true} if the file was read and each entry accepted by the
+     * Block; else {@code false} no configuration was done
+     *
+     * @throws IOException for zip/jar file handling exception.
+     * @throws ParseException if the format of the configuration file is wrong.
+     */
+    static boolean readDeviation(String typeId, String calendarType,
+            Block<HijrahChrono.Deviation> block) throws IOException, ParseException {
+        InputStream is = getConfigFileInputStream(typeId);
+        if (is != null) {
+            try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
+                String line = "";
+                int num = 0;
+                while ((line = br.readLine()) != null) {
+                    num++;
+                    HijrahChrono.Deviation entry = parseLine(line, num);
+                    if (entry != null) {
+                        block.accept(entry);
+                    }
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Parse each deviation element.
+     *
+     * @param line  a line to parse
+     * @param num  line number
+     * @return an Entry or null if the line is empty.
+     * @throws ParseException if line has incorrect format.
+     */
+    private static HijrahChrono.Deviation parseLine(final String line, final int num) throws ParseException {
+        int hash = line.indexOf("#");
+        String nocomment = (hash < 0) ? line : line.substring(0, hash);
+        String[] split = nocomment.split("\\s");
+        if (split.length == 0 || split[0].isEmpty()) {
+            return null;    // Nothing to parse
+        }
+        if (split.length != 2) {
+            throw new ParseException("Less than 2 tokens on line : " + line + Arrays.toString(split) + ", split.length: " + split.length, num);
+        }
+
+        //element [0] is a date
+        //element [1] is the offset
+
+        LocalDate isoDate = DateTimeFormatters.pattern("MMM-dd-yyyy").parse(split[0], LocalDate::from);
+        int offset = Integer.valueOf(split[1]);
+
+        // Convert date to HijrahDate using the default Islamic Calendar
+
+        ChronoLocalDate<HijrahChrono> hijrahDate = HijrahChrono.INSTANCE.date(isoDate);
+
+        int year = hijrahDate.get(ChronoField.YEAR);
+        int month = hijrahDate.get(ChronoField.MONTH_OF_YEAR);
+        return new HijrahChrono.Deviation(year, month, year, month, offset);
+    }
+
+
+    /**
+     * Return InputStream for deviation configuration file. The default location
+     * of the deviation file is:
+     * <pre>
+     *   $CLASSPATH/java/time/calendar
+     * </pre> And the default file name is:
+     * <pre>
+     *   hijrah_ + typeId + .cfg
+     * </pre> The default location and file name can be overridden by setting
+     * following two Java system properties.
+     * <pre>
+     *   Location: java.time.calendar.HijrahDate.deviationConfigDir
+     *   File name: java.time.calendar.HijrahDate.File. + typeid
+     * </pre> Regarding the file format, see readDeviationConfig() method for
+     * details.
+     *
+     * @param typeId the name of the calendar deviation data
+     * @return InputStream for file reading.
+     * @throws IOException for zip/jar file handling exception.
+     */
+    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;
+                String filename = System.getProperty(propFilename);
+                File file = null;
+                if (filename != null) {
+                    file = new File(filename);
+                } else {
+                    String libDir = System.getProperty("java.home") + File.separator + "lib";
+                    try {
+                        libDir = FileSystems.getDefault().getPath(libDir).toRealPath().toString();
+                    } catch(Exception e) {}
+                    filename = DEFAULT_CONFIG_FILE_PREFIX + typeId + ".cfg";
+                    file = new File(libDir, filename);
+                }
+
+                if (file.exists()) {
+                    try {
+                        return new FileInputStream(file);
+                    } catch (IOException ioe) {
+                        throw ioe;
+                    }
+                } else {
+                    return null;
+                }
+            });
+            return stream;
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            // Not working
+            return null;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/calendar/HijrahEra.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.calendar;
+
+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 Hijrah calendar system.
+ * <p>
+ * The Hijrah calendar system has two eras.
+ * The date {@code 0001-01-01 (Hijrah)} is {@code 622-06-19 (ISO)}.
+ * <p>
+ * <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code HijrahEra}.
+ * Use {@code getValue()} instead.</b>
+ *
+ * <h3>Specification for implementors</h3>
+ * This is an immutable and thread-safe enum.
+ *
+ * @since 1.8
+ */
+enum HijrahEra implements Era<HijrahChrono> {
+
+    /**
+     * The singleton instance for the era before the current one, 'Before Anno Hegirae',
+     * which has the value 0.
+     */
+    BEFORE_AH,
+    /**
+     * The singleton instance for the current era, 'Anno Hegirae', which has the value 1.
+     */
+    AH;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code HijrahEra} from a value.
+     * <p>
+     * The current era (from ISO date 622-06-19 onwards) has the value 1
+     * The previous era has the value 0.
+     *
+     * @param hijrahEra  the era to represent, from 0 to 1
+     * @return the HijrahEra singleton, never null
+     * @throws DateTimeException if the era is invalid
+     */
+    public static HijrahEra of(int hijrahEra) {
+        switch (hijrahEra) {
+            case 0:
+                return BEFORE_AH;
+            case 1:
+                return AH;
+            default:
+                throw new DateTimeException("HijrahEra not valid");
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the era numeric value.
+     * <p>
+     * The current era (from ISO date 622-06-19 onwards) has the value 1.
+     * The previous era has the value 0.
+     *
+     * @return the era value, from 0 (BEFORE_AH) to 1 (AH)
+     */
+    @Override
+    public int getValue() {
+        return ordinal();
+    }
+
+    @Override
+    public HijrahChrono getChrono() {
+        return HijrahChrono.INSTANCE;
+    }
+
+    // JDK8 default methods:
+    //-----------------------------------------------------------------------
+    @Override
+    public ChronoLocalDate<HijrahChrono> date(int year, int month, int day) {
+        return getChrono().date(this, year, month, day);
+    }
+
+    @Override
+    public ChronoLocalDate<HijrahChrono> 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);
+    }
+
+    /**
+     * Returns the proleptic year from this era and year of era.
+     *
+     * @param yearOfEra the year of Era
+     * @return the computed prolepticYear
+     */
+    int prolepticYear(int yearOfEra) {
+        return (this == HijrahEra.AH ? yearOfEra : 1 - yearOfEra);
+    }
+
+    //-----------------------------------------------------------------------
+    private Object writeReplace() {
+        return new Ser(Ser.HIJRAH_ERA_TYPE, this);
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        out.writeByte(this.getValue());
+    }
+
+    static HijrahEra readExternal(DataInput in) throws IOException {
+        byte eraValue = in.readByte();
+        return HijrahEra.of(eraValue);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/calendar/JapaneseChrono.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.calendar;
+
+import java.io.Serializable;
+import java.time.DateTimeException;
+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.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;
+
+/**
+ * The Japanese Imperial calendar system.
+ * <p>
+ * This chronology defines the rules of the Japanese Imperial calendar system.
+ * 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.
+ * <p>
+ * Only Meiji (1865-04-07 - 1868-09-07) and later eras are supported.
+ * Older eras are handled as an unknown era where the year-of-era is the ISO year.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class JapaneseChrono extends Chrono<JapaneseChrono> implements Serializable {
+    // TODO: definition for unknown era may break requirement that year-of-era >= 1
+
+    static final LocalGregorianCalendar JCAL =
+        (LocalGregorianCalendar) CalendarSystem.forName("japanese");
+
+    // Locale for creating a JapaneseImpericalCalendar.
+    static final Locale LOCALE = Locale.forLanguageTag("ja-JP-u-ca-japanese");
+
+    /**
+     * Singleton instance for Japanese chronology.
+     */
+    public static final JapaneseChrono INSTANCE = new JapaneseChrono();
+
+    /**
+     * The singleton instance for the before Meiji era ( - 1868-09-07)
+     * which has the value -999.
+     */
+    public static final Era<JapaneseChrono> 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<JapaneseChrono> 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<JapaneseChrono> 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<JapaneseChrono> ERA_SHOWA = JapaneseEra.SHOWA;
+    /**
+     * The singleton instance for the Heisei era (1989-01-08 - current)
+     * which has the value 2.
+     */
+    public static final Era<JapaneseChrono> ERA_HEISEI = JapaneseEra.HEISEI;
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 459996390165777884L;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Restricted constructor.
+     */
+    private JapaneseChrono() {
+    }
+
+    /**
+     * Resolve singleton.
+     *
+     * @return the singleton instance, not null
+     */
+    private Object readResolve() {
+        return INSTANCE;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the ID of the chronology - 'Japanese'.
+     * <p>
+     * The ID uniquely identifies the {@code Chrono}.
+     * It can be used to lookup the {@code Chrono} using {@link #of(String)}.
+     *
+     * @return the chronology ID - 'Japanese'
+     * @see #getCalendarType()
+     */
+    @Override
+    public String getId() {
+        return "Japanese";
+    }
+
+    /**
+     * Gets the calendar type of the underlying calendar system - 'japanese'.
+     * <p>
+     * The calendar type is an identifier defined by the
+     * <em>Unicode Locale Data Markup Language (LDML)</em> specification.
+     * It can be used to lookup the {@code Chrono} using {@link #of(String)}.
+     * It can also be used as part of a locale, accessible via
+     * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
+     *
+     * @return the calendar system type - 'japanese'
+     * @see #getId()
+     */
+    @Override
+    public String getCalendarType() {
+        return "japanese";
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ChronoLocalDate<JapaneseChrono> date(Era<JapaneseChrono> 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);
+    }
+
+    @Override
+    public ChronoLocalDate<JapaneseChrono> date(int prolepticYear, int month, int dayOfMonth) {
+        return new JapaneseDate(LocalDate.of(prolepticYear, month, dayOfMonth));
+    }
+
+    @Override
+    public ChronoLocalDate<JapaneseChrono> dateYearDay(int prolepticYear, int dayOfYear) {
+        LocalDate date = LocalDate.ofYearDay(prolepticYear, dayOfYear);
+        return date(prolepticYear, date.getMonthValue(), date.getDayOfMonth());
+    }
+
+    @Override
+    public ChronoLocalDate<JapaneseChrono> date(TemporalAccessor temporal) {
+        if (temporal instanceof JapaneseDate) {
+            return (JapaneseDate) temporal;
+        }
+        return new JapaneseDate(LocalDate.from(temporal));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified year is a leap year.
+     * <p>
+     * Japanese calendar leap years occur exactly in line with ISO leap years.
+     * This method does not validate the year passed in, and only has a
+     * well-defined result for years in the supported range.
+     *
+     * @param prolepticYear  the proleptic-year to check, not validated for range
+     * @return true if the year is a leap year
+     */
+    @Override
+    public boolean isLeapYear(long prolepticYear) {
+        return ISOChrono.INSTANCE.isLeapYear(prolepticYear);
+    }
+
+    @Override
+    public int prolepticYear(Era<JapaneseChrono> era, int yearOfEra) {
+        if (era instanceof JapaneseEra == false) {
+            throw new DateTimeException("Era must be JapaneseEra");
+        }
+        JapaneseEra jera = (JapaneseEra) era;
+        int gregorianYear = jera.getPrivateEra().getSinceDate().getYear() + yearOfEra - 1;
+        if (yearOfEra == 1) {
+            return gregorianYear;
+        }
+        LocalGregorianCalendar.Date jdate = JCAL.newCalendarDate(null);
+        jdate.setEra(jera.getPrivateEra()).setDate(yearOfEra, 1, 1);
+        JCAL.normalize(jdate);
+        if (jdate.getNormalizedYear() == gregorianYear) {
+            return gregorianYear;
+        }
+        throw new DateTimeException("invalid yearOfEra value");
+    }
+
+    /**
+     * Returns the calendar system era object from the given numeric value.
+     *
+     * See the description of each Era for the numeric values of:
+     * {@link #ERA_HEISEI}, {@link #ERA_SHOWA},{@link #ERA_TAISHO},
+     * {@link #ERA_MEIJI}), only Meiji and later eras are supported.
+     * Prior to Meiji {@link #ERA_SEIREKI} is used.
+     *
+     * @param eraValue  the era value
+     * @return the Japanese {@code Era} for the given numeric era value
+     * @throws DateTimeException if {@code eraValue} is invalid
+     */
+    @Override
+    public Era<JapaneseChrono> eraOf(int eraValue) {
+        return JapaneseEra.of(eraValue);
+    }
+
+    @Override
+    public List<Era<JapaneseChrono>> eras() {
+        return Arrays.<Era<JapaneseChrono>>asList(JapaneseEra.values());
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ValueRange range(ChronoField field) {
+        switch (field) {
+            case DAY_OF_MONTH:
+            case DAY_OF_WEEK:
+            case MICRO_OF_DAY:
+            case MICRO_OF_SECOND:
+            case HOUR_OF_DAY:
+            case HOUR_OF_AMPM:
+            case MINUTE_OF_DAY:
+            case MINUTE_OF_HOUR:
+            case SECOND_OF_DAY:
+            case SECOND_OF_MINUTE:
+            case MILLI_OF_DAY:
+            case MILLI_OF_SECOND:
+            case NANO_OF_DAY:
+            case NANO_OF_SECOND:
+            case CLOCK_HOUR_OF_DAY:
+            case CLOCK_HOUR_OF_AMPM:
+            case EPOCH_DAY:
+            case EPOCH_MONTH:
+                return field.range();
+        }
+        Calendar jcal = Calendar.getInstance(LOCALE);
+        int fieldIndex;
+        switch (field) {
+            case ERA:
+                return ValueRange.of(jcal.getMinimum(Calendar.ERA) - JapaneseEra.ERA_OFFSET,
+                        jcal.getMaximum(Calendar.ERA) - JapaneseEra.ERA_OFFSET);
+            case YEAR:
+            case YEAR_OF_ERA:
+                return ValueRange.of(Year.MIN_VALUE, jcal.getGreatestMinimum(Calendar.YEAR),
+                        jcal.getLeastMaximum(Calendar.YEAR), Year.MAX_VALUE);
+            case MONTH_OF_YEAR:
+                return ValueRange.of(jcal.getMinimum(Calendar.MONTH) + 1, jcal.getGreatestMinimum(Calendar.MONTH) + 1,
+                        jcal.getLeastMaximum(Calendar.MONTH) + 1, jcal.getMaximum(Calendar.MONTH) + 1);
+            case DAY_OF_YEAR:
+                fieldIndex = Calendar.DAY_OF_YEAR;
+                break;
+            default:
+                 // TODO: review the remaining fields
+                throw new UnsupportedOperationException("Unimplementable field: " + field);
+        }
+        return ValueRange.of(jcal.getMinimum(fieldIndex), jcal.getGreatestMinimum(fieldIndex),
+                jcal.getLeastMaximum(fieldIndex), jcal.getMaximum(fieldIndex));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/calendar/JapaneseDate.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,377 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.calendar;
+
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.YEAR;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoLocalDate;
+import java.time.temporal.TemporalField;
+import java.time.temporal.ValueRange;
+import java.util.Calendar;
+import java.util.Objects;
+
+import sun.util.calendar.LocalGregorianCalendar;
+
+/**
+ * A date in the Japanese Imperial calendar system.
+ * <p>
+ * This implements {@code ChronoLocalDate} for the
+ * {@linkplain JapaneseChrono Japanese Imperial calendar}.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+final class JapaneseDate
+        extends ChronoDateImpl<JapaneseChrono>
+        implements ChronoLocalDate<JapaneseChrono>, Serializable {
+    // this class is package-scoped so that future conversion to public
+    // would not change serialization
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -305327627230580483L;
+
+    /**
+     * The underlying ISO local date.
+     */
+    private transient final LocalDate isoDate;
+    /**
+     * The JapaneseEra of this date.
+     */
+    private transient JapaneseEra era;
+    /**
+     * The Japanese imperial calendar year of this date.
+     */
+    private transient int yearOfEra;
+
+    /**
+     * Obtains an instance of {@code JapaneseDate} from the era, year-of-era,
+     * month-of-year and day-of-month.
+     *
+     * @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
+     */
+    static JapaneseDate of(JapaneseEra era, int yearOfEra, int month, int dayOfMonth) {
+        Objects.requireNonNull(era, "era");
+        LocalGregorianCalendar.Date jdate = JapaneseChrono.JCAL.newCalendarDate(null);
+        jdate.setEra(era.getPrivateEra()).setDate(yearOfEra, month, dayOfMonth);
+        if (!JapaneseChrono.JCAL.validate(jdate)) {
+            throw new IllegalArgumentException();
+        }
+        LocalDate date = LocalDate.of(jdate.getNormalizedYear(), month, dayOfMonth);
+        return new JapaneseDate(era, yearOfEra, date);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Creates an instance from an ISO date.
+     *
+     * @param isoDate  the standard local date, validated not null
+     */
+    JapaneseDate(LocalDate isoDate) {
+        LocalGregorianCalendar.Date jdate = toPrivateJapaneseDate(isoDate);
+        this.era = JapaneseEra.toJapaneseEra(jdate.getEra());
+        this.yearOfEra = jdate.getYear();
+        this.isoDate = isoDate;
+    }
+
+    /**
+     * Constructs a {@code JapaneseDate}. This constructor does NOT validate the given parameters,
+     * and {@code era} and {@code year} must agree with {@code isoDate}.
+     *
+     * @param era  the era, validated not null
+     * @param year  the year-of-era, validated
+     * @param isoDate  the standard local date, validated not null
+     */
+    JapaneseDate(JapaneseEra era, int year, LocalDate isoDate) {
+        this.era = era;
+        this.yearOfEra = year;
+        this.isoDate = isoDate;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public JapaneseChrono getChrono() {
+        return JapaneseChrono.INSTANCE;
+    }
+
+    @Override
+    public int lengthOfMonth() {
+        return isoDate.lengthOfMonth();
+    }
+
+    @Override
+    public ValueRange range(TemporalField field) {
+        if (field instanceof ChronoField) {
+            if (isSupported(field)) {
+                ChronoField f = (ChronoField) field;
+                switch (f) {
+                    case DAY_OF_YEAR:
+                        return actualRange(Calendar.DAY_OF_YEAR);
+                    case YEAR_OF_ERA:
+                        return actualRange(Calendar.YEAR);
+                }
+                return getChrono().range(f);
+            }
+            throw new DateTimeException("Unsupported field: " + field.getName());
+        }
+        return field.doRange(this);
+    }
+
+    private ValueRange actualRange(int calendarField) {
+        Calendar jcal = Calendar.getInstance(JapaneseChrono.LOCALE);
+        jcal.set(Calendar.ERA, era.getValue() + JapaneseEra.ERA_OFFSET);
+        jcal.set(yearOfEra, isoDate.getMonthValue() - 1, isoDate.getDayOfMonth());
+        return ValueRange.of(jcal.getActualMinimum(calendarField),
+                jcal.getActualMaximum(calendarField));
+    }
+
+    @Override
+    public long getLong(TemporalField field) {
+        if (field instanceof ChronoField) {
+            switch ((ChronoField) field) {
+                case YEAR_OF_ERA:
+                    return yearOfEra;
+                case ERA:
+                    return era.getValue();
+                case DAY_OF_YEAR: {
+                    LocalGregorianCalendar.Date jdate = toPrivateJapaneseDate(isoDate);
+                    return JapaneseChrono.JCAL.getDayOfYear(jdate);
+                }
+            }
+            // TODO: review other fields
+            return isoDate.getLong(field);
+        }
+        return field.doGet(this);
+    }
+
+    /**
+     * Returns a {@code LocalGregorianCalendar.Date} converted from the given {@code isoDate}.
+     *
+     * @param isoDate  the local date, not null
+     * @return a {@code LocalGregorianCalendar.Date}, not null
+     */
+    private static LocalGregorianCalendar.Date toPrivateJapaneseDate(LocalDate isoDate) {
+        LocalGregorianCalendar.Date jdate = JapaneseChrono.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);
+        return jdate;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public JapaneseDate with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            if (getLong(f) == newValue) {
+                return this;
+            }
+            switch (f) {
+                case YEAR_OF_ERA:
+                case YEAR:
+                case ERA: {
+                    f.checkValidValue(newValue);
+                    int nvalue = (int) newValue;
+                    switch (f) {
+                        case YEAR_OF_ERA:
+                            return this.withYear(nvalue);
+                        case YEAR:
+                            return with(isoDate.withYear(nvalue));
+                        case ERA: {
+                            return this.withYear(JapaneseEra.of(nvalue), yearOfEra);
+                        }
+                    }
+                }
+            }
+            // TODO: review other fields, such as WEEK_OF_YEAR
+            return with(isoDate.with(field, newValue));
+        }
+        return (JapaneseDate) ChronoLocalDate.super.with(field, newValue);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this date with the year altered.
+     * <p>
+     * This method changes the year of the date.
+     * If the month-day is invalid for the year, then the previous valid day
+     * will be selected instead.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param era  the era to set in the result, not null
+     * @param yearOfEra  the year-of-era to set in the returned date
+     * @return a {@code JapaneseDate} based on this date with the requested year, never null
+     * @throws DateTimeException if {@code year} is invalid
+     */
+    private JapaneseDate withYear(JapaneseEra era, int yearOfEra) {
+        int year = JapaneseChrono.INSTANCE.prolepticYear(era, yearOfEra);
+        return with(isoDate.withYear(year));
+    }
+
+    /**
+     * Returns a copy of this date with the year-of-era altered.
+     * <p>
+     * This method changes the year-of-era of the date.
+     * If the month-day is invalid for the year, then the previous valid day
+     * will be selected instead.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param year  the year to set in the returned date
+     * @return a {@code JapaneseDate} based on this date with the requested year-of-era, never null
+     * @throws DateTimeException if {@code year} is invalid
+     */
+    private JapaneseDate withYear(int year) {
+        return withYear((JapaneseEra) getEra(), year);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    JapaneseDate plusYears(long years) {
+        return with(isoDate.plusYears(years));
+    }
+
+    @Override
+    JapaneseDate plusMonths(long months) {
+        return with(isoDate.plusMonths(months));
+    }
+
+    @Override
+    JapaneseDate plusDays(long days) {
+        return with(isoDate.plusDays(days));
+    }
+
+    private JapaneseDate with(LocalDate newDate) {
+        return (newDate.equals(isoDate) ? this : new JapaneseDate(newDate));
+    }
+
+    @Override  // override for performance
+    public long toEpochDay() {
+        return isoDate.toEpochDay();
+    }
+
+    //-------------------------------------------------------------------------
+    @Override  // override for performance
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof JapaneseDate) {
+            JapaneseDate otherDate = (JapaneseDate) obj;
+            return this.isoDate.equals(otherDate.isoDate);
+        }
+        return false;
+    }
+
+    @Override  // override for performance
+    public int hashCode() {
+        return getChrono().getId().hashCode() ^ isoDate.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        if (era == JapaneseEra.SEIREKI) {
+            return getChrono().getId() + " " + isoDate.toString();
+        }
+        return super.toString();
+    }
+
+    //-----------------------------------------------------------------------
+    private Object writeReplace() {
+        return new Ser(Ser.JAPANESE_DATE_TYPE, this);
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        // JapaneseChrono 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<JapaneseChrono> readExternal(DataInput in) throws IOException {
+        int year = in.readInt();
+        int month = in.readByte();
+        int dayOfMonth = in.readByte();
+        return JapaneseChrono.INSTANCE.date(year, month, dayOfMonth);
+    }
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/calendar/JapaneseEra.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.calendar;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.temporal.Era;
+import java.util.Arrays;
+
+import sun.util.calendar.CalendarDate;
+
+/**
+ * An era in the Japanese Imperial calendar system.
+ * <p>
+ * This class defines the valid eras for the Japanese chronology.
+ * Only Meiji (1868-09-08 - 1912-07-29) and later eras are supported.
+ * Japan introduced the Gregorian calendar since Meiji 6. The dates
+ * between Meiji 1 - 5 are not historically correct.
+ * The older eras are recognized as Seireki (Western calendar) era,
+ * and the year of era of Seireki is proleptic Gregorian year.
+ * (The Julian to Gregorian transition is not supported.)
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+final class JapaneseEra
+        implements Era<JapaneseChrono>, 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
+    static final int ERA_OFFSET = 2;
+
+    static final sun.util.calendar.Era[] ERA_CONFIG;
+
+    /**
+     * The singleton instance for the before Meiji era ( - 1868-09-07)
+     * which has the value -999.
+     */
+    public static final JapaneseEra SEIREKI = new JapaneseEra(-999, LocalDate.MIN);
+    /**
+     * The singleton instance for the 'Meiji' era (1868-09-08 - 1912-07-29)
+     * which has the value -1.
+     */
+    public static final JapaneseEra MEIJI = new JapaneseEra(-1, LocalDate.of(1868, 9, 8));
+    /**
+     * The singleton instance for the 'Taisho' era (1912-07-30 - 1926-12-24)
+     * which has the value 0.
+     */
+    public static final JapaneseEra TAISHO = new JapaneseEra(0, LocalDate.of(1912, 7, 30));
+    /**
+     * The singleton instance for the 'Showa' era (1926-12-25 - 1989-01-07)
+     * which has the value 1.
+     */
+    public static final JapaneseEra SHOWA = new JapaneseEra(1, LocalDate.of(1926, 12, 25));
+    /**
+     * The singleton instance for the 'Heisei' era (1989-01-08 - current)
+     * which has the value 2.
+     */
+    public static final JapaneseEra HEISEI = new JapaneseEra(2, LocalDate.of(1989, 1, 8));
+
+    // the number of defined JapaneseEra constants.
+    // There could be an extra era defined in its configuration.
+    private static final int N_ERA_CONSTANTS = HEISEI.getValue() + ERA_OFFSET + 1;
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 1466499369062886794L;
+
+    // array for the singleton JapaneseEra instances
+    private static final JapaneseEra[] KNOWN_ERAS;
+
+    static {
+        sun.util.calendar.Era[] sunEras = JapaneseChrono.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];
+        }
+        KNOWN_ERAS = new JapaneseEra[ERA_CONFIG.length];
+        KNOWN_ERAS[0] = SEIREKI;
+        KNOWN_ERAS[1] = MEIJI;
+        KNOWN_ERAS[2] = TAISHO;
+        KNOWN_ERAS[3] = SHOWA;
+        KNOWN_ERAS[4] = HEISEI;
+        for (int i = N_ERA_CONSTANTS; i < ERA_CONFIG.length; i++) {
+            CalendarDate date = ERA_CONFIG[i].getSinceDate();
+            LocalDate isoDate = LocalDate.of(date.getYear(), date.getMonth(), date.getDayOfMonth());
+            KNOWN_ERAS[i] = new JapaneseEra(i - ERA_OFFSET, isoDate);
+        }
+    };
+
+    /**
+     * The era value.
+     * @serial
+     */
+    private final int eraValue;
+
+    // the first day of the era
+    private final transient LocalDate since;
+
+    /**
+     * Creates an instance.
+     *
+     * @param eraValue  the era value, validated
+     * @param since  the date representing the first date of the era, validated not null
+     */
+    private JapaneseEra(int eraValue, LocalDate since) {
+        this.eraValue = eraValue;
+        this.since = since;
+    }
+
+    /**
+     * Returns the singleton {@code JapaneseEra} corresponding to this object.
+     * It's possible that this version of {@code JapaneseEra} doesn't support the latest era value.
+     * In that case, this method throws an {@code ObjectStreamException}.
+     *
+     * @return the singleton {@code JapaneseEra} for this object
+     * @throws ObjectStreamException if the deserialized object has any unknown numeric era value.
+     */
+    private Object readResolve() throws ObjectStreamException {
+        try {
+            return of(eraValue);
+        } catch (DateTimeException e) {
+            InvalidObjectException ex = new InvalidObjectException("Invalid era");
+            ex.initCause(e);
+            throw ex;
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns the Sun private Era instance corresponding to this {@code JapaneseEra}.
+     * SEIREKI doesn't have its corresponding one.
+     *
+     * @return the Sun private Era instance for this {@code JapaneseEra},
+     *         or null for SEIREKI.
+     */
+    sun.util.calendar.Era getPrivateEra() {
+        return ERA_CONFIG[ordinal(eraValue)];
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code JapaneseEra} from a value.
+     * <p>
+     * The {@link #SHOWA} era that contains 1970-01-01 (ISO calendar system) has the value 1
+     * Later era is numbered 2 ({@link #HEISEI}). Earlier eras are numbered 0 ({@link #TAISHO}),
+     * -1 ({@link #MEIJI}), only Meiji and later eras are supported. The prior to Meiji,
+     * {@link #SEIREKI} is used.
+     *
+     * @param japaneseEra  the era to represent
+     * @return the {@code JapaneseEra} singleton, never null
+     * @throws DateTimeException if {@code japaneseEra} is invalid
+     */
+    public static JapaneseEra of(int japaneseEra) {
+        if (japaneseEra != SEIREKI.eraValue &&
+            (japaneseEra < MEIJI.eraValue || japaneseEra > HEISEI.eraValue)) {
+            throw new DateTimeException("japaneseEra is invalid");
+        }
+        return KNOWN_ERAS[ordinal(japaneseEra)];
+    }
+
+    /**
+     * Returns an array of JapaneseEras.
+     * @return an array of JapaneseEras
+     */
+    static JapaneseEra[] values() {
+        return Arrays.copyOf(KNOWN_ERAS, KNOWN_ERAS.length);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code JapaneseEra} from a date.
+     *
+     * @param date  the date, not null
+     * @return the Era singleton, never null
+     */
+    static JapaneseEra from(LocalDate date) {
+        for (int i = KNOWN_ERAS.length - 1; i > 0; i--) {
+            JapaneseEra era = KNOWN_ERAS[i];
+            if (date.compareTo(era.since) >= 0) {
+                return era;
+            }
+        }
+        return SEIREKI;
+    }
+
+    static JapaneseEra toJapaneseEra(sun.util.calendar.Era privateEra) {
+        for (int i = ERA_CONFIG.length - 1; i > 0; i--) {
+            if (ERA_CONFIG[i].equals(privateEra)) {
+                return KNOWN_ERAS[i];
+            }
+        }
+        return SEIREKI;
+    }
+
+    static sun.util.calendar.Era privateEraFrom(LocalDate isoDate) {
+        for (int i = KNOWN_ERAS.length - 1; i > 0; i--) {
+            JapaneseEra era = KNOWN_ERAS[i];
+            if (isoDate.compareTo(era.since) >= 0) {
+                return ERA_CONFIG[i];
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns the index into the arrays from the Era value.
+     * the eraValue is a valid Era number, -999, -1..2.
+     * @param eravalue the era value to convert to the index
+     * @return the index of the current Era
+     */
+    private static int ordinal(int eravalue) {
+        return (eravalue == SEIREKI.eraValue) ? 0 : eravalue + ERA_OFFSET;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns the numeric value of this {@code JapaneseEra}.
+     * <p>
+     * The {@link #SHOWA} era that contains 1970-01-01 (ISO calendar system) has the value 1.
+     * Later eras are numbered from 2 ({@link #HEISEI}).
+     * Earlier eras are numbered 0 ({@link #TAISHO}), -1 ({@link #MEIJI}), and -999 ({@link #SEIREKI}).
+     *
+     * @return the era value
+     */
+    @Override
+    public int getValue() {
+        return eraValue;
+    }
+
+    @Override
+    public JapaneseChrono getChrono() {
+        return JapaneseChrono.INSTANCE;
+    }
+
+    //-----------------------------------------------------------------------
+    String getAbbreviation() {
+        int index = ordinal(getValue());
+        if (index == 0) {
+            return "";
+        }
+        return ERA_CONFIG[index].getAbbreviation();
+    }
+
+    String getName() {
+        int index = ordinal(getValue());
+        if (index == 0) {
+            return "Seireki";
+        }
+        return ERA_CONFIG[index].getName();
+    }
+
+    @Override
+    public String toString() {
+        return getName();
+    }
+
+    //-----------------------------------------------------------------------
+    private Object writeReplace() {
+        return new Ser(Ser.JAPANESE_ERA_TYPE, this);
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        out.writeByte(this.getValue());
+    }
+
+    static JapaneseEra readExternal(DataInput in) throws IOException {
+        byte eraValue = in.readByte();
+        return JapaneseEra.of(eraValue);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/calendar/MinguoChrono.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.calendar;
+
+import static java.time.temporal.ChronoField.YEAR;
+
+import java.io.Serializable;
+import java.time.DateTimeException;
+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.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * The Minguo calendar system.
+ * <p>
+ * 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)}.
+ * <p>
+ * The fields are defined as follows:
+ * <p><ul>
+ * <li>era - There are two eras, the current 'Republic' (ERA_ROC) and the previous era (ERA_BEFORE_ROC).
+ * <li>year-of-era - The year-of-era for the current era increases uniformly from the epoch at year one.
+ *  For the previous era the year increases from one as time goes backwards.
+ *  The value for the current era is equal to the ISO proleptic-year minus 1911.
+ * <li>proleptic-year - The proleptic year is the same as the year-of-era for the
+ *  current era. For the previous era, years have zero, then negative values.
+ *  The value is equal to the ISO proleptic-year minus 1911.
+ * <li>month-of-year - The Minguo month-of-year exactly matches ISO.
+ * <li>day-of-month - The Minguo day-of-month exactly matches ISO.
+ * <li>day-of-year - The Minguo day-of-year exactly matches ISO.
+ * <li>leap-year - The Minguo leap-year pattern exactly matches ISO, such that the two calendars
+ *  are never out of step.
+ * </ul><p>
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class MinguoChrono extends Chrono<MinguoChrono> implements Serializable {
+
+    /**
+     * Singleton instance for the Minguo chronology.
+     */
+    public static final MinguoChrono INSTANCE = new MinguoChrono();
+
+    /**
+     * The singleton instance for the era ROC.
+     */
+    public static final Era<MinguoChrono> ERA_ROC = MinguoEra.ROC;
+
+    /**
+     * The singleton instance for the era BEFORE_ROC.
+     */
+    public static final Era<MinguoChrono> ERA_BEFORE_ROC = MinguoEra.BEFORE_ROC;
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 1039765215346859963L;
+    /**
+     * The difference in years between ISO and Minguo.
+     */
+    static final int YEARS_DIFFERENCE = 1911;
+
+    /**
+     * Restricted constructor.
+     */
+    private MinguoChrono() {
+    }
+
+    /**
+     * Resolve singleton.
+     *
+     * @return the singleton instance, not null
+     */
+    private Object readResolve() {
+        return INSTANCE;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the ID of the chronology - 'Minguo'.
+     * <p>
+     * The ID uniquely identifies the {@code Chrono}.
+     * It can be used to lookup the {@code Chrono} using {@link #of(String)}.
+     *
+     * @return the chronology ID - 'Minguo'
+     * @see #getCalendarType()
+     */
+    @Override
+    public String getId() {
+        return "Minguo";
+    }
+
+    /**
+     * Gets the calendar type of the underlying calendar system - 'roc'.
+     * <p>
+     * The calendar type is an identifier defined by the
+     * <em>Unicode Locale Data Markup Language (LDML)</em> specification.
+     * It can be used to lookup the {@code Chrono} using {@link #of(String)}.
+     * It can also be used as part of a locale, accessible via
+     * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
+     *
+     * @return the calendar system type - 'roc'
+     * @see #getId()
+     */
+    @Override
+    public String getCalendarType() {
+        return "roc";
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ChronoLocalDate<MinguoChrono> date(int prolepticYear, int month, int dayOfMonth) {
+        return new MinguoDate(LocalDate.of(prolepticYear + YEARS_DIFFERENCE, month, dayOfMonth));
+    }
+
+    @Override
+    public ChronoLocalDate<MinguoChrono> dateYearDay(int prolepticYear, int dayOfYear) {
+        return new MinguoDate(LocalDate.ofYearDay(prolepticYear + YEARS_DIFFERENCE, dayOfYear));
+    }
+
+    @Override
+    public ChronoLocalDate<MinguoChrono> date(TemporalAccessor temporal) {
+        if (temporal instanceof MinguoDate) {
+            return (MinguoDate) temporal;
+        }
+        return new MinguoDate(LocalDate.from(temporal));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified year is a leap year.
+     * <p>
+     * Minguo leap years occur exactly in line with ISO leap years.
+     * This method does not validate the year passed in, and only has a
+     * well-defined result for years in the supported range.
+     *
+     * @param prolepticYear  the proleptic-year to check, not validated for range
+     * @return true if the year is a leap year
+     */
+    @Override
+    public boolean isLeapYear(long prolepticYear) {
+        return ISOChrono.INSTANCE.isLeapYear(prolepticYear + YEARS_DIFFERENCE);
+    }
+
+    @Override
+    public int prolepticYear(Era<MinguoChrono> era, int yearOfEra) {
+        if (era instanceof MinguoEra == false) {
+            throw new DateTimeException("Era must be MinguoEra");
+        }
+        return (era == MinguoEra.ROC ? yearOfEra : 1 - yearOfEra);
+    }
+
+    @Override
+    public Era<MinguoChrono> eraOf(int eraValue) {
+        return MinguoEra.of(eraValue);
+    }
+
+    @Override
+    public List<Era<MinguoChrono>> eras() {
+        return Arrays.<Era<MinguoChrono>>asList(MinguoEra.values());
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ValueRange range(ChronoField field) {
+        switch (field) {
+            case YEAR_OF_ERA: {
+                ValueRange range = YEAR.range();
+                return ValueRange.of(1, range.getMaximum() - YEARS_DIFFERENCE, -range.getMinimum() + 1 + YEARS_DIFFERENCE);
+            }
+            case YEAR: {
+                ValueRange range = YEAR.range();
+                return ValueRange.of(range.getMinimum() - YEARS_DIFFERENCE, range.getMaximum() - YEARS_DIFFERENCE);
+            }
+        }
+        return field.range();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/calendar/MinguoDate.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.calendar;
+
+import static java.time.calendar.MinguoChrono.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;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.Serializable;
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoLocalDate;
+import java.time.temporal.TemporalField;
+import java.time.temporal.ValueRange;
+import java.util.Objects;
+
+/**
+ * A date in the Minguo calendar system.
+ * <p>
+ * This implements {@code ChronoLocalDate} for the {@link MinguoChrono Minguo calendar}.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+final class MinguoDate
+        extends ChronoDateImpl<MinguoChrono>
+        implements ChronoLocalDate<MinguoChrono>, Serializable {
+    // this class is package-scoped so that future conversion to public
+    // would not change serialization
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 1300372329181994526L;
+
+    /**
+     * The underlying date.
+     */
+    private final LocalDate isoDate;
+
+    /**
+     * Creates an instance from an ISO date.
+     *
+     * @param isoDate  the standard local date, validated not null
+     */
+    MinguoDate(LocalDate isoDate) {
+        Objects.requireNonNull(isoDate, "isoDate");
+        this.isoDate = isoDate;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public MinguoChrono getChrono() {
+        return MinguoChrono.INSTANCE;
+    }
+
+    @Override
+    public int lengthOfMonth() {
+        return isoDate.lengthOfMonth();
+    }
+
+    @Override
+    public ValueRange range(TemporalField field) {
+        if (field instanceof ChronoField) {
+            if (isSupported(field)) {
+                ChronoField f = (ChronoField) field;
+                switch (f) {
+                    case DAY_OF_MONTH:
+                    case DAY_OF_YEAR:
+                    case ALIGNED_WEEK_OF_MONTH:
+                        return isoDate.range(field);
+                    case YEAR_OF_ERA: {
+                        ValueRange range = YEAR.range();
+                        long max = (getProlepticYear() <= 0 ? -range.getMinimum() + 1 + YEARS_DIFFERENCE : range.getMaximum() - YEARS_DIFFERENCE);
+                        return ValueRange.of(1, max);
+                    }
+                }
+                return getChrono().range(f);
+            }
+            throw new DateTimeException("Unsupported field: " + field.getName());
+        }
+        return field.doRange(this);
+    }
+
+    @Override
+    public long getLong(TemporalField field) {
+        if (field instanceof ChronoField) {
+            switch ((ChronoField) field) {
+                case YEAR_OF_ERA: {
+                    int prolepticYear = getProlepticYear();
+                    return (prolepticYear >= 1 ? prolepticYear : 1 - prolepticYear);
+                }
+                case YEAR:
+                    return getProlepticYear();
+                case ERA:
+                    return (getProlepticYear() >= 1 ? 1 : 0);
+            }
+            return isoDate.getLong(field);
+        }
+        return field.doGet(this);
+    }
+
+    private int getProlepticYear() {
+        return isoDate.getYear() - YEARS_DIFFERENCE;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public MinguoDate with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            if (getLong(f) == newValue) {
+                return this;
+            }
+            switch (f) {
+                case YEAR_OF_ERA:
+                case YEAR:
+                case ERA: {
+                    f.checkValidValue(newValue);
+                    int nvalue = (int) newValue;
+                    switch (f) {
+                        case YEAR_OF_ERA:
+                            return with(isoDate.withYear(getProlepticYear() >= 1 ? nvalue + YEARS_DIFFERENCE : (1 - nvalue)  + YEARS_DIFFERENCE));
+                        case YEAR:
+                            return with(isoDate.withYear(nvalue + YEARS_DIFFERENCE));
+                        case ERA:
+                            return with(isoDate.withYear((1 - getProlepticYear()) + YEARS_DIFFERENCE));
+                    }
+                }
+            }
+            return with(isoDate.with(field, newValue));
+        }
+        return (MinguoDate) ChronoLocalDate.super.with(field, newValue);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    MinguoDate plusYears(long years) {
+        return with(isoDate.plusYears(years));
+    }
+
+    @Override
+    MinguoDate plusMonths(long months) {
+        return with(isoDate.plusMonths(months));
+    }
+
+    @Override
+    MinguoDate plusDays(long days) {
+        return with(isoDate.plusDays(days));
+    }
+
+    private MinguoDate with(LocalDate newDate) {
+        return (newDate.equals(isoDate) ? this : new MinguoDate(newDate));
+    }
+
+    @Override  // override for performance
+    public long toEpochDay() {
+        return isoDate.toEpochDay();
+    }
+
+    //-------------------------------------------------------------------------
+    @Override  // override for performance
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof MinguoDate) {
+            MinguoDate otherDate = (MinguoDate) obj;
+            return this.isoDate.equals(otherDate.isoDate);
+        }
+        return false;
+    }
+
+    @Override  // override for performance
+    public int hashCode() {
+        return getChrono().getId().hashCode() ^ isoDate.hashCode();
+    }
+
+    //-----------------------------------------------------------------------
+    private Object writeReplace() {
+        return new Ser(Ser.MINGUO_DATE_TYPE, this);
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        // MinguoChrono 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<MinguoChrono> readExternal(DataInput in) throws IOException {
+        int year = in.readInt();
+        int month = in.readByte();
+        int dayOfMonth = in.readByte();
+        return MinguoChrono.INSTANCE.date(year, month, dayOfMonth);
+    }
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/calendar/MinguoEra.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.calendar;
+
+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 Minguo calendar system.
+ * <p>
+ * The Minguo calendar system has two eras.
+ * The date {@code 0001-01-01 (Minguo)} is equal to {@code 1912-01-01 (ISO)}.
+ * <p>
+ * <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code MinguoEra}.
+ * Use {@code getValue()} instead.</b>
+ *
+ * <h3>Specification for implementors</h3>
+ * This is an immutable and thread-safe enum.
+ *
+ * @since 1.8
+ */
+enum MinguoEra implements Era<MinguoChrono>  {
+
+    /**
+     * The singleton instance for the era BEFORE_ROC, 'Before Republic of China'.
+     * This has the numeric value of {@code 0}.
+     */
+    BEFORE_ROC,
+    /**
+     * The singleton instance for the era ROC, 'Republic of China'.
+     * This has the numeric value of {@code 1}.
+     */
+    ROC;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code MinguoEra} from an {@code int} value.
+     * <p>
+     * {@code MinguoEra} is an enum representing the Minguo eras of BEFORE_ROC/ROC.
+     * This factory allows the enum to be obtained from the {@code int} value.
+     *
+     * @param era  the BEFORE_ROC/ROC value to represent, from 0 (BEFORE_ROC) to 1 (ROC)
+     * @return the era singleton, not null
+     * @throws DateTimeException if the value is invalid
+     */
+    public static MinguoEra of(int era) {
+        switch (era) {
+            case 0:
+                return BEFORE_ROC;
+            case 1:
+                return ROC;
+            default:
+                throw new DateTimeException("Invalid era: " + era);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the numeric era {@code int} value.
+     * <p>
+     * The era BEFORE_ROC has the value 0, while the era ROC has the value 1.
+     *
+     * @return the era value, from 0 (BEFORE_ROC) to 1 (ROC)
+     */
+    @Override
+    public int getValue() {
+        return ordinal();
+    }
+
+    @Override
+    public MinguoChrono getChrono() {
+        return MinguoChrono.INSTANCE;
+    }
+
+    // JDK8 default methods:
+    //-----------------------------------------------------------------------
+    @Override
+    public ChronoLocalDate<MinguoChrono> date(int year, int month, int day) {
+        return getChrono().date(this, year, month, day);
+    }
+
+    @Override
+    public ChronoLocalDate<MinguoChrono> 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);
+    }
+
+    //-----------------------------------------------------------------------
+    private Object writeReplace() {
+        return new Ser(Ser.MINGUO_ERA_TYPE, this);
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        out.writeByte(this.getValue());
+    }
+
+    static MinguoEra readExternal(DataInput in) throws IOException {
+        byte eraValue = in.readByte();
+        return MinguoEra.of(eraValue);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/calendar/Ser.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * 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.calendar;
+
+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.
+ *
+ * <h3>Implementation notes</h3>
+ * 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}.
+ * <p>
+ * 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.
+ * <p>
+ * 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.
+ * <p>
+ * 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 = 7857518227608961174L;
+
+    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;
+
+    /** 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 JAPANESE_DATE_TYPE:
+                ((JapaneseDate) object).writeExternal(out);
+                break;
+            case JAPANESE_ERA_TYPE:
+                ((JapaneseEra) object).writeExternal(out);
+                break;
+            case HIJRAH_DATE_TYPE:
+                ((HijrahDate) object).writeExternal(out);
+                break;
+            case HIJRAH_ERA_TYPE:
+                ((HijrahEra) object).writeExternal(out);
+                break;
+            case MINGUO_DATE_TYPE:
+                ((MinguoDate) object).writeExternal(out);
+                break;
+            case MINGUO_ERA_TYPE:
+                ((MinguoEra) object).writeExternal(out);
+                break;
+            case THAIBUDDHIST_DATE_TYPE:
+                ((ThaiBuddhistDate) object).writeExternal(out);
+                break;
+            case THAIBUDDHIST_ERA_TYPE:
+                ((ThaiBuddhistEra) 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 JAPANESE_DATE_TYPE:  return JapaneseDate.readExternal(in);
+            case JAPANESE_ERA_TYPE: return JapaneseEra.readExternal(in);
+            case HIJRAH_DATE_TYPE: return HijrahDate.readExternal(in);
+            case HIJRAH_ERA_TYPE: return HijrahEra.readExternal(in);
+            case MINGUO_DATE_TYPE: return MinguoDate.readExternal(in);
+            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");
+        }
+    }
+
+    /**
+     * Returns the object that will replace this one.
+     *
+     * @return the read object, should never be null
+     */
+    private Object readResolve() {
+         return object;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/calendar/ThaiBuddhistChrono.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.calendar;
+
+import static java.time.temporal.ChronoField.YEAR;
+
+import java.io.Serializable;
+import java.time.DateTimeException;
+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.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * The Thai Buddhist calendar system.
+ * <p>
+ * This chronology defines the rules of the Thai Buddhist calendar system.
+ * This calendar system is primarily used in Thailand.
+ * Dates are aligned such that {@code 2484-01-01 (Buddhist)} is {@code 1941-01-01 (ISO)}.
+ * <p>
+ * The fields are defined as follows:
+ * <p><ul>
+ * <li>era - There are two eras, the current 'Buddhist' (ERA_BE) and the previous era (ERA_BEFORE_BE).
+ * <li>year-of-era - The year-of-era for the current era increases uniformly from the epoch at year one.
+ *  For the previous era the year increases from one as time goes backwards.
+ *  The value for the current era is equal to the ISO proleptic-year plus 543.
+ * <li>proleptic-year - The proleptic year is the same as the year-of-era for the
+ *  current era. For the previous era, years have zero, then negative values.
+ *  The value is equal to the ISO proleptic-year plus 543.
+ * <li>month-of-year - The ThaiBuddhist month-of-year exactly matches ISO.
+ * <li>day-of-month - The ThaiBuddhist day-of-month exactly matches ISO.
+ * <li>day-of-year - The ThaiBuddhist day-of-year exactly matches ISO.
+ * <li>leap-year - The ThaiBuddhist leap-year pattern exactly matches ISO, such that the two calendars
+ *  are never out of step.
+ * </ul><p>
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class ThaiBuddhistChrono extends Chrono<ThaiBuddhistChrono> implements Serializable {
+
+    /**
+     * Singleton instance of the Buddhist chronology.
+     */
+    public static final ThaiBuddhistChrono INSTANCE = new ThaiBuddhistChrono();
+    /**
+     * The singleton instance for the era before the current one - Before Buddhist -
+     * which has the value 0.
+     */
+    public static final Era<ThaiBuddhistChrono> ERA_BEFORE_BE = ThaiBuddhistEra.BEFORE_BE;
+    /**
+     * The singleton instance for the current era - Buddhist - which has the value 1.
+     */
+    public static final Era<ThaiBuddhistChrono> ERA_BE = ThaiBuddhistEra.BE;
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 2775954514031616474L;
+    /**
+     * Containing the offset to add to the ISO year.
+     */
+    static final int YEARS_DIFFERENCE = 543;
+    /**
+     * Narrow names for eras.
+     */
+    private static final HashMap<String, String[]> ERA_NARROW_NAMES = new HashMap<>();
+    /**
+     * Short names for eras.
+     */
+    private static final HashMap<String, String[]> ERA_SHORT_NAMES = new HashMap<>();
+    /**
+     * Full names for eras.
+     */
+    private static final HashMap<String, String[]> ERA_FULL_NAMES = new HashMap<>();
+    /**
+     * Fallback language for the era names.
+     */
+    private static final String FALLBACK_LANGUAGE = "en";
+    /**
+     * Language that has the era names.
+     */
+    private static final String TARGET_LANGUAGE = "th";
+    /**
+     * Name data.
+     */
+    static {
+        ERA_NARROW_NAMES.put(FALLBACK_LANGUAGE, new String[]{"BB", "BE"});
+        ERA_NARROW_NAMES.put(TARGET_LANGUAGE, new String[]{"BB", "BE"});
+        ERA_SHORT_NAMES.put(FALLBACK_LANGUAGE, new String[]{"B.B.", "B.E."});
+        ERA_SHORT_NAMES.put(TARGET_LANGUAGE,
+                new String[]{"\u0e1e.\u0e28.",
+                "\u0e1b\u0e35\u0e01\u0e48\u0e2d\u0e19\u0e04\u0e23\u0e34\u0e2a\u0e15\u0e4c\u0e01\u0e32\u0e25\u0e17\u0e35\u0e48"});
+        ERA_FULL_NAMES.put(FALLBACK_LANGUAGE, new String[]{"Before Buddhist", "Budhhist Era"});
+        ERA_FULL_NAMES.put(TARGET_LANGUAGE,
+                new String[]{"\u0e1e\u0e38\u0e17\u0e18\u0e28\u0e31\u0e01\u0e23\u0e32\u0e0a",
+                "\u0e1b\u0e35\u0e01\u0e48\u0e2d\u0e19\u0e04\u0e23\u0e34\u0e2a\u0e15\u0e4c\u0e01\u0e32\u0e25\u0e17\u0e35\u0e48"});
+    }
+
+    /**
+     * Restricted constructor.
+     */
+    private ThaiBuddhistChrono() {
+    }
+
+    /**
+     * Resolve singleton.
+     *
+     * @return the singleton instance, not null
+     */
+    private Object readResolve() {
+        return INSTANCE;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the ID of the chronology - 'ThaiBuddhist'.
+     * <p>
+     * The ID uniquely identifies the {@code Chrono}.
+     * It can be used to lookup the {@code Chrono} using {@link #of(String)}.
+     *
+     * @return the chronology ID - 'ThaiBuddhist'
+     * @see #getCalendarType()
+     */
+    @Override
+    public String getId() {
+        return "ThaiBuddhist";
+    }
+
+    /**
+     * Gets the calendar type of the underlying calendar system - 'buddhist'.
+     * <p>
+     * The calendar type is an identifier defined by the
+     * <em>Unicode Locale Data Markup Language (LDML)</em> specification.
+     * It can be used to lookup the {@code Chrono} using {@link #of(String)}.
+     * It can also be used as part of a locale, accessible via
+     * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
+     *
+     * @return the calendar system type - 'buddhist'
+     * @see #getId()
+     */
+    @Override
+    public String getCalendarType() {
+        return "buddhist";
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ChronoLocalDate<ThaiBuddhistChrono> date(int prolepticYear, int month, int dayOfMonth) {
+        return new ThaiBuddhistDate(LocalDate.of(prolepticYear - YEARS_DIFFERENCE, month, dayOfMonth));
+    }
+
+    @Override
+    public ChronoLocalDate<ThaiBuddhistChrono> dateYearDay(int prolepticYear, int dayOfYear) {
+        return new ThaiBuddhistDate(LocalDate.ofYearDay(prolepticYear - YEARS_DIFFERENCE, dayOfYear));
+    }
+
+    @Override
+    public ChronoLocalDate<ThaiBuddhistChrono> date(TemporalAccessor temporal) {
+        if (temporal instanceof ThaiBuddhistDate) {
+            return (ThaiBuddhistDate) temporal;
+        }
+        return new ThaiBuddhistDate(LocalDate.from(temporal));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified year is a leap year.
+     * <p>
+     * Thai Buddhist leap years occur exactly in line with ISO leap years.
+     * This method does not validate the year passed in, and only has a
+     * well-defined result for years in the supported range.
+     *
+     * @param prolepticYear  the proleptic-year to check, not validated for range
+     * @return true if the year is a leap year
+     */
+    @Override
+    public boolean isLeapYear(long prolepticYear) {
+        return ISOChrono.INSTANCE.isLeapYear(prolepticYear - YEARS_DIFFERENCE);
+    }
+
+    @Override
+    public int prolepticYear(Era<ThaiBuddhistChrono> era, int yearOfEra) {
+        if (era instanceof ThaiBuddhistEra == false) {
+            throw new DateTimeException("Era must be BuddhistEra");
+        }
+        return (era == ThaiBuddhistEra.BE ? yearOfEra : 1 - yearOfEra);
+    }
+
+    @Override
+    public Era<ThaiBuddhistChrono> eraOf(int eraValue) {
+        return ThaiBuddhistEra.of(eraValue);
+    }
+
+    @Override
+    public List<Era<ThaiBuddhistChrono>> eras() {
+        return Arrays.<Era<ThaiBuddhistChrono>>asList(ThaiBuddhistEra.values());
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ValueRange range(ChronoField field) {
+        switch (field) {
+            case YEAR_OF_ERA: {
+                ValueRange range = YEAR.range();
+                return ValueRange.of(1, -(range.getMinimum() + YEARS_DIFFERENCE) + 1, range.getMaximum() + YEARS_DIFFERENCE);
+            }
+            case YEAR: {
+                ValueRange range = YEAR.range();
+                return ValueRange.of(range.getMinimum() + YEARS_DIFFERENCE, range.getMaximum() + YEARS_DIFFERENCE);
+            }
+        }
+        return field.range();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/calendar/ThaiBuddhistDate.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.calendar;
+
+import static java.time.calendar.ThaiBuddhistChrono.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;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.Serializable;
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoLocalDate;
+import java.time.temporal.TemporalField;
+import java.time.temporal.ValueRange;
+import java.util.Objects;
+
+/**
+ * A date in the Thai Buddhist calendar system.
+ * <p>
+ * This implements {@code ChronoLocalDate} for the {@link ThaiBuddhistChrono Thai Buddhist calendar}.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+final class ThaiBuddhistDate
+        extends ChronoDateImpl<ThaiBuddhistChrono>
+        implements ChronoLocalDate<ThaiBuddhistChrono>, Serializable {
+    // this class is package-scoped so that future conversion to public
+    // would not change serialization
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -8722293800195731463L;
+
+    /**
+     * The underlying date.
+     */
+    private final LocalDate isoDate;
+
+    /**
+     * Creates an instance from an ISO date.
+     *
+     * @param isoDate  the standard local date, validated not null
+     */
+    ThaiBuddhistDate(LocalDate isoDate) {
+        Objects.requireNonNull(isoDate, "isoDate");
+        this.isoDate = isoDate;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ThaiBuddhistChrono getChrono() {
+        return ThaiBuddhistChrono.INSTANCE;
+    }
+
+    @Override
+    public int lengthOfMonth() {
+        return isoDate.lengthOfMonth();
+    }
+
+    @Override
+    public ValueRange range(TemporalField field) {
+        if (field instanceof ChronoField) {
+            if (isSupported(field)) {
+                ChronoField f = (ChronoField) field;
+                switch (f) {
+                    case DAY_OF_MONTH:
+                    case DAY_OF_YEAR:
+                    case ALIGNED_WEEK_OF_MONTH:
+                        return isoDate.range(field);
+                    case YEAR_OF_ERA: {
+                        ValueRange range = YEAR.range();
+                        long max = (getProlepticYear() <= 0 ? -(range.getMinimum() + YEARS_DIFFERENCE) + 1 : range.getMaximum() + YEARS_DIFFERENCE);
+                        return ValueRange.of(1, max);
+                    }
+                }
+                return getChrono().range(f);
+            }
+            throw new DateTimeException("Unsupported field: " + field.getName());
+        }
+        return field.doRange(this);
+    }
+
+    @Override
+    public long getLong(TemporalField field) {
+        if (field instanceof ChronoField) {
+            switch ((ChronoField) field) {
+                case YEAR_OF_ERA: {
+                    int prolepticYear = getProlepticYear();
+                    return (prolepticYear >= 1 ? prolepticYear : 1 - prolepticYear);
+                }
+                case YEAR:
+                    return getProlepticYear();
+                case ERA:
+                    return (getProlepticYear() >= 1 ? 1 : 0);
+            }
+            return isoDate.getLong(field);
+        }
+        return field.doGet(this);
+    }
+
+    private int getProlepticYear() {
+        return isoDate.getYear() + YEARS_DIFFERENCE;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ThaiBuddhistDate with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            if (getLong(f) == newValue) {
+                return this;
+            }
+            switch (f) {
+                case YEAR_OF_ERA:
+                case YEAR:
+                case ERA: {
+                    f.checkValidValue(newValue);
+                    int nvalue = (int) newValue;
+                    switch (f) {
+                        case YEAR_OF_ERA:
+                            return with(isoDate.withYear((getProlepticYear() >= 1 ? nvalue : 1 - nvalue)  - YEARS_DIFFERENCE));
+                        case YEAR:
+                            return with(isoDate.withYear(nvalue - YEARS_DIFFERENCE));
+                        case ERA:
+                            return with(isoDate.withYear((1 - getProlepticYear()) - YEARS_DIFFERENCE));
+                    }
+                }
+            }
+            return with(isoDate.with(field, newValue));
+        }
+        return (ThaiBuddhistDate) ChronoLocalDate.super.with(field, newValue);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    ThaiBuddhistDate plusYears(long years) {
+        return with(isoDate.plusYears(years));
+    }
+
+    @Override
+    ThaiBuddhistDate plusMonths(long months) {
+        return with(isoDate.plusMonths(months));
+    }
+
+    @Override
+    ThaiBuddhistDate plusDays(long days) {
+        return with(isoDate.plusDays(days));
+    }
+
+    private ThaiBuddhistDate with(LocalDate newDate) {
+        return (newDate.equals(isoDate) ? this : new ThaiBuddhistDate(newDate));
+    }
+
+    @Override  // override for performance
+    public long toEpochDay() {
+        return isoDate.toEpochDay();
+    }
+
+    //-------------------------------------------------------------------------
+    @Override  // override for performance
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof ThaiBuddhistDate) {
+            ThaiBuddhistDate otherDate = (ThaiBuddhistDate) obj;
+            return this.isoDate.equals(otherDate.isoDate);
+        }
+        return false;
+    }
+
+    @Override  // override for performance
+    public int hashCode() {
+        return getChrono().getId().hashCode() ^ isoDate.hashCode();
+    }
+
+    //-----------------------------------------------------------------------
+    private Object writeReplace() {
+        return new Ser(Ser.THAIBUDDHIST_DATE_TYPE, this);
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        // MinguoChrono 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<ThaiBuddhistChrono> readExternal(DataInput in) throws IOException {
+        int year = in.readInt();
+        int month = in.readByte();
+        int dayOfMonth = in.readByte();
+        return ThaiBuddhistChrono.INSTANCE.date(year, month, dayOfMonth);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/calendar/ThaiBuddhistEra.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.calendar;
+
+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.
+ * <p>
+ * The Thai Buddhist calendar system has two eras.
+ * <p>
+ * <b>Do not use ordinal() to obtain the numeric representation of a ThaiBuddhistEra
+ * instance. Use getValue() instead.</b>
+ *
+ * <h3>Specification for implementors</h3>
+ * This is an immutable and thread-safe enum.
+ *
+ * @since 1.8
+ */
+enum ThaiBuddhistEra implements Era<ThaiBuddhistChrono> {
+
+    /**
+     * The singleton instance for the era before the current one, 'Before Buddhist Era',
+     * which has the value 0.
+     */
+    BEFORE_BE,
+    /**
+     * The singleton instance for the current era, 'Buddhist Era', which has the value 1.
+     */
+    BE;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ThaiBuddhistEra} from a value.
+     * <p>
+     * The current era (from ISO year -543 onwards) has the value 1
+     * The previous era has the value 0.
+     *
+     * @param thaiBuddhistEra  the era to represent, from 0 to 1
+     * @return the BuddhistEra singleton, never null
+     * @throws IllegalCalendarFieldValueException if the era is invalid
+     */
+    public static ThaiBuddhistEra of(int thaiBuddhistEra) {
+        switch (thaiBuddhistEra) {
+            case 0:
+                return BEFORE_BE;
+            case 1:
+                return BE;
+            default:
+                throw new DateTimeException("Era is not valid for ThaiBuddhistEra");
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the era numeric value.
+     * <p>
+     * The current era (from ISO year -543 onwards) has the value 1
+     * The previous era has the value 0.
+     *
+     * @return the era value, from 0 (BEFORE_BE) to 1 (BE)
+     */
+    @Override
+    public int getValue() {
+        return ordinal();
+    }
+
+    @Override
+    public ThaiBuddhistChrono getChrono() {
+        return ThaiBuddhistChrono.INSTANCE;
+    }
+
+    // JDK8 default methods:
+    //-----------------------------------------------------------------------
+    @Override
+    public ChronoLocalDate<ThaiBuddhistChrono> date(int year, int month, int day) {
+        return getChrono().date(this, year, month, day);
+    }
+
+    @Override
+    public ChronoLocalDate<ThaiBuddhistChrono> 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);
+    }
+
+    //-----------------------------------------------------------------------
+    private Object writeReplace() {
+        return new Ser(Ser.THAIBUDDHIST_ERA_TYPE, this);
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        out.writeByte(this.getValue());
+    }
+
+    static ThaiBuddhistEra readExternal(DataInput in) throws IOException {
+        byte eraValue = in.readByte();
+        return ThaiBuddhistEra.of(eraValue);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/calendar/package-info.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * 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.
+ */
+
+/**
+ * <p>
+ * Support for calendar systems other than the default ISO.
+ * </p>
+ * <p>
+ * The main API is based around the calendar system defined in ISO-8601.
+ * This package provides support for alternate systems.
+ * </p>
+ * <p>
+ * The supported calendar systems includes:
+ * </p>
+ * <ul>
+ * <li>{@link java.time.calendar.HijrahChrono Hijrah calendar}</li>
+ * <li>{@link java.time.calendar.JapaneseChrono Japanese calendar}</li>
+ * <li>{@link java.time.calendar.MinguoChrono Minguo calendar}</li>
+ * <li>{@link java.time.calendar.ThaiBuddhistChrono Thai Buddhist calendar}</li>
+ * </ul>
+ * <p>
+ * 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.
+ * This package is then used at the user interface level to deal with
+ * localized input/output.
+ * See {@link java.time.temporal.ChronoLocalDate ChronoLocalDate}
+ * for a full discussion of the issues.
+ * </p>
+ *
+ * <h3>Example</h3>
+ * <p>
+ * This example creates and uses a date in a non-ISO calendar system.
+ * </p>
+ * <pre>
+ *   // Print the Thai Buddhist date
+ *       ChronoLocalDate&lt;ThaiBuddhistChrono&gt; 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&lt;Chrono&lt;?&gt;&gt; chronos = Chrono.getAvailableChronologies();
+ *       for (Chrono&lt;?&gt; chrono : chronos) {
+ *         ChronoLocalDate&lt;?&gt; 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&lt;ThaiBuddhistChrono&gt; first = now1
+ *                 .with(ChronoField.DAY_OF_MONTH, 1)
+ *                 .with(ChronoField.MONTH_OF_YEAR, 1);
+ *       ChronoLocalDate&lt;ThaiBuddhistChrono&gt; 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);
+ *  </pre>
+ *
+ * <h3>Package specification</h3>
+ * <p>
+ * 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.
+ * </p>
+ * <p>
+ * All calculations should check for numeric overflow and throw either an {@link java.lang.ArithmeticException}
+ * or a {@link java.time.DateTimeException}.
+ * </p>
+ * @since JDK1.8
+ */
+package java.time.calendar;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/format/DateTimeBuilder.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,719 @@
+/*
+ * 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.format;
+
+import static java.time.temporal.Adjusters.nextOrSame;
+import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH;
+import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR;
+import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH;
+import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR;
+import static java.time.temporal.ChronoField.AMPM_OF_DAY;
+import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_AMPM;
+import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_DAY;
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.DAY_OF_WEEK;
+import static java.time.temporal.ChronoField.DAY_OF_YEAR;
+import static java.time.temporal.ChronoField.EPOCH_DAY;
+import static java.time.temporal.ChronoField.EPOCH_MONTH;
+import static java.time.temporal.ChronoField.HOUR_OF_AMPM;
+import static java.time.temporal.ChronoField.HOUR_OF_DAY;
+import static java.time.temporal.ChronoField.INSTANT_SECONDS;
+import static java.time.temporal.ChronoField.MICRO_OF_DAY;
+import static java.time.temporal.ChronoField.MICRO_OF_SECOND;
+import static java.time.temporal.ChronoField.MILLI_OF_DAY;
+import static java.time.temporal.ChronoField.MILLI_OF_SECOND;
+import static java.time.temporal.ChronoField.MINUTE_OF_DAY;
+import static java.time.temporal.ChronoField.MINUTE_OF_HOUR;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.NANO_OF_DAY;
+import static java.time.temporal.ChronoField.NANO_OF_SECOND;
+import static java.time.temporal.ChronoField.OFFSET_SECONDS;
+import static java.time.temporal.ChronoField.SECOND_OF_DAY;
+import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
+import static java.time.temporal.ChronoField.YEAR;
+
+import 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.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.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.
+ * <p>
+ * <b>This class still needs major revision before JDK1.8 ships.</b>
+ * <p>
+ * The builder is used to hold onto different elements of date and time.
+ * It is designed as two separate maps:
+ * <p><ul>
+ * <li>from {@link java.time.temporal.TemporalField} to {@code long} value, where the value may be
+ * outside the valid range for the field
+ * <li>from {@code Class} to {@link java.time.temporal.TemporalAccessor}, holding larger scale objects
+ * like {@code LocalDateTime}.
+ * </ul><p>
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is mutable and not thread-safe.
+ * It should only be used from a single thread.
+ *
+ * @since 1.8
+ */
+public final class DateTimeBuilder
+        implements TemporalAccessor, Cloneable {
+
+    /**
+     * The map of other fields.
+     */
+    private Map<TemporalField, Long> otherFields;
+    /**
+     * The map of date-time fields.
+     */
+    private final EnumMap<ChronoField, Long> standardFields = new EnumMap<ChronoField, Long>(ChronoField.class);
+    /**
+     * The list of complete date-time objects.
+     */
+    private final List<Object> objects = new ArrayList<>(2);
+
+    //-----------------------------------------------------------------------
+    /**
+     * Creates an empty instance of the builder.
+     */
+    public DateTimeBuilder() {
+    }
+
+    /**
+     * Creates a new instance of the builder with a single field-value.
+     * <p>
+     * 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<TemporalField, Long> getFieldValueMap() {
+        Map<TemporalField, Long> map = new HashMap<TemporalField, Long>(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);
+        } else if (otherFields != null) {
+            return otherFields.get(field);
+        }
+        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.
+     * <p>
+     * This adds a field to the builder.
+     * If the field is not already present, then the field-value pair is added to the map.
+     * If the field is already present and it has the same value as that specified, no action occurs.
+     * If the field is already present and it has a different value to that specified, then
+     * an exception is thrown.
+     *
+     * @param field  the field to add, not null
+     * @param value  the value to add, not null
+     * @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) {
+        Objects.requireNonNull(field, "field");
+        Long old = getFieldValue0(field);  // check first for better error message
+        if (old != null && old.longValue() != value) {
+            throw new DateTimeException("Conflict found: " + field + " " + old + " differs from " + field + " " + value + ": " + this);
+        }
+        return putFieldValue0(field, value);
+    }
+
+    private DateTimeBuilder putFieldValue0(TemporalField field, long value) {
+        if (field instanceof ChronoField) {
+            standardFields.put((ChronoField) field, value);
+        } else {
+            if (otherFields == null) {
+                otherFields = new LinkedHashMap<TemporalField, Long>();
+            }
+            otherFields.put(field, value);
+        }
+        return this;
+    }
+
+    /**
+     * Removes a field-value pair from the builder.
+     * <p>
+     * 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.
+     * <p>
+     * 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);
+            }
+        }
+    }
+
+    /**
+     * Queries a list of fields from the builder.
+     * <p>
+     * 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;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the list of date-time objects in the builder.
+     * <p>
+     * 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<Object> getCalendricalList() {
+        return objects;
+    }
+
+    /**
+     * Adds a date-time object to the builder.
+     * <p>
+     * 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;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Resolves the builder, evaluating the date and time.
+     * <p>
+     * This examines the contents of the builder and resolves it to produce the best
+     * available date and time, throwing an exception if a problem occurs.
+     * Calling this method changes the state of the builder.
+     *
+     * @return {@code this}, for method chaining
+     */
+    public DateTimeBuilder resolve() {
+        splitObjects();
+        // handle unusual fields
+        if (otherFields != null) {
+            outer:
+            while (true) {
+                Set<Entry<TemporalField, Long>> entrySet = new HashSet<>(otherFields.entrySet());
+                for (Entry<TemporalField, Long> entry : entrySet) {
+                    if (entry.getKey().resolve(this, entry.getValue())) {
+                        continue outer;
+                    }
+                }
+                break;
+            }
+        }
+        // handle standard fields
+        mergeDate();
+        mergeTime();
+        // TODO: cross validate remaining fields?
+        return this;
+    }
+
+    private void mergeDate() {
+        if (standardFields.containsKey(EPOCH_DAY)) {
+            checkDate(LocalDate.ofEpochDay(standardFields.remove(EPOCH_DAY)));
+            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);
+        }
+
+        // build date
+        if (standardFields.containsKey(YEAR)) {
+            if (standardFields.containsKey(MONTH_OF_YEAR)) {
+                if (standardFields.containsKey(DAY_OF_MONTH)) {
+                    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));
+                    return;
+                }
+                if (standardFields.containsKey(ALIGNED_WEEK_OF_MONTH)) {
+                    if (standardFields.containsKey(ALIGNED_DAY_OF_WEEK_IN_MONTH)) {
+                        int y = Math.toIntExact(standardFields.remove(YEAR));
+                        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)));
+                        return;
+                    }
+                    if (standardFields.containsKey(DAY_OF_WEEK)) {
+                        int y = Math.toIntExact(standardFields.remove(YEAR));
+                        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))));
+                        return;
+                    }
+                }
+            }
+            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));
+                return;
+            }
+            if (standardFields.containsKey(ALIGNED_WEEK_OF_YEAR)) {
+                if (standardFields.containsKey(ALIGNED_DAY_OF_WEEK_IN_YEAR)) {
+                    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)));
+                    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))));
+                    return;
+                }
+            }
+        }
+    }
+
+    private void checkDate(LocalDate date) {
+        // TODO: this doesn't handle aligned weeks over into next month which would otherwise be valid
+
+        addCalendrical(date);
+        for (ChronoField field : standardFields.keySet()) {
+            long val1;
+            try {
+                val1 = date.getLong(field);
+            } catch (DateTimeException ex) {
+                continue;
+            }
+            Long val2 = standardFields.get(field);
+            if (val1 != val2) {
+                throw new DateTimeException("Conflict found: Field " + field + " " + val1 + " differs from " + field + " " + val2 + " derived from " + date);
+            }
+        }
+    }
+
+    private void mergeTime() {
+        if (standardFields.containsKey(CLOCK_HOUR_OF_DAY)) {
+            long ch = standardFields.remove(CLOCK_HOUR_OF_DAY);
+            addFieldValue(HOUR_OF_DAY, ch == 24 ? 0 : ch);
+        }
+        if (standardFields.containsKey(CLOCK_HOUR_OF_AMPM)) {
+            long ch = standardFields.remove(CLOCK_HOUR_OF_AMPM);
+            addFieldValue(HOUR_OF_AMPM, ch == 12 ? 0 : ch);
+        }
+        if (standardFields.containsKey(AMPM_OF_DAY) && standardFields.containsKey(HOUR_OF_AMPM)) {
+            long ap = standardFields.remove(AMPM_OF_DAY);
+            long hap = standardFields.remove(HOUR_OF_AMPM);
+            addFieldValue(HOUR_OF_DAY, ap * 12 + hap);
+        }
+//        if (timeFields.containsKey(HOUR_OF_DAY) && timeFields.containsKey(MINUTE_OF_HOUR)) {
+//            long hod = timeFields.remove(HOUR_OF_DAY);
+//            long moh = timeFields.remove(MINUTE_OF_HOUR);
+//            addFieldValue(MINUTE_OF_DAY, hod * 60 + moh);
+//        }
+//        if (timeFields.containsKey(MINUTE_OF_DAY) && timeFields.containsKey(SECOND_OF_MINUTE)) {
+//            long mod = timeFields.remove(MINUTE_OF_DAY);
+//            long som = timeFields.remove(SECOND_OF_MINUTE);
+//            addFieldValue(SECOND_OF_DAY, mod * 60 + som);
+//        }
+        if (standardFields.containsKey(NANO_OF_DAY)) {
+            long nod = standardFields.remove(NANO_OF_DAY);
+            addFieldValue(SECOND_OF_DAY, nod / 1000_000_000L);
+            addFieldValue(NANO_OF_SECOND, nod % 1000_000_000L);
+        }
+        if (standardFields.containsKey(MICRO_OF_DAY)) {
+            long cod = standardFields.remove(MICRO_OF_DAY);
+            addFieldValue(SECOND_OF_DAY, cod / 1000_000L);
+            addFieldValue(MICRO_OF_SECOND, cod % 1000_000L);
+        }
+        if (standardFields.containsKey(MILLI_OF_DAY)) {
+            long lod = standardFields.remove(MILLI_OF_DAY);
+            addFieldValue(SECOND_OF_DAY, lod / 1000);
+            addFieldValue(MILLI_OF_SECOND, lod % 1000);
+        }
+        if (standardFields.containsKey(SECOND_OF_DAY)) {
+            long sod = standardFields.remove(SECOND_OF_DAY);
+            addFieldValue(HOUR_OF_DAY, sod / 3600);
+            addFieldValue(MINUTE_OF_HOUR, (sod / 60) % 60);
+            addFieldValue(SECOND_OF_MINUTE, sod % 60);
+        }
+        if (standardFields.containsKey(MINUTE_OF_DAY)) {
+            long mod = standardFields.remove(MINUTE_OF_DAY);
+            addFieldValue(HOUR_OF_DAY, mod / 60);
+            addFieldValue(MINUTE_OF_HOUR, mod % 60);
+        }
+
+//            long sod = nod / 1000_000_000L;
+//            addFieldValue(HOUR_OF_DAY, sod / 3600);
+//            addFieldValue(MINUTE_OF_HOUR, (sod / 60) % 60);
+//            addFieldValue(SECOND_OF_MINUTE, sod % 60);
+//            addFieldValue(NANO_OF_SECOND, nod % 1000_000_000L);
+        if (standardFields.containsKey(MILLI_OF_SECOND) && standardFields.containsKey(MICRO_OF_SECOND)) {
+            long los = standardFields.remove(MILLI_OF_SECOND);
+            long cos = standardFields.get(MICRO_OF_SECOND);
+            addFieldValue(MICRO_OF_SECOND, los * 1000 + (cos % 1000));
+        }
+
+        Long hod = standardFields.get(HOUR_OF_DAY);
+        Long moh = standardFields.get(MINUTE_OF_HOUR);
+        Long som = standardFields.get(SECOND_OF_MINUTE);
+        Long nos = standardFields.get(NANO_OF_SECOND);
+        if (hod != null) {
+            int hodVal = Math.toIntExact(hod);
+            if (moh != null) {
+                int mohVal = Math.toIntExact(moh);
+                if (som != null) {
+                    int somVal = Math.toIntExact(som);
+                    if (nos != null) {
+                        int nosVal = Math.toIntExact(nos);
+                        addCalendrical(LocalTime.of(hodVal, mohVal, somVal, nosVal));
+                    } else {
+                        addCalendrical(LocalTime.of(hodVal, mohVal, somVal));
+                    }
+                } else {
+                    addCalendrical(LocalTime.of(hodVal, mohVal));
+                }
+            } else {
+                addCalendrical(LocalTime.of(hodVal, 0));
+            }
+        }
+    }
+
+    private void splitObjects() {
+        List<Object> 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);
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public <R> R query(TemporalQuery<R> query) {
+        if (query == Queries.zoneId()) {
+            return (R) extract(ZoneId.class);
+        }
+        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 (R) offset;
+        }
+        if (query == Queries.chrono()) {
+            return extract(Chrono.class);
+        }
+        // incomplete, so no need to handle PRECISION
+        return TemporalAccessor.super.query(query);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <R> 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);
+        }
+        return dtb;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder(128);
+        buf.append("DateTimeBuilder[");
+        Map<TemporalField, Long> fields = getFieldValueMap();
+        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(']');
+        return buf.toString();
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public boolean isSupported(TemporalField field) {
+        return field != null && containsFieldValue(field);
+    }
+
+    @Override
+    public long getLong(TemporalField field) {
+        return getFieldValue(field);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/format/DateTimeFormatStyleProvider.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.format;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.time.temporal.Chrono;
+import java.util.Locale;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * A provider to obtain date-time formatters for a style.
+ * <p>
+ *
+ * <h3>Specification for implementors</h3>
+ * This implementation is based on extraction of data from a {@link SimpleDateFormat}.
+ * This class is immutable and thread-safe.
+ * This Implementations caches the returned formatters.
+ *
+ * @since 1.8
+ */
+final class DateTimeFormatStyleProvider {
+    // TODO: Better implementation based on CLDR
+
+    /** Cache of formatters. */
+    private static final ConcurrentMap<String, Object> FORMATTER_CACHE = new ConcurrentHashMap<>(16, 0.75f, 2);
+
+    private DateTimeFormatStyleProvider() {}
+
+    /**
+     * Gets an Instance of the provider of format styles.
+     *
+     * @return the provider, not null
+     */
+    static DateTimeFormatStyleProvider getInstance() {
+        return new DateTimeFormatStyleProvider();
+    }
+
+    /**
+     * Gets a localized date, time or date-time formatter.
+     * <p>
+     * The formatter will be the most appropriate to use for the date and time style in the locale.
+     * For example, some locales will use the month name while others will use the number.
+     *
+     * @param dateStyle  the date formatter style to obtain, null to obtain a time formatter
+     * @param timeStyle  the time formatter style to obtain, null to obtain a date formatter
+     * @param chrono  the chronology to use, not null
+     * @param locale  the locale to use, not null
+     * @return the date-time formatter, not null
+     * @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) {
+        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");
+    }
+
+    /**
+     * Converts the enum style to the old format style.
+     * @param style  the enum style, not null
+     * @return the int style
+     */
+    private int convertStyle(FormatStyle style) {
+        return style.ordinal();  // indices happen to align
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/format/DateTimeFormatSymbols.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,369 @@
+/*
+ * 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.text.DecimalFormatSymbols;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * Localized symbols used in date and time formatting.
+ * <p>
+ * A significant part of dealing with dates and times is the localization.
+ * This class acts as a central point for accessing the information.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class DateTimeFormatSymbols {
+
+    /**
+     * The standard set of non-localized symbols.
+     * <p>
+     * This uses standard ASCII characters for zero, positive, negative and a dot for the decimal point.
+     */
+    public static final DateTimeFormatSymbols STANDARD = new DateTimeFormatSymbols('0', '+', '-', '.');
+    /**
+     * The cache of symbols instances.
+     */
+    private static final ConcurrentMap<Locale, DateTimeFormatSymbols> CACHE = new ConcurrentHashMap<>(16, 0.75f, 2);
+
+    /**
+     * The zero digit.
+     */
+    private final char zeroDigit;
+    /**
+     * The positive sign.
+     */
+    private final char positiveSign;
+    /**
+     * The negative sign.
+     */
+    private final char negativeSign;
+    /**
+     * The decimal separator.
+     */
+    private final char decimalSeparator;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Lists all the locales that are supported.
+     * <p>
+     * The locale 'en_US' will always be present.
+     *
+     * @return an array of locales for which localization is supported
+     */
+    public static Locale[] getAvailableLocales() {
+        return DecimalFormatSymbols.getAvailableLocales();
+    }
+
+    /**
+     * Obtains symbols for the default locale.
+     * <p>
+     * This method provides access to locale sensitive symbols.
+     *
+     * @return the info, not null
+     */
+    public static DateTimeFormatSymbols ofDefaultLocale() {
+        return of(Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Obtains symbols for the specified locale.
+     * <p>
+     * This method provides access to locale sensitive symbols.
+     *
+     * @param locale  the locale, not null
+     * @return the info, not null
+     */
+    public static DateTimeFormatSymbols of(Locale locale) {
+        Objects.requireNonNull(locale, "locale");
+        DateTimeFormatSymbols info = CACHE.get(locale);
+        if (info == null) {
+            info = create(locale);
+            CACHE.putIfAbsent(locale, info);
+            info = CACHE.get(locale);
+        }
+        return info;
+    }
+
+    private static DateTimeFormatSymbols create(Locale locale) {
+        DecimalFormatSymbols oldSymbols = DecimalFormatSymbols.getInstance(locale);
+        char zeroDigit = oldSymbols.getZeroDigit();
+        char positiveSign = '+';
+        char negativeSign = oldSymbols.getMinusSign();
+        char decimalSeparator = oldSymbols.getDecimalSeparator();
+        if (zeroDigit == '0' && negativeSign == '-' && decimalSeparator == '.') {
+            return STANDARD;
+        }
+        return new DateTimeFormatSymbols(zeroDigit, positiveSign, negativeSign, decimalSeparator);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Restricted constructor.
+     *
+     * @param zeroChar  the character to use for the digit of zero
+     * @param positiveSignChar  the character to use for the positive sign
+     * @param negativeSignChar  the character to use for the negative sign
+     * @param decimalPointChar  the character to use for the decimal point
+     */
+    private DateTimeFormatSymbols(char zeroChar, char positiveSignChar, char negativeSignChar, char decimalPointChar) {
+        this.zeroDigit = zeroChar;
+        this.positiveSign = positiveSignChar;
+        this.negativeSign = negativeSignChar;
+        this.decimalSeparator = decimalPointChar;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the character that represents zero.
+     * <p>
+     * The character used to represent digits may vary by culture.
+     * This method specifies the zero character to use, which implies the characters for one to nine.
+     *
+     * @return the character for zero
+     */
+    public char getZeroDigit() {
+        return zeroDigit;
+    }
+
+    /**
+     * Returns a copy of the info with a new character that represents zero.
+     * <p>
+     * The character used to represent digits may vary by culture.
+     * This method specifies the zero character to use, which implies the characters for one to nine.
+     *
+     * @param zeroDigit  the character for zero
+     * @return  a copy with a new character that represents zero, not null
+
+     */
+    public DateTimeFormatSymbols withZeroDigit(char zeroDigit) {
+        if (zeroDigit == this.zeroDigit) {
+            return this;
+        }
+        return new DateTimeFormatSymbols(zeroDigit, positiveSign, negativeSign, decimalSeparator);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the character that represents the positive sign.
+     * <p>
+     * The character used to represent a positive number may vary by culture.
+     * This method specifies the character to use.
+     *
+     * @return the character for the positive sign
+     */
+    public char getPositiveSign() {
+        return positiveSign;
+    }
+
+    /**
+     * Returns a copy of the info with a new character that represents the positive sign.
+     * <p>
+     * The character used to represent a positive number may vary by culture.
+     * This method specifies the character to use.
+     *
+     * @param positiveSign  the character for the positive sign
+     * @return  a copy with a new character that represents the positive sign, not null
+     */
+    public DateTimeFormatSymbols withPositiveSign(char positiveSign) {
+        if (positiveSign == this.positiveSign) {
+            return this;
+        }
+        return new DateTimeFormatSymbols(zeroDigit, positiveSign, negativeSign, decimalSeparator);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the character that represents the negative sign.
+     * <p>
+     * The character used to represent a negative number may vary by culture.
+     * This method specifies the character to use.
+     *
+     * @return the character for the negative sign
+     */
+    public char getNegativeSign() {
+        return negativeSign;
+    }
+
+    /**
+     * Returns a copy of the info with a new character that represents the negative sign.
+     * <p>
+     * The character used to represent a negative number may vary by culture.
+     * This method specifies the character to use.
+     *
+     * @param negativeSign  the character for the negative sign
+     * @return  a copy with a new character that represents the negative sign, not null
+     */
+    public DateTimeFormatSymbols withNegativeSign(char negativeSign) {
+        if (negativeSign == this.negativeSign) {
+            return this;
+        }
+        return new DateTimeFormatSymbols(zeroDigit, positiveSign, negativeSign, decimalSeparator);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the character that represents the decimal point.
+     * <p>
+     * The character used to represent a decimal point may vary by culture.
+     * This method specifies the character to use.
+     *
+     * @return the character for the decimal point
+     */
+    public char getDecimalSeparator() {
+        return decimalSeparator;
+    }
+
+    /**
+     * Returns a copy of the info with a new character that represents the decimal point.
+     * <p>
+     * The character used to represent a decimal point may vary by culture.
+     * This method specifies the character to use.
+     *
+     * @param decimalSeparator  the character for the decimal point
+     * @return  a copy with a new character that represents the decimal point, not null
+     */
+    public DateTimeFormatSymbols withDecimalSeparator(char decimalSeparator) {
+        if (decimalSeparator == this.decimalSeparator) {
+            return this;
+        }
+        return new DateTimeFormatSymbols(zeroDigit, positiveSign, negativeSign, decimalSeparator);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks whether the character is a digit, based on the currently set zero character.
+     *
+     * @param ch  the character to check
+     * @return the value, 0 to 9, of the character, or -1 if not a digit
+     */
+    int convertToDigit(char ch) {
+        int val = ch - zeroDigit;
+        return (val >= 0 && val <= 9) ? val : -1;
+    }
+
+    /**
+     * Converts the input numeric text to the internationalized form using the zero character.
+     *
+     * @param numericText  the text, consisting of digits 0 to 9, to convert, not null
+     * @return the internationalized text, not null
+     */
+    String convertNumberToI18N(String numericText) {
+        if (zeroDigit == '0') {
+            return numericText;
+        }
+        int diff = zeroDigit - '0';
+        char[] array = numericText.toCharArray();
+        for (int i = 0; i < array.length; i++) {
+            array[i] = (char) (array[i] + diff);
+        }
+        return new String(array);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if these symbols equal another set of symbols.
+     *
+     * @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 DateTimeFormatSymbols) {
+            DateTimeFormatSymbols other = (DateTimeFormatSymbols) obj;
+            return (zeroDigit == other.zeroDigit && positiveSign == other.positiveSign &&
+                    negativeSign == other.negativeSign && decimalSeparator == other.decimalSeparator);
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for these symbols.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return zeroDigit + positiveSign + negativeSign + decimalSeparator;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a string describing these symbols.
+     *
+     * @return a string description, not null
+     */
+    @Override
+    public String toString() {
+        return "Symbols[" + zeroDigit + positiveSign + negativeSign + decimalSeparator + "]";
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/format/DateTimeFormatter.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,655 @@
+/*
+ * 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.text.FieldPosition;
+import java.text.Format;
+import java.text.ParseException;
+import java.text.ParsePosition;
+import java.time.DateTimeException;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatterBuilder.CompositePrinterParser;
+import java.time.temporal.Chrono;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalQuery;
+import java.util.Locale;
+import java.util.Objects;
+
+/**
+ * Formatter for printing and parsing date-time objects.
+ * <p>
+ * 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.
+ * <p>
+ * In most cases, it is not necessary to use this class directly when formatting.
+ * 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)}.
+ * For example:
+ * <pre>
+ *  String text = date.toString(formatter);
+ *  LocalDate date = LocalDate.parse(text, formatter);
+ * </pre>
+ * Some aspects of printing 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.
+ * <p>
+ * Some applications may need to use the older {@link Format} class for formatting.
+ * The {@link #toFormat()} method returns an implementation of the old API.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class DateTimeFormatter {
+
+    /**
+     * The printer and/or parser to use, not null.
+     */
+    private final CompositePrinterParser printerParser;
+    /**
+     * The locale to use for formatting, not null.
+     */
+    private final Locale locale;
+    /**
+     * The symbols to use for formatting, not null.
+     */
+    private final DateTimeFormatSymbols symbols;
+    /**
+     * The chronology to use for formatting, null for no override.
+     */
+    private final Chrono<?> chrono;
+    /**
+     * The zone to use for formatting, null for no override.
+     */
+    private final ZoneId zone;
+
+    /**
+     * Constructor.
+     *
+     * @param printerParser  the printer/parser to use, not null
+     * @param locale  the locale to use, not null
+     * @param symbols  the symbols to use, not null
+     * @param chrono  the chronology to use, null for no override
+     * @param zone  the zone to use, null for no override
+     */
+    DateTimeFormatter(CompositePrinterParser printerParser, Locale locale,
+                      DateTimeFormatSymbols symbols, Chrono chrono, ZoneId zone) {
+        this.printerParser = Objects.requireNonNull(printerParser, "printerParser");
+        this.locale = Objects.requireNonNull(locale, "locale");
+        this.symbols = Objects.requireNonNull(symbols, "symbols");
+        this.chrono = chrono;
+        this.zone = zone;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the locale to be used during formatting.
+     * <p>
+     * This is used to lookup any part of the formatter needing specific
+     * localization, such as the text or localized pattern.
+     *
+     * @return the locale of this formatter, not null
+     */
+    public Locale getLocale() {
+        return locale;
+    }
+
+    /**
+     * Returns a copy of this formatter with a new locale.
+     * <p>
+     * This is used to lookup any part of the formatter needing specific
+     * localization, such as the text or localized pattern.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param locale  the new locale, not null
+     * @return a formatter based on this formatter with the requested locale, not null
+     */
+    public DateTimeFormatter withLocale(Locale locale) {
+        if (this.locale.equals(locale)) {
+            return this;
+        }
+        return new DateTimeFormatter(printerParser, locale, symbols, chrono, zone);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the set of symbols to be used during formatting.
+     *
+     * @return the locale of this formatter, not null
+     */
+    public DateTimeFormatSymbols getSymbols() {
+        return symbols;
+    }
+
+    /**
+     * Returns a copy of this formatter with a new set of symbols.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param symbols  the new symbols, not null
+     * @return a formatter based on this formatter with the requested symbols, not null
+     */
+    public DateTimeFormatter withSymbols(DateTimeFormatSymbols symbols) {
+        if (this.symbols.equals(symbols)) {
+            return this;
+        }
+        return new DateTimeFormatter(printerParser, locale, symbols, chrono, zone);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the overriding chronology to be used during formatting.
+     * <p>
+     * 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.
+     *
+     * @return the chronology of this formatter, null if no override
+     */
+    public Chrono<?> getChrono() {
+        return chrono;
+    }
+
+    /**
+     * Returns a copy of this formatter with a new override chronology.
+     * <p>
+     * This returns a formatter with similar state to this formatter but
+     * with the override chronology set.
+     * By default, a formatter has no override chronology, returning null.
+     * <p>
+     * If an override is added, then any date that is printed or parsed will be affected.
+     * <p>
+     * When printing, 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
+     * of {@code ChronoLocalDate},{@code ChronoLocalDateTime} or {@code ChronoZonedDateTime}.
+     * <p>
+     * When parsing, the override chronology will be used to interpret the
+     * {@link java.time.temporal.ChronoField fields} into a date unless the
+     * formatter directly parses a valid chronology.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @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) {
+        if (Objects.equals(this.chrono, chrono)) {
+            return this;
+        }
+        return new DateTimeFormatter(printerParser, locale, symbols, chrono, zone);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the overriding zone to be used during formatting.
+     * <p>
+     * This returns the override zone, used to convert instants.
+     * By default, a formatter has no override zone, returning null.
+     * See {@link #withZone(ZoneId)} for more details on overriding.
+     *
+     * @return the chronology of this formatter, null if no override
+     */
+    public ZoneId getZone() {
+        return zone;
+    }
+
+    /**
+     * Returns a copy of this formatter with a new override zone.
+     * <p>
+     * This returns a formatter with similar state to this formatter but
+     * with the override zone set.
+     * By default, a formatter has no override zone, returning null.
+     * <p>
+     * If an override is added, then any instant that is printed or parsed will be affected.
+     * <p>
+     * When printing, 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
+     * the ISO chronology will be used.
+     * The converted result will behave in a manner equivalent to an implementation
+     * of {@code ChronoZonedDateTime}.
+     * <p>
+     * When parsing, the override zone will be used to interpret the
+     * {@link java.time.temporal.ChronoField fields} into an instant unless the
+     * formatter directly parses a valid zone.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param zone  the new override zone, not null
+     * @return a formatter based on this formatter with the requested override zone, not null
+     */
+    public DateTimeFormatter withZone(ZoneId zone) {
+        if (Objects.equals(this.zone, zone)) {
+            return this;
+        }
+        return new DateTimeFormatter(printerParser, locale, symbols, chrono, zone);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Prints a date-time object using this formatter.
+     * <p>
+     * This prints 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
+     */
+    public String print(TemporalAccessor temporal) {
+        StringBuilder buf = new StringBuilder(32);
+        printTo(temporal, buf);
+        return buf.toString();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Prints a date-time object to an {@code Appendable} using this formatter.
+     * <p>
+     * This prints the 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}.
+     * <p>
+     * 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
+     */
+    public void printTo(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);
+            } else {
+                // buffer output to avoid writing to appendable in case of error
+                StringBuilder buf = new StringBuilder(32);
+                printerParser.print(context, buf);
+                appendable.append(buf);
+            }
+        } catch (IOException ex) {
+            throw new DateTimePrintException(ex.getMessage(), ex);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Fully parses the text producing an object of the specified type.
+     * <p>
+     * Most applications should use this method for parsing.
+     * It parses the entire text to produce the required date-time.
+     * The query is typically a method reference to a {@code from(TemporalAccessor)} method.
+     * For example:
+     * <pre>
+     *  LocalDateTime dt = parser.parse(str, LocalDateTime::from);
+     * </pre>
+     * 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 <T> the type of the parsed date-time
+     * @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
+     */
+    public <T> T parse(CharSequence text, TemporalQuery<T> 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();
+            return builder.query(query);
+        } catch (DateTimeParseException ex) {
+            throw ex;
+        } catch (RuntimeException ex) {
+            throw createError(str, ex);
+        }
+    }
+
+    /**
+     * Fully parses the text producing an object of one of the specified types.
+     * <p>
+     * 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}.
+     * 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.
+     * <p>
+     * The result is associated with the first type that successfully parses.
+     * Normally, applications will use {@code instanceof} to check the result.
+     * For example:
+     * <pre>
+     *  TemporalAccessor dt = parser.parseBest(str, OffsetDate::from, LocalDate::from);
+     *  if (dt instanceof OffsetDate) {
+     *   ...
+     *  } else {
+     *   ...
+     *  }
+     * </pre>
+     * 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
+     * @param queries  the queries defining the types to attempt to parse to,
+     *  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
+     */
+    public TemporalAccessor parseBest(CharSequence text, TemporalQuery<?>... queries) {
+        Objects.requireNonNull(text, "text");
+        Objects.requireNonNull(queries, "queries");
+        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();
+            for (TemporalQuery<?> query : queries) {
+                try {
+                    return (TemporalAccessor) builder.query(query);
+                } catch (RuntimeException ex) {
+                    // continue
+                }
+            }
+            throw new DateTimeException("Unable to convert parsed text using any of the specified queries");
+        } catch (DateTimeParseException ex) {
+            throw ex;
+        } catch (RuntimeException ex) {
+            throw createError(str, ex);
+        }
+    }
+
+    private DateTimeParseException createError(String str, RuntimeException ex) {
+        String abbr = str;
+        if (abbr.length() > 64) {
+            abbr = abbr.substring(0, 64) + "...";
+        }
+        return new DateTimeParseException("Text '" + abbr + "' could not be parsed: " + ex.getMessage(), str, 0, ex);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Parses the text to a builder.
+     * <p>
+     * This parses to a {@code DateTimeBuilder} ensuring that the text is fully parsed.
+     * This method throws {@link DateTimeParseException} if unable to parse, or
+     * some other {@code DateTimeException} if another date/time problem occurs.
+     *
+     * @param text  the text to parse, not null
+     * @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) + "...";
+            }
+            if (pos.getErrorIndex() >= 0) {
+                throw new DateTimeParseException("Text '" + abbr + "' could not be parsed at index " +
+                        pos.getErrorIndex(), str, pos.getErrorIndex());
+            } else {
+                throw new DateTimeParseException("Text '" + abbr + "' could not be parsed, unparsed text found at index " +
+                        pos.getIndex(), str, pos.getIndex());
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Parses the text to a builder.
+     * <p>
+     * This parses to a {@code DateTimeBuilder} but does not require the input to be fully parsed.
+     * <p>
+     * This method does not throw {@link DateTimeParseException}.
+     * Instead, errors are returned within the state of the specified parse position.
+     * Callers must check for errors before using the context.
+     * <p>
+     * This method may throw some other {@code DateTimeException} if a 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, not null
+     * @return the parsed text, null only 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) {
+        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);
+            return null;
+        }
+        position.setIndex(pos);
+        return context.toBuilder();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns the formatter as a composite printer parser.
+     *
+     * @param optional  whether the printer/parser should be optional
+     * @return the printer/parser, not null
+     */
+    CompositePrinterParser toPrinterParser(boolean optional) {
+        return printerParser.withOptional(optional);
+    }
+
+    /**
+     * Returns this formatter as a {@code java.text.Format} instance.
+     * <p>
+     * The returned {@link Format} instance will print any {@link java.time.temporal.TemporalAccessor}
+     * and parses to a resolved {@link DateTimeBuilder}.
+     * <p>
+     * Exceptions will follow the definitions of {@code Format}, see those methods
+     * for details about {@code IllegalArgumentException} during formatting and
+     * {@code ParseException} or null during parsing.
+     * The format does not support attributing of the returned format string.
+     *
+     * @return this formatter as a classic format instance, not null
+     */
+    public Format toFormat() {
+        return new ClassicFormat(this, null);
+    }
+
+    /**
+     * Returns this formatter as a {@code java.text.Format} instance that will
+     * parse using the specified query.
+     * <p>
+     * The returned {@link Format} instance will print any {@link java.time.temporal.TemporalAccessor}
+     * and parses to the type specified.
+     * The type must be one that is supported by {@link #parse}.
+     * <p>
+     * Exceptions will follow the definitions of {@code Format}, see those methods
+     * for details about {@code IllegalArgumentException} during formatting and
+     * {@code ParseException} or null during parsing.
+     * The format does not support attributing of the returned format string.
+     *
+     * @param parseQuery  the query defining the type to parse to, not null
+     * @return this formatter as a classic format instance, not null
+     */
+    public Format toFormat(TemporalQuery<?> parseQuery) {
+        Objects.requireNonNull(parseQuery, "parseQuery");
+        return new ClassicFormat(this, parseQuery);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a description of the underlying formatters.
+     *
+     * @return a description of this formatter, not null
+     */
+    @Override
+    public String toString() {
+        String pattern = printerParser.toString();
+        pattern = pattern.startsWith("[") ? pattern : pattern.substring(1, pattern.length() - 1);
+        return pattern;
+        // TODO: Fix tests to not depend on toString()
+//        return "DateTimeFormatter[" + locale +
+//                (chrono != null ? "," + chrono : "") +
+//                (zone != null ? "," + zone : "") +
+//                pattern + "]";
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Implements the classic Java Format API.
+     * @serial exclude
+     */
+    @SuppressWarnings("serial")  // not actually serializable
+    static class ClassicFormat extends Format {
+        /** The formatter. */
+        private final DateTimeFormatter formatter;
+        /** The type to be parsed. */
+        private final TemporalQuery<?> parseType;
+        /** Constructor. */
+        public ClassicFormat(DateTimeFormatter formatter, TemporalQuery<?> parseType) {
+            this.formatter = formatter;
+            this.parseType = parseType;
+        }
+
+        @Override
+        public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
+            Objects.requireNonNull(obj, "obj");
+            Objects.requireNonNull(toAppendTo, "toAppendTo");
+            Objects.requireNonNull(pos, "pos");
+            if (obj instanceof TemporalAccessor == false) {
+                throw new IllegalArgumentException("Format target must implement TemporalAccessor");
+            }
+            pos.setBeginIndex(0);
+            pos.setEndIndex(0);
+            try {
+                formatter.printTo((TemporalAccessor) obj, toAppendTo);
+            } catch (RuntimeException ex) {
+                throw new IllegalArgumentException(ex.getMessage(), ex);
+            }
+            return toAppendTo;
+        }
+        @Override
+        public Object parseObject(String text) throws ParseException {
+            Objects.requireNonNull(text, "text");
+            try {
+                if (parseType != null) {
+                    return formatter.parse(text, parseType);
+                }
+                return formatter.parseToBuilder(text);
+            } catch (DateTimeParseException ex) {
+                throw new ParseException(ex.getMessage(), ex.getErrorIndex());
+            } catch (RuntimeException ex) {
+                throw (ParseException) new ParseException(ex.getMessage(), 0).initCause(ex);
+            }
+        }
+        @Override
+        public Object parseObject(String text, ParsePosition pos) {
+            Objects.requireNonNull(text, "text");
+            DateTimeBuilder builder;
+            try {
+                builder = formatter.parseToBuilder(text, pos);
+            } catch (IndexOutOfBoundsException ex) {
+                if (pos.getErrorIndex() < 0) {
+                    pos.setErrorIndex(0);
+                }
+                return null;
+            }
+            if (builder == null) {
+                if (pos.getErrorIndex() < 0) {
+                    pos.setErrorIndex(0);
+                }
+                return null;
+            }
+            if (parseType == null) {
+                return builder;
+            }
+            try {
+                return builder.resolve().query(parseType);
+            } catch (RuntimeException ex) {
+                pos.setErrorIndex(0);
+                return null;
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/format/DateTimeFormatterBuilder.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,3365 @@
+/*
+ * 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.HOUR_OF_DAY;
+import static java.time.temporal.ChronoField.INSTANT_SECONDS;
+import static java.time.temporal.ChronoField.MINUTE_OF_HOUR;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.NANO_OF_SECOND;
+import static java.time.temporal.ChronoField.OFFSET_SECONDS;
+import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
+import static java.time.temporal.ChronoField.YEAR;
+
+import java.lang.ref.SoftReference;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.RoundingMode;
+import java.text.ParsePosition;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+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.Queries;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.ValueRange;
+import java.time.temporal.WeekFields;
+import java.time.zone.ZoneRulesProvider;
+import java.util.AbstractMap.SimpleImmutableEntry;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+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.TimeZone;
+import java.util.concurrent.ConcurrentHashMap;
+
+import sun.util.locale.provider.TimeZoneNameUtility;
+
+/**
+ * Builder to create date-time formatters.
+ * <p>
+ * This allows a {@code DateTimeFormatter} to be created.
+ * All date-time formatters are created ultimately using this builder.
+ * <p>
+ * The basic elements of date-time can all be added:
+ * <p><ul>
+ * <li>Value - a numeric value</li>
+ * <li>Fraction - a fractional value including the decimal place. Always use this when
+ * outputting fractions to ensure that the fraction is parsed correctly</li>
+ * <li>Text - the textual equivalent for the value</li>
+ * <li>OffsetId/Offset - the {@linkplain ZoneOffset zone offset}</li>
+ * <li>ZoneId - the {@linkplain ZoneId time-zone} id</li>
+ * <li>ZoneText - the name of the time-zone</li>
+ * <li>Literal - a text literal</li>
+ * <li>Nested and Optional - formats can be nested or made optional</li>
+ * <li>Other - the printer and parser interfaces can be used to add user supplied formatting</li>
+ * </ul><p>
+ * In addition, any of the elements may be decorated by padding, either with spaces or any other character.
+ * <p>
+ * Finally, a shorthand pattern, mostly compatible with {@code java.text.SimpleDateFormat SimpleDateFormat}
+ * can be used, see {@link #appendPattern(String)}.
+ * In practice, this simply parses the pattern and calls other methods on the builder.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is a mutable builder intended for use from a single thread.
+ *
+ * @since 1.8
+ */
+public final class DateTimeFormatterBuilder {
+
+    /**
+     * Query for a time-zone that is region-only.
+     */
+    private static final TemporalQuery<ZoneId> QUERY_REGION_ONLY = (temporal) -> {
+        ZoneId zone = temporal.query(Queries.zoneId());
+        return (zone != null && zone instanceof ZoneOffset == false ? zone : null);
+    };
+
+    /**
+     * The currently active builder, used by the outermost builder.
+     */
+    private DateTimeFormatterBuilder active = this;
+    /**
+     * The parent builder, null for the outermost builder.
+     */
+    private final DateTimeFormatterBuilder parent;
+    /**
+     * The list of printers that will be used.
+     */
+    private final List<DateTimePrinterParser> printerParsers = new ArrayList<>();
+    /**
+     * Whether this builder produces an optional formatter.
+     */
+    private final boolean optional;
+    /**
+     * The width to pad the next field to.
+     */
+    private int padNextWidth;
+    /**
+     * The character to pad the next field with.
+     */
+    private char padNextChar;
+    /**
+     * The index of the last variable width value parser.
+     */
+    private int valueParserIndex = -1;
+
+    /**
+     * Constructs a new instance of the builder.
+     */
+    public DateTimeFormatterBuilder() {
+        super();
+        parent = null;
+        optional = false;
+    }
+
+    /**
+     * Constructs a new instance of the builder.
+     *
+     * @param parent  the parent builder, not null
+     * @param optional  whether the formatter is optional, not null
+     */
+    private DateTimeFormatterBuilder(DateTimeFormatterBuilder parent, boolean optional) {
+        super();
+        this.parent = parent;
+        this.optional = optional;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Changes the parse style to be case sensitive for the remainder of the formatter.
+     * <p>
+     * Parsing can be case sensitive or insensitive - by default it is case sensitive.
+     * This method allows the case sensitivity setting of parsing to be changed.
+     * <p>
+     * Calling this method changes the state of the builder such that all
+     * subsequent builder method calls will parse text in case sensitive mode.
+     * See {@link #parseCaseInsensitive} for the opposite setting.
+     * The parse case sensitive/insensitive methods may be called at any point
+     * in the builder, thus the parser can swap between case parsing modes
+     * multiple times during the parse.
+     * <p>
+     * Since the default is case sensitive, this method should only be used after
+     * a previous call to {@code #parseCaseInsensitive}.
+     *
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder parseCaseSensitive() {
+        appendInternal(SettingsParser.SENSITIVE);
+        return this;
+    }
+
+    /**
+     * Changes the parse style to be case insensitive for the remainder of the formatter.
+     * <p>
+     * Parsing can be case sensitive or insensitive - by default it is case sensitive.
+     * This method allows the case sensitivity setting of parsing to be changed.
+     * <p>
+     * Calling this method changes the state of the builder such that all
+     * subsequent builder method calls will parse text in case insensitive mode.
+     * See {@link #parseCaseSensitive()} for the opposite setting.
+     * The parse case sensitive/insensitive methods may be called at any point
+     * in the builder, thus the parser can swap between case parsing modes
+     * multiple times during the parse.
+     *
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder parseCaseInsensitive() {
+        appendInternal(SettingsParser.INSENSITIVE);
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Changes the parse style to be strict for the remainder of the formatter.
+     * <p>
+     * Parsing can be strict or lenient - by default its strict.
+     * This controls the degree of flexibility in matching the text and sign styles.
+     * <p>
+     * When used, this method changes the parsing to be strict from this point onwards.
+     * As strict is the default, this is normally only needed after calling {@link #parseLenient()}.
+     * The change will remain in force until the end of the formatter that is eventually
+     * constructed or until {@code parseLenient} is called.
+     *
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder parseStrict() {
+        appendInternal(SettingsParser.STRICT);
+        return this;
+    }
+
+    /**
+     * Changes the parse style to be lenient for the remainder of the formatter.
+     * Note that case sensitivity is set separately to this method.
+     * <p>
+     * Parsing can be strict or lenient - by default its strict.
+     * This controls the degree of flexibility in matching the text and sign styles.
+     * Applications calling this method should typically also call {@link #parseCaseInsensitive()}.
+     * <p>
+     * When used, this method changes the parsing to be lenient from this point onwards.
+     * The change will remain in force until the end of the formatter that is eventually
+     * constructed or until {@code parseStrict} is called.
+     *
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder parseLenient() {
+        appendInternal(SettingsParser.LENIENT);
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends the value of a date-time field to the formatter using a normal
+     * output style.
+     * <p>
+     * The value of the field will be output during a print.
+     * If the value cannot be obtained then an exception will be thrown.
+     * <p>
+     * The value will be printed as per the normal print of an integer value.
+     * Only negative numbers will be signed. No padding will be added.
+     * <p>
+     * The parser for a variable width value such as this normally behaves greedily,
+     * requiring one digit, but accepting as many digits as possible.
+     * This behavior can be affected by 'adjacent value parsing'.
+     * See {@link #appendValue(java.time.temporal.TemporalField, int)} for full details.
+     *
+     * @param field  the field to append, not null
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder appendValue(TemporalField field) {
+        Objects.requireNonNull(field, "field");
+        active.valueParserIndex = appendInternal(new NumberPrinterParser(field, 1, 19, SignStyle.NORMAL));
+        return this;
+    }
+
+    /**
+     * Appends the value of a date-time field to the formatter using a fixed
+     * width, zero-padded approach.
+     * <p>
+     * The value of the field will be output during a print.
+     * If the value cannot be obtained then an exception will be thrown.
+     * <p>
+     * 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.
+     * <p>
+     * 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
+     * fixed length values. The standard parser is greedy, and thus it would normally
+     * steal the digits that are needed by the fixed width value parsers that follow the
+     * variable width one.
+     * <p>
+     * No action is required to initiate 'adjacent value parsing'.
+     * When a call to {@code appendValue} with a variable width is made, the builder
+     * enters adjacent value parsing setup mode. If the immediately subsequent method
+     * call or calls on the same builder are to this method, then the parser will reserve
+     * space so that the fixed width values can be parsed.
+     * <p>
+     * For example, consider {@code builder.appendValue(YEAR).appendValue(MONTH_OF_YEAR, 2);}
+     * The year is a variable width parse of between 1 and 19 digits.
+     * The month is a fixed width parse of 2 digits.
+     * Because these were appended to the same builder immediately after one another,
+     * the year parser will reserve two digits for the month to parse.
+     * Thus, the text '201106' will correctly parse to a year of 2011 and a month of 6.
+     * Without adjacent value parsing, the year would greedily parse all six digits and leave
+     * nothing for the month.
+     * <p>
+     * Adjacent value parsing applies to each set of fixed width not-negative values in the parser
+     * that immediately follow any kind of variable width value.
+     * Calling any other append method will end the setup of adjacent value parsing.
+     * Thus, in the unlikely event that you need to avoid adjacent value parsing behavior,
+     * simply add the {@code appendValue} to another {@code DateTimeFormatterBuilder}
+     * and add that to this builder.
+     * <p>
+     * If adjacent parsing is active, then parsing must match exactly the specified
+     * number of digits in both strict and lenient modes.
+     * In addition, no positive or negative sign is permitted.
+     *
+     * @param field  the field to append, not null
+     * @param width  the width of the printed field, from 1 to 19
+     * @return this, for chaining, not null
+     * @throws IllegalArgumentException if the width is invalid
+     */
+    public DateTimeFormatterBuilder appendValue(TemporalField field, int width) {
+        Objects.requireNonNull(field, "field");
+        if (width < 1 || width > 19) {
+            throw new IllegalArgumentException("The width must be from 1 to 19 inclusive but was " + width);
+        }
+        NumberPrinterParser pp = new NumberPrinterParser(field, width, width, SignStyle.NOT_NEGATIVE);
+        return appendFixedWidth(width, pp);
+    }
+
+    /**
+     * Appends the value of a date-time field to the formatter providing full
+     * control over printing.
+     * <p>
+     * The value of the field will be output during a print.
+     * If the value cannot be obtained then an exception will be thrown.
+     * <p>
+     * This method provides full control of the numeric formatting, including
+     * zero-padding and the positive/negative sign.
+     * <p>
+     * The parser for a variable width value such as this normally behaves greedily,
+     * accepting as many digits as possible.
+     * This behavior can be affected by 'adjacent value parsing'.
+     * See {@link #appendValue(java.time.temporal.TemporalField, int)} for full details.
+     * <p>
+     * In strict parsing mode, the minimum number of parsed digits is {@code minWidth}.
+     * In lenient parsing mode, the minimum number of parsed digits is one.
+     * <p>
+     * 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.
+     *
+     * @param field  the field to append, not null
+     * @param minWidth  the minimum field width of the printed field, from 1 to 19
+     * @param maxWidth  the maximum field width of the printed field, from 1 to 19
+     * @param signStyle  the positive/negative output style, not null
+     * @return this, for chaining, not null
+     * @throws IllegalArgumentException if the widths are invalid
+     */
+    public DateTimeFormatterBuilder appendValue(
+            TemporalField field, int minWidth, int maxWidth, SignStyle signStyle) {
+        if (minWidth == maxWidth && signStyle == SignStyle.NOT_NEGATIVE) {
+            return appendValue(field, maxWidth);
+        }
+        Objects.requireNonNull(field, "field");
+        Objects.requireNonNull(signStyle, "signStyle");
+        if (minWidth < 1 || minWidth > 19) {
+            throw new IllegalArgumentException("The minimum width must be from 1 to 19 inclusive but was " + minWidth);
+        }
+        if (maxWidth < 1 || maxWidth > 19) {
+            throw new IllegalArgumentException("The maximum width must be from 1 to 19 inclusive but was " + maxWidth);
+        }
+        if (maxWidth < minWidth) {
+            throw new IllegalArgumentException("The maximum width must exceed or equal the minimum width but " +
+                    maxWidth + " < " + minWidth);
+        }
+        NumberPrinterParser pp = new NumberPrinterParser(field, minWidth, maxWidth, signStyle);
+        if (minWidth == maxWidth) {
+            appendInternal(pp);
+        } else {
+            active.valueParserIndex = appendInternal(pp);
+        }
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends the reduced value of a date-time field to the formatter.
+     * <p>
+     * This is typically used for printing 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.
+     * <p>
+     * For printing, the width is used to determine the number of characters to print.
+     * The rightmost characters are output to match the width, left padding with zero.
+     * <p>
+     * For parsing, exactly the number of characters specified by the width are parsed.
+     * This is incomplete information however, so the base value is used to complete the parse.
+     * The base value is the first valid value in a range of ten to the power of width.
+     * <p>
+     * For example, a base value of {@code 1980} and a width of {@code 2} will have
+     * valid values from {@code 1980} to {@code 2079}.
+     * During parsing, the text {@code "12"} will result in the value {@code 2012} as that
+     * is the value within the range where the last two digits are "12".
+     * <p>
+     * This is a fixed width parser operating using 'adjacent value parsing'.
+     * See {@link #appendValue(java.time.temporal.TemporalField, int)} for full details.
+     *
+     * @param field  the field to append, not null
+     * @param width  the width of the printed and parsed field, from 1 to 18
+     * @param baseValue  the base value of the range of valid values
+     * @return this, for chaining, not null
+     * @throws IllegalArgumentException if the width or base value is invalid
+     */
+    public DateTimeFormatterBuilder appendValueReduced(
+            TemporalField field, int width, int baseValue) {
+        Objects.requireNonNull(field, "field");
+        ReducedPrinterParser pp = new ReducedPrinterParser(field, width, baseValue);
+        appendFixedWidth(width, pp);
+        return this;
+    }
+
+    /**
+     * Appends a fixed width printer-parser.
+     *
+     * @param width  the width
+     * @param pp  the printer-parser, not null
+     * @return this, for chaining, not null
+     */
+    private DateTimeFormatterBuilder appendFixedWidth(int width, NumberPrinterParser pp) {
+        if (active.valueParserIndex >= 0) {
+            // adjacent parsing mode, update setting in previous parsers
+            NumberPrinterParser basePP = (NumberPrinterParser) active.printerParsers.get(active.valueParserIndex);
+            basePP = basePP.withSubsequentWidth(width);
+            int activeValueParser = active.valueParserIndex;
+            active.printerParsers.set(active.valueParserIndex, basePP);
+            appendInternal(pp.withFixedWidth());
+            active.valueParserIndex = activeValueParser;
+        } else {
+            // not adjacent parsing
+            appendInternal(pp);
+        }
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends the fractional value of a date-time field to the formatter.
+     * <p>
+     * The fractional value of the field will be output including the
+     * preceding decimal point. The preceding value is not output.
+     * For example, the second-of-minute value of 15 would be output as {@code .25}.
+     * <p>
+     * The width of the printed fraction can be controlled. Setting the
+     * minimum width to zero will cause no output to be generated.
+     * The printed fraction will have the minimum width necessary between
+     * the minimum and maximum widths - trailing zeroes are omitted.
+     * No rounding occurs due to the maximum width - digits are simply dropped.
+     * <p>
+     * When parsing in strict mode, the number of parsed digits must be between
+     * the minimum and maximum width. When parsing in lenient mode, the minimum
+     * width is considered to be zero and the maximum is nine.
+     * <p>
+     * If the value cannot be obtained then an exception will be thrown.
+     * If the value is negative an exception will be thrown.
+     * If the field does not have a fixed set of valid values then an
+     * exception will be thrown.
+     * If the field value in the date-time to be printed is invalid it
+     * cannot be printed and an exception will be thrown.
+     *
+     * @param field  the field to append, not null
+     * @param minWidth  the minimum width of the field excluding the decimal point, from 0 to 9
+     * @param maxWidth  the maximum width of the field excluding the decimal point, from 1 to 9
+     * @param decimalPoint  whether to output the localized decimal point symbol
+     * @return this, for chaining, not null
+     * @throws IllegalArgumentException if the field has a variable set of valid values or
+     *  either width is invalid
+     */
+    public DateTimeFormatterBuilder appendFraction(
+            TemporalField field, int minWidth, int maxWidth, boolean decimalPoint) {
+        appendInternal(new FractionPrinterParser(field, minWidth, maxWidth, decimalPoint));
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends the text of a date-time field to the formatter using the full
+     * text style.
+     * <p>
+     * The text of the field will be output during a print.
+     * 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.
+     * <p>
+     * The value will be printed as per the normal print of an integer value.
+     * Only negative numbers will be signed. No padding will be added.
+     *
+     * @param field  the field to append, not null
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder appendText(TemporalField field) {
+        return appendText(field, TextStyle.FULL);
+    }
+
+    /**
+     * Appends the text of a date-time field to the formatter.
+     * <p>
+     * The text of the field will be output during a print.
+     * 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.
+     * <p>
+     * The value will be printed as per the normal print of an integer value.
+     * Only negative numbers will be signed. No padding will be added.
+     *
+     * @param field  the field to append, not null
+     * @param textStyle  the text style to use, not null
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder appendText(TemporalField field, TextStyle textStyle) {
+        Objects.requireNonNull(field, "field");
+        Objects.requireNonNull(textStyle, "textStyle");
+        appendInternal(new TextPrinterParser(field, textStyle, DateTimeTextProvider.getInstance()));
+        return this;
+    }
+
+    /**
+     * Appends the text of a date-time field to the formatter using the specified
+     * map to supply the text.
+     * <p>
+     * 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
+     * parsing is possible, thus an invalid map may throw an error during later use.
+     * <p>
+     * Supplying the map of text provides considerable flexibility in printing 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
+     * defines the connection between each value and the text:
+     * <pre>
+     * Map&lt;Long, String&gt; map = new HashMap&lt;&gt;();
+     * map.put(1, "JNY");
+     * map.put(2, "FBY");
+     * map.put(3, "MCH");
+     * ...
+     * builder.appendText(MONTH_OF_YEAR, map);
+     * </pre>
+     * <p>
+     * Other uses might be to output the value with a suffix, such as "1st", "2nd", "3rd",
+     * or as Roman numerals "I", "II", "III", "IV".
+     * <p>
+     * During printing, 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.
+     *
+     * @param field  the field to append, not null
+     * @param textLookup  the map from the value to the text
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder appendText(TemporalField field, Map<Long, String> textLookup) {
+        Objects.requireNonNull(field, "field");
+        Objects.requireNonNull(textLookup, "textLookup");
+        Map<Long, String> copy = new LinkedHashMap<>(textLookup);
+        Map<TextStyle, Map<Long, String>> map = Collections.singletonMap(TextStyle.FULL, copy);
+        final LocaleStore store = new LocaleStore(map);
+        DateTimeTextProvider provider = new DateTimeTextProvider() {
+            @Override
+            public String getText(TemporalField field, long value, TextStyle style, Locale locale) {
+                return store.getText(value, style);
+            }
+            @Override
+            public Iterator<Entry<String, Long>> getTextIterator(TemporalField field, TextStyle style, Locale locale) {
+                return store.getTextIterator(style);
+            }
+        };
+        appendInternal(new TextPrinterParser(field, TextStyle.FULL, provider));
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends an instant using ISO-8601 to the formatter.
+     * <p>
+     * Instants have a fixed output format.
+     * They are converted to a date-time with a zone-offset of UTC and printed
+     * using the standard ISO-8601 format.
+     * <p>
+     * An alternative to this method is to print/parse the instant as a single
+     * epoch-seconds value. That is achieved using {@code appendValue(INSTANT_SECONDS)}.
+     *
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder appendInstant() {
+        appendInternal(new InstantPrinterParser());
+        return this;
+    }
+
+    /**
+     * Appends the zone offset, such as '+01:00', to the formatter.
+     * <p>
+     * This appends an instruction to print/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);
+        return this;
+    }
+
+    /**
+     * Appends the zone offset, such as '+01:00', to the formatter.
+     * <p>
+     * This appends an instruction to print/parse the offset ID to the builder.
+     * <p>
+     * During printing, 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
+     * section of the formatter is optional.
+     * <p>
+     * During parsing, the offset is parsed using the format defined below.
+     * If the offset cannot be parsed then an exception is thrown unless the
+     * section of the formatter is optional.
+     * <p>
+     * The format of the offset is controlled by a pattern which must be one
+     * of the following:
+     * <p><ul>
+     * <li>{@code +HH} - hour only, ignoring any minute
+     * <li>{@code +HHMM} - hour and minute, no colon
+     * <li>{@code +HH:MM} - hour and minute, with colon
+     * <li>{@code +HHMMss} - hour and minute, with second if non-zero and no colon
+     * <li>{@code +HH:MM:ss} - hour and minute, with second if non-zero and colon
+     * <li>{@code +HHMMSS} - hour, minute and second, no colon
+     * <li>{@code +HH:MM:SS} - hour, minute and second, with colon
+     * </ul><p>
+     * The "no offset" text controls what text is printed when the offset 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.
+     *
+     * @param pattern  the pattern to use, not null
+     * @param noOffsetText  the text to use when the offset is zero, not null
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder appendOffset(String pattern, String noOffsetText) {
+        appendInternal(new OffsetIdPrinterParser(noOffsetText, pattern));
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends the time-zone ID, such as 'Europe/Paris' or '+02:00', to the formatter.
+     * <p>
+     * This appends an instruction to print/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()}.
+     * <p>
+     * During printing, 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.
+     * <p>
+     * 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.
+     *
+     * @return this, for chaining, not null
+     * @see #appendZoneRegionId()
+     */
+    public DateTimeFormatterBuilder appendZoneId() {
+        appendInternal(new ZoneIdPrinterParser(Queries.zoneId(), "ZoneId()"));
+        return this;
+    }
+
+    /**
+     * Appends the time-zone region ID, such as 'Europe/Paris', to the formatter,
+     * rejecting the zone ID if it is a {@code ZoneOffset}.
+     * <p>
+     * This appends an instruction to print/parse the zone ID to the builder
+     * only if it is a region-based ID.
+     * <p>
+     * During printing, 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()}.
+     * <p>
+     * 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}.
+     *
+     * @return this, for chaining, not null
+     * @see #appendZoneId()
+     */
+    public DateTimeFormatterBuilder appendZoneRegionId() {
+        appendInternal(new ZoneIdPrinterParser(QUERY_REGION_ONLY, "ZoneRegionId()"));
+        return this;
+    }
+
+    /**
+     * Appends the time-zone ID, such as 'Europe/Paris' or '+02:00', to
+     * the formatter, using the best available zone ID.
+     * <p>
+     * This appends an instruction to print/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}.
+     * <p>
+     * During printing, 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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()
+     */
+    public DateTimeFormatterBuilder appendZoneOrOffsetId() {
+        appendInternal(new ZoneIdPrinterParser(Queries.zone(), "ZoneOrOffsetId()"));
+        return this;
+    }
+
+    /**
+     * Appends the time-zone name, such as 'British Summer Time', to the formatter.
+     * <p>
+     * This appends an instruction to print the textual name of the zone to the builder.
+     * <p>
+     * During printing, 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.
+     * <p>
+     * Parsing is not currently supported.
+     *
+     * @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));
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends the chronology ID to the formatter.
+     * <p>
+     * The chronology ID will be output during a print.
+     * If the chronology cannot be obtained then an exception will be thrown.
+     *
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder appendChronoId() {
+        appendInternal(new ChronoPrinterParser(null));
+        return this;
+    }
+
+    /**
+     * Appends the chronology name to the formatter.
+     * <p>
+     * The calendar system name will be output during a print.
+     * 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) {
+        Objects.requireNonNull(textStyle, "textStyle");
+        appendInternal(new ChronoPrinterParser(textStyle));
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends a localized date-time pattern to the formatter.
+     * <p>
+     * The pattern is resolved lazily using the locale being used during the print/parse
+     * (stored in {@link DateTimeFormatter}.
+     * <p>
+     * The pattern can vary by chronology, although typically it doesn't.
+     * This method uses the standard ISO chronology patterns.
+     *
+     * @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
+     */
+    public DateTimeFormatterBuilder appendLocalized(FormatStyle dateStyle, FormatStyle timeStyle) {
+        return appendLocalized(dateStyle, timeStyle, ISOChrono.INSTANCE);
+    }
+
+    /**
+     * Appends a localized date-time pattern to the formatter.
+     * <p>
+     * The pattern is resolved lazily using the locale being used during the print/parse,
+     * stored in {@link DateTimeFormatter}.
+     * <p>
+     * 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));
+        }
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends a character literal to the formatter.
+     * <p>
+     * This character will be output during a print.
+     *
+     * @param literal  the literal to append, not null
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder appendLiteral(char literal) {
+        appendInternal(new CharLiteralPrinterParser(literal));
+        return this;
+    }
+
+    /**
+     * Appends a string literal to the formatter.
+     * <p>
+     * This string will be output during a print.
+     * <p>
+     * If the literal is empty, nothing is added to the formatter.
+     *
+     * @param literal  the literal to append, not null
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder appendLiteral(String literal) {
+        Objects.requireNonNull(literal, "literal");
+        if (literal.length() > 0) {
+            if (literal.length() == 1) {
+                appendInternal(new CharLiteralPrinterParser(literal.charAt(0)));
+            } else {
+                appendInternal(new StringLiteralPrinterParser(literal));
+            }
+        }
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends all the elements of a formatter to the builder.
+     * <p>
+     * This method has the same effect as appending each of the constituent
+     * parts of the formatter directly to this builder.
+     *
+     * @param formatter  the formatter to add, not null
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder append(DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        appendInternal(formatter.toPrinterParser(false));
+        return this;
+    }
+
+    /**
+     * Appends a formatter to the builder which will optionally print/parse.
+     * <p>
+     * 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()}.
+     * <p>
+     * The formatter will print 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
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder appendOptional(DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        appendInternal(formatter.toPrinterParser(true));
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends the elements defined by the specified pattern to the builder.
+     * <p>
+     * All letters 'A' to 'Z' and 'a' to 'z' are reserved as pattern letters.
+     * The characters '{' and '}' are reserved for future use.
+     * The characters '[' and ']' indicate optional patterns.
+     * The following pattern letters are defined:
+     * <pre>
+     *  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
+     * </pre>
+     * <p>
+     * The count of pattern letters determine the format.
+     * <p>
+     * <b>Text</b>: 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}.
+     * <p>
+     * <b>Number</b>: If the count of letters is one, then the value is printed using the minimum number
+     * of digits and without padding as per {@link #appendValue(java.time.temporal.TemporalField)}. Otherwise, the
+     * count of digits is used as the width of the output field as per {@link #appendValue(java.time.temporal.TemporalField, int)}.
+     * <p>
+     * <b>Number/Text</b>: If the count of pattern letters is 3 or greater, use the Text rules above.
+     * Otherwise use the Number rules above.
+     * <p>
+     * <b>Fraction</b>: 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.
+     * <p>
+     * <b>Year</b>: 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
+     * 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}
+     * <p>
+     * <b>ZoneId</b>: 'I' outputs the zone ID, such as 'Europe/Paris'.
+     * <p>
+     * <b>Offset X</b>: 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'.
+     * <p>
+     * <b>Offset Z</b>: 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'.
+     * <p>
+     * <b>Zone names</b>: Time zone names ('z') cannot be parsed.
+     * <p>
+     * <b>Optional section</b>: The optional section markers work exactly like calling {@link #optionalStart()}
+     * and {@link #optionalEnd()}.
+     * <p>
+     * <b>Pad modifier</b>: 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 #padNext(int)}.
+     * <p>
+     * For example, 'ppH' outputs the hour-of-day padded on the left with spaces to a width of 2.
+     * <p>
+     * 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.
+     * <p>
+     * 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 add, not null
+     * @return this, for chaining, not null
+     * @throws IllegalArgumentException if the pattern is invalid
+     */
+    public DateTimeFormatterBuilder appendPattern(String pattern) {
+        Objects.requireNonNull(pattern, "pattern");
+        parsePattern(pattern);
+        return this;
+    }
+
+    private void parsePattern(String pattern) {
+        for (int pos = 0; pos < pattern.length(); pos++) {
+            char cur = pattern.charAt(pos);
+            if ((cur >= 'A' && cur <= 'Z') || (cur >= 'a' && cur <= 'z')) {
+                int start = pos++;
+                for ( ; pos < pattern.length() && pattern.charAt(pos) == cur; pos++);  // short loop
+                int count = pos - start;
+                // padding
+                if (cur == 'p') {
+                    int pad = 0;
+                    if (pos < pattern.length()) {
+                        cur = pattern.charAt(pos);
+                        if ((cur >= 'A' && cur <= 'Z') || (cur >= 'a' && cur <= 'z')) {
+                            pad = count;
+                            start = pos++;
+                            for ( ; pos < pattern.length() && pattern.charAt(pos) == cur; pos++);  // short loop
+                            count = pos - start;
+                        }
+                    }
+                    if (pad == 0) {
+                        throw new IllegalArgumentException(
+                                "Pad letter 'p' must be followed by valid pad pattern: " + pattern);
+                    }
+                    padNext(pad); // pad and continue parsing
+                }
+                // main rules
+                TemporalField field = FIELD_MAP.get(cur);
+                if (field != null) {
+                    parseField(cur, count, field);
+                } else if (cur == 'z') {
+                    if (count < 4) {
+                        appendZoneText(TextStyle.SHORT);
+                    } else {
+                        appendZoneText(TextStyle.FULL);
+                    }
+                } 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");
+                    }
+                } else if (cur == 'X') {
+                    if (count > 5) {
+                        throw new IllegalArgumentException("Too many pattern letters: " + cur);
+                    }
+                    appendOffset(OffsetIdPrinterParser.PATTERNS[count - 1], "Z");
+                } else if (cur == 'w' || cur == 'e') {
+                    // Fields defined by Locale
+                    if (count > 1) {
+                        throw new IllegalArgumentException("Too many pattern letters: " + cur);
+                    }
+                    appendInternal(new WeekBasedFieldPrinterParser(cur, count));
+                } else if (cur == 'W') {
+                    // Fields defined by Locale
+                    if (count > 2) {
+                        throw new IllegalArgumentException("Too many pattern letters: " + cur);
+                    }
+                    appendInternal(new WeekBasedFieldPrinterParser(cur, count));
+                } else {
+                    throw new IllegalArgumentException("Unknown pattern letter: " + cur);
+                }
+                pos--;
+
+            } else if (cur == '\'') {
+                // parse literals
+                int start = pos++;
+                for ( ; pos < pattern.length(); pos++) {
+                    if (pattern.charAt(pos) == '\'') {
+                        if (pos + 1 < pattern.length() && pattern.charAt(pos + 1) == '\'') {
+                            pos++;
+                        } else {
+                            break;  // end of literal
+                        }
+                    }
+                }
+                if (pos >= pattern.length()) {
+                    throw new IllegalArgumentException("Pattern ends with an incomplete string literal: " + pattern);
+                }
+                String str = pattern.substring(start + 1, pos);
+                if (str.length() == 0) {
+                    appendLiteral('\'');
+                } else {
+                    appendLiteral(str.replace("''", "'"));
+                }
+
+            } else if (cur == '[') {
+                optionalStart();
+
+            } else if (cur == ']') {
+                if (active.parent == null) {
+                    throw new IllegalArgumentException("Pattern invalid as it contains ] without previous [");
+                }
+                optionalEnd();
+
+            } else if (cur == '{' || cur == '}') {
+                throw new IllegalArgumentException("Pattern includes reserved character: '" + cur + "'");
+            } else {
+                appendLiteral(cur);
+            }
+        }
+    }
+
+    private void parseField(char cur, int count, TemporalField field) {
+        switch (cur) {
+            case 'y':
+            case 'Y':
+                if (count == 2) {
+                    appendValueReduced(field, 2, 2000);
+                } else if (count < 4) {
+                    appendValue(field, count, 19, SignStyle.NORMAL);
+                } else {
+                    appendValue(field, count, 19, SignStyle.EXCEEDS_PAD);
+                }
+                break;
+            case 'G':
+            case 'M':
+            case 'Q':
+            case 'E':
+                switch (count) {
+                    case 1:
+                        appendValue(field);
+                        break;
+                    case 2:
+                        appendValue(field, 2);
+                        break;
+                    case 3:
+                        appendText(field, TextStyle.SHORT);
+                        break;
+                    case 4:
+                        appendText(field, TextStyle.FULL);
+                        break;
+                    case 5:
+                        appendText(field, TextStyle.NARROW);
+                        break;
+                    default:
+                        throw new IllegalArgumentException("Too many pattern letters: " + cur);
+                }
+                break;
+            case 'a':
+                switch (count) {
+                    case 1:
+                    case 2:
+                    case 3:
+                        appendText(field, TextStyle.SHORT);
+                        break;
+                    case 4:
+                        appendText(field, TextStyle.FULL);
+                        break;
+                    case 5:
+                        appendText(field, TextStyle.NARROW);
+                        break;
+                    default:
+                        throw new IllegalArgumentException("Too many pattern letters: " + cur);
+                }
+                break;
+            case 'S':
+                appendFraction(NANO_OF_SECOND, count, count, false);
+                break;
+            default:
+                if (count == 1) {
+                    appendValue(field);
+                } else {
+                    appendValue(field, count);
+                }
+                break;
+        }
+    }
+
+    /** Map of letters to fields. */
+    private static final Map<Character, TemporalField> 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
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Causes the next added printer/parser to pad to a fixed width using a space.
+     * <p>
+     * This padding will pad to a fixed width using spaces.
+     * <p>
+     * An exception will be thrown during printing if the pad width
+     * is exceeded.
+     *
+     * @param padWidth  the pad width, 1 or greater
+     * @return this, for chaining, not null
+     * @throws IllegalArgumentException if pad width is too small
+     */
+    public DateTimeFormatterBuilder padNext(int padWidth) {
+        return padNext(padWidth, ' ');
+    }
+
+    /**
+     * Causes the next added printer/parser to pad to a fixed width.
+     * <p>
+     * This padding is intended for padding other than zero-padding.
+     * Zero-padding should be achieved using the appendValue methods.
+     * <p>
+     * An exception will be thrown during printing if the pad width
+     * is exceeded.
+     *
+     * @param padWidth  the pad width, 1 or greater
+     * @param padChar  the pad character
+     * @return this, for chaining, not null
+     * @throws IllegalArgumentException if pad width is too small
+     */
+    public DateTimeFormatterBuilder padNext(int padWidth, char padChar) {
+        if (padWidth < 1) {
+            throw new IllegalArgumentException("The pad width must be at least one but was " + padWidth);
+        }
+        active.padNextWidth = padWidth;
+        active.padNextChar = padChar;
+        active.valueParserIndex = -1;
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Mark the start of an optional section.
+     * <p>
+     * The output of printing 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.
+     * <p>
+     * All elements in the optional section are treated as optional.
+     * During printing, 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.
+     * <p>
+     * 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 parsing, the input will be successfully parsed whether the minute is present or not.
+     *
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder optionalStart() {
+        active.valueParserIndex = -1;
+        active = new DateTimeFormatterBuilder(active, true);
+        return this;
+    }
+
+    /**
+     * Ends an optional section.
+     * <p>
+     * The output of printing 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).
+     * <p>
+     * Calling this method without having previously called {@code optionalStart}
+     * will throw an exception.
+     * Calling this method immediately after calling {@code optionalStart} has no effect
+     * on the formatter other than ending the (empty) optional section.
+     * <p>
+     * All elements in the optional section are treated as optional.
+     * During printing, 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.
+     * <p>
+     * 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 parsing, the input will be successfully parsed whether the minute is present or not.
+     *
+     * @return this, for chaining, not null
+     * @throws IllegalStateException if there was no previous call to {@code optionalStart}
+     */
+    public DateTimeFormatterBuilder optionalEnd() {
+        if (active.parent == null) {
+            throw new IllegalStateException("Cannot call optionalEnd() as there was no previous call to optionalStart()");
+        }
+        if (active.printerParsers.size() > 0) {
+            CompositePrinterParser cpp = new CompositePrinterParser(active.printerParsers, active.optional);
+            active = active.parent;
+            appendInternal(cpp);
+        } else {
+            active = active.parent;
+        }
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends a printer and/or parser to the internal list handling padding.
+     *
+     * @param pp  the printer-parser to add, not null
+     * @return the index into the active parsers list
+     */
+    private int appendInternal(DateTimePrinterParser pp) {
+        Objects.requireNonNull(pp, "pp");
+        if (active.padNextWidth > 0) {
+            if (pp != null) {
+                pp = new PadPrinterParserDecorator(pp, active.padNextWidth, active.padNextChar);
+            }
+            active.padNextWidth = 0;
+            active.padNextChar = 0;
+        }
+        active.printerParsers.add(pp);
+        active.valueParserIndex = -1;
+        return active.printerParsers.size() - 1;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Completes this builder by creating the DateTimeFormatter using the default locale.
+     * <p>
+     * This will create a formatter with the {@link Locale#getDefault(Locale.Category) default FORMAT locale}.
+     * Numbers will be printed and parsed using the standard non-localized set of symbols.
+     * <p>
+     * Calling this method will end any open optional sections by repeatedly
+     * calling {@link #optionalEnd()} before creating the formatter.
+     * <p>
+     * This builder can still be used after creating the formatter if desired,
+     * although the state may have been changed by calls to {@code optionalEnd}.
+     *
+     * @return the created formatter, not null
+     */
+    public DateTimeFormatter toFormatter() {
+        return toFormatter(Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Completes this builder by creating the DateTimeFormatter using the specified locale.
+     * <p>
+     * This will create a formatter with the specified locale.
+     * Numbers will be printed and parsed using the standard non-localized set of symbols.
+     * <p>
+     * Calling this method will end any open optional sections by repeatedly
+     * calling {@link #optionalEnd()} before creating the formatter.
+     * <p>
+     * This builder can still be used after creating the formatter if desired,
+     * although the state may have been changed by calls to {@code optionalEnd}.
+     *
+     * @param locale  the locale to use for formatting, not null
+     * @return the created formatter, not null
+     */
+    public DateTimeFormatter toFormatter(Locale locale) {
+        Objects.requireNonNull(locale, "locale");
+        while (active.parent != null) {
+            optionalEnd();
+        }
+        CompositePrinterParser pp = new CompositePrinterParser(printerParsers, false);
+        return new DateTimeFormatter(pp, locale, DateTimeFormatSymbols.STANDARD, null, null);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Strategy for printing/parsing date-time information.
+     * <p>
+     * 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
+     * units, each outputting a single field.
+     * <p>
+     * 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}.
+     * <p>
+     * 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
+     * for the next parser. If an error occurs, the returned index will be negative
+     * and will have the error position encoded using the complement operator.
+     *
+     * <h3>Specification for implementors</h3>
+     * 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.
+     * <p>
+     * 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
+     * variable or shared with any other threads.
+     */
+    interface DateTimePrinterParser {
+
+        /**
+         * Prints the date-time object to the buffer.
+         * <p>
+         * The context holds information to use during the print.
+         * It also contains the date-time information to be printed.
+         * <p>
+         * The buffer must not be mutated beyond the content controlled by the implementation.
+         *
+         * @param context  the context to print 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);
+
+        /**
+         * Parses text into date-time information.
+         * <p>
+         * The context holds information to use during the parse.
+         * It is also used to store the parsed date-time information.
+         *
+         * @param context  the context to use and parse into, not null
+         * @param text  the input text to parse, not null
+         * @param position  the position to start parsing at, from 0 to the text length
+         * @return the new parse position, where negative means an error with the
+         *  error position encoded using the complement ~ operator
+         * @throws NullPointerException if the context or text is null
+         * @throws IndexOutOfBoundsException if the position is invalid
+         */
+        int parse(DateTimeParseContext context, CharSequence text, int position);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Composite printer and parser.
+     */
+    static final class CompositePrinterParser implements DateTimePrinterParser {
+        private final DateTimePrinterParser[] printerParsers;
+        private final boolean optional;
+
+        CompositePrinterParser(List<DateTimePrinterParser> printerParsers, boolean optional) {
+            this(printerParsers.toArray(new DateTimePrinterParser[printerParsers.size()]), optional);
+        }
+
+        CompositePrinterParser(DateTimePrinterParser[] printerParsers, boolean optional) {
+            this.printerParsers = printerParsers;
+            this.optional = optional;
+        }
+
+        /**
+         * Returns a copy of this printer-parser with the optional flag changed.
+         *
+         * @param optional  the optional flag to set in the copy
+         * @return the new printer-parser, not null
+         */
+        public CompositePrinterParser withOptional(boolean optional) {
+            if (optional == this.optional) {
+                return this;
+            }
+            return new CompositePrinterParser(printerParsers, optional);
+        }
+
+        @Override
+        public boolean print(DateTimePrintContext context, StringBuilder buf) {
+            int length = buf.length();
+            if (optional) {
+                context.startOptional();
+            }
+            try {
+                for (DateTimePrinterParser pp : printerParsers) {
+                    if (pp.print(context, buf) == false) {
+                        buf.setLength(length);  // reset buffer
+                        return true;
+                    }
+                }
+            } finally {
+                if (optional) {
+                    context.endOptional();
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public int parse(DateTimeParseContext context, CharSequence text, int position) {
+            if (optional) {
+                context.startOptional();
+                int pos = position;
+                for (DateTimePrinterParser pp : printerParsers) {
+                    pos = pp.parse(context, text, pos);
+                    if (pos < 0) {
+                        context.endOptional(false);
+                        return position;  // return original position
+                    }
+                }
+                context.endOptional(true);
+                return pos;
+            } else {
+                for (DateTimePrinterParser pp : printerParsers) {
+                    position = pp.parse(context, text, position);
+                    if (position < 0) {
+                        break;
+                    }
+                }
+                return position;
+            }
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder buf = new StringBuilder();
+            if (printerParsers != null) {
+                buf.append(optional ? "[" : "(");
+                for (DateTimePrinterParser pp : printerParsers) {
+                    buf.append(pp);
+                }
+                buf.append(optional ? "]" : ")");
+            }
+            return buf.toString();
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Pads the output to a fixed width.
+     */
+    static final class PadPrinterParserDecorator implements DateTimePrinterParser {
+        private final DateTimePrinterParser printerParser;
+        private final int padWidth;
+        private final char padChar;
+
+        /**
+         * Constructor.
+         *
+         * @param printerParser  the printer, not null
+         * @param padWidth  the width to pad to, 1 or greater
+         * @param padChar  the pad character
+         */
+        PadPrinterParserDecorator(DateTimePrinterParser printerParser, int padWidth, char padChar) {
+            // input checked by DateTimeFormatterBuilder
+            this.printerParser = printerParser;
+            this.padWidth = padWidth;
+            this.padChar = padChar;
+        }
+
+        @Override
+        public boolean print(DateTimePrintContext context, StringBuilder buf) {
+            int preLen = buf.length();
+            if (printerParser.print(context, buf) == false) {
+                return false;
+            }
+            int len = buf.length() - preLen;
+            if (len > padWidth) {
+                throw new DateTimePrintException(
+                    "Cannot print as output of " + len + " characters exceeds pad width of " + padWidth);
+            }
+            for (int i = 0; i < padWidth - len; i++) {
+                buf.insert(preLen, padChar);
+            }
+            return true;
+        }
+
+        @Override
+        public int parse(DateTimeParseContext context, CharSequence text, int position) {
+            if (position > text.length()) {
+                throw new IndexOutOfBoundsException();
+            }
+            int endPos = position + padWidth;
+            if (endPos > text.length()) {
+                return ~position;  // not enough characters in the string to meet the parse width
+            }
+            int pos = position;
+            while (pos < endPos && 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;
+            }
+            // 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
+        }
+
+        @Override
+        public String toString() {
+            return "Pad(" + printerParser + "," + padWidth + (padChar == ' ' ? ")" : ",'" + padChar + "')");
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Enumeration to apply simple parse settings.
+     */
+    static enum SettingsParser implements DateTimePrinterParser {
+        SENSITIVE,
+        INSENSITIVE,
+        STRICT,
+        LENIENT;
+
+        @Override
+        public boolean print(DateTimePrintContext context, StringBuilder buf) {
+            return true;  // nothing to do here
+        }
+
+        @Override
+        public int parse(DateTimeParseContext context, CharSequence text, int position) {
+            // using ordinals to avoid javac synthetic inner class
+            switch (ordinal()) {
+                case 0: context.setCaseSensitive(true); break;
+                case 1: context.setCaseSensitive(false); break;
+                case 2: context.setStrict(true); break;
+                case 3: context.setStrict(false); break;
+            }
+            return position;
+        }
+
+        @Override
+        public String toString() {
+            // using ordinals to avoid javac synthetic inner class
+            switch (ordinal()) {
+                case 0: return "ParseCaseSensitive(true)";
+                case 1: return "ParseCaseSensitive(false)";
+                case 2: return "ParseStrict(true)";
+                case 3: return "ParseStrict(false)";
+            }
+            throw new IllegalStateException("Unreachable");
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Prints or parses a character literal.
+     */
+    static final class CharLiteralPrinterParser implements DateTimePrinterParser {
+        private final char literal;
+
+        CharLiteralPrinterParser(char literal) {
+            this.literal = literal;
+        }
+
+        @Override
+        public boolean print(DateTimePrintContext context, StringBuilder buf) {
+            buf.append(literal);
+            return true;
+        }
+
+        @Override
+        public int parse(DateTimeParseContext context, CharSequence text, int position) {
+            int length = text.length();
+            if (position == length) {
+                return ~position;
+            }
+            char ch = text.charAt(position);
+            if (ch != literal) {
+                if (context.isCaseSensitive() ||
+                        (Character.toUpperCase(ch) != Character.toUpperCase(literal) &&
+                         Character.toLowerCase(ch) != Character.toLowerCase(literal))) {
+                    return ~position;
+                }
+            }
+            return position + 1;
+        }
+
+        @Override
+        public String toString() {
+            if (literal == '\'') {
+                return "''";
+            }
+            return "'" + literal + "'";
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Prints or parses a string literal.
+     */
+    static final class StringLiteralPrinterParser implements DateTimePrinterParser {
+        private final String literal;
+
+        StringLiteralPrinterParser(String literal) {
+            this.literal = literal;  // validated by caller
+        }
+
+        @Override
+        public boolean print(DateTimePrintContext context, StringBuilder buf) {
+            buf.append(literal);
+            return true;
+        }
+
+        @Override
+        public int parse(DateTimeParseContext context, CharSequence text, int position) {
+            int length = text.length();
+            if (position > length || position < 0) {
+                throw new IndexOutOfBoundsException();
+            }
+            if (context.subSequenceEquals(text, position, literal, 0, literal.length()) == false) {
+                return ~position;
+            }
+            return position + literal.length();
+        }
+
+        @Override
+        public String toString() {
+            String converted = literal.replace("'", "''");
+            return "'" + converted + "'";
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Prints and parses a numeric date-time field with optional padding.
+     */
+    static class NumberPrinterParser implements DateTimePrinterParser {
+
+        /**
+         * Array of 10 to the power of n.
+         */
+        static final int[] EXCEED_POINTS = new int[] {
+            0,
+            10,
+            100,
+            1000,
+            10000,
+            100000,
+            1000000,
+            10000000,
+            100000000,
+            1000000000,
+        };
+
+        final TemporalField field;
+        final int minWidth;
+        private final int maxWidth;
+        private final SignStyle signStyle;
+        private final int subsequentWidth;
+
+        /**
+         * Constructor.
+         *
+         * @param field  the field to print, 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
+         */
+        NumberPrinterParser(TemporalField field, int minWidth, int maxWidth, SignStyle signStyle) {
+            // validated by caller
+            this.field = field;
+            this.minWidth = minWidth;
+            this.maxWidth = maxWidth;
+            this.signStyle = signStyle;
+            this.subsequentWidth = 0;
+        }
+
+        /**
+         * Constructor.
+         *
+         * @param field  the field to print, 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
+         * @param subsequentWidth  the width of subsequent non-negative numbers, 0 or greater,
+         *  -1 if fixed width due to active adjacent parsing
+         */
+        private NumberPrinterParser(TemporalField field, int minWidth, int maxWidth, SignStyle signStyle, int subsequentWidth) {
+            // validated by caller
+            this.field = field;
+            this.minWidth = minWidth;
+            this.maxWidth = maxWidth;
+            this.signStyle = signStyle;
+            this.subsequentWidth = subsequentWidth;
+        }
+
+        /**
+         * Returns a new instance with fixed width flag set.
+         *
+         * @return a new updated printer-parser, not null
+         */
+        NumberPrinterParser withFixedWidth() {
+            return new NumberPrinterParser(field, minWidth, maxWidth, signStyle, -1);
+        }
+
+        /**
+         * Returns a new instance with an updated subsequent width.
+         *
+         * @param subsequentWidth  the width of subsequent non-negative numbers, 0 or greater
+         * @return a new updated printer-parser, not null
+         */
+        NumberPrinterParser withSubsequentWidth(int subsequentWidth) {
+            return new NumberPrinterParser(field, minWidth, maxWidth, signStyle, this.subsequentWidth + subsequentWidth);
+        }
+
+        @Override
+        public boolean print(DateTimePrintContext context, StringBuilder buf) {
+            Long valueLong = context.getValue(field);
+            if (valueLong == null) {
+                return false;
+            }
+            long value = getValue(valueLong);
+            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() +
+                    " cannot be printed as the value " + value +
+                    " exceeds the maximum print width of " + maxWidth);
+            }
+            str = symbols.convertNumberToI18N(str);
+
+            if (value >= 0) {
+                switch (signStyle) {
+                    case EXCEEDS_PAD:
+                        if (minWidth < 19 && value >= EXCEED_POINTS[minWidth]) {
+                            buf.append(symbols.getPositiveSign());
+                        }
+                        break;
+                    case ALWAYS:
+                        buf.append(symbols.getPositiveSign());
+                        break;
+                }
+            } else {
+                switch (signStyle) {
+                    case NORMAL:
+                    case EXCEEDS_PAD:
+                    case ALWAYS:
+                        buf.append(symbols.getNegativeSign());
+                        break;
+                    case NOT_NEGATIVE:
+                        throw new DateTimePrintException("Field " + field.getName() +
+                            " cannot be printed as the value " + value +
+                            " cannot be negative according to the SignStyle");
+                }
+            }
+            for (int i = 0; i < minWidth - str.length(); i++) {
+                buf.append(symbols.getZeroDigit());
+            }
+            buf.append(str);
+            return true;
+        }
+
+        /**
+         * Gets the value to output.
+         *
+         * @param value  the base value of the field, not null
+         * @return the value
+         */
+        long getValue(long value) {
+            return value;
+        }
+
+        boolean isFixedWidth() {
+            return subsequentWidth == -1;
+        }
+
+        @Override
+        public int parse(DateTimeParseContext context, CharSequence text, int position) {
+            int length = text.length();
+            if (position == length) {
+                return ~position;
+            }
+            char sign = text.charAt(position);  // IOOBE if invalid position
+            boolean negative = false;
+            boolean positive = false;
+            if (sign == context.getSymbols().getPositiveSign()) {
+                if (signStyle.parse(true, context.isStrict(), minWidth == maxWidth) == false) {
+                    return ~position;
+                }
+                positive = true;
+                position++;
+            } else if (sign == context.getSymbols().getNegativeSign()) {
+                if (signStyle.parse(false, context.isStrict(), minWidth == maxWidth) == false) {
+                    return ~position;
+                }
+                negative = true;
+                position++;
+            } else {
+                if (signStyle == SignStyle.ALWAYS && context.isStrict()) {
+                    return ~position;
+                }
+            }
+            int effMinWidth = (context.isStrict() || isFixedWidth() ? minWidth : 1);
+            int minEndPos = position + effMinWidth;
+            if (minEndPos > length) {
+                return ~position;
+            }
+            int effMaxWidth = maxWidth + Math.max(subsequentWidth, 0);
+            long total = 0;
+            BigInteger totalBig = null;
+            int pos = position;
+            for (int pass = 0; pass < 2; pass++) {
+                int maxEndPos = Math.min(pos + effMaxWidth, length);
+                while (pos < maxEndPos) {
+                    char ch = text.charAt(pos++);
+                    int digit = context.getSymbols().convertToDigit(ch);
+                    if (digit < 0) {
+                        pos--;
+                        if (pos < minEndPos) {
+                            return ~position;  // need at least min width digits
+                        }
+                        break;
+                    }
+                    if ((pos - position) > 18) {
+                        if (totalBig == null) {
+                            totalBig = BigInteger.valueOf(total);
+                        }
+                        totalBig = totalBig.multiply(BigInteger.TEN).add(BigInteger.valueOf(digit));
+                    } else {
+                        total = total * 10 + digit;
+                    }
+                }
+                if (subsequentWidth > 0 && pass == 0) {
+                    // re-parse now we know the correct width
+                    int parseLen = pos - position;
+                    effMaxWidth = Math.max(effMinWidth, parseLen - subsequentWidth);
+                    pos = position;
+                    total = 0;
+                    totalBig = null;
+                } else {
+                    break;
+                }
+            }
+            if (negative) {
+                if (totalBig != null) {
+                    if (totalBig.equals(BigInteger.ZERO) && context.isStrict()) {
+                        return ~(position - 1);  // minus zero not allowed
+                    }
+                    totalBig = totalBig.negate();
+                } else {
+                    if (total == 0 && context.isStrict()) {
+                        return ~(position - 1);  // minus zero not allowed
+                    }
+                    total = -total;
+                }
+            } else if (signStyle == SignStyle.EXCEEDS_PAD && context.isStrict()) {
+                int parseLen = pos - position;
+                if (positive) {
+                    if (parseLen <= minWidth) {
+                        return ~(position - 1);  // '+' only parsed if minWidth exceeded
+                    }
+                } else {
+                    if (parseLen > minWidth) {
+                        return ~position;  // '+' must be parsed if minWidth exceeded
+                    }
+                }
+            }
+            if (totalBig != null) {
+                if (totalBig.bitLength() > 63) {
+                    // overflow, parse 1 less digit
+                    totalBig = totalBig.divide(BigInteger.TEN);
+                    pos--;
+                }
+                setValue(context, totalBig.longValue());
+            } else {
+                setValue(context, total);
+            }
+            return pos;
+        }
+
+        /**
+         * Stores the value.
+         *
+         * @param context  the context to store into, not null
+         * @param value  the value
+         */
+        void setValue(DateTimeParseContext context, long value) {
+            context.setParsedField(field, value);
+        }
+
+        @Override
+        public String toString() {
+            if (minWidth == 1 && maxWidth == 19 && signStyle == SignStyle.NORMAL) {
+                return "Value(" + field.getName() + ")";
+            }
+            if (minWidth == maxWidth && signStyle == SignStyle.NOT_NEGATIVE) {
+                return "Value(" + field.getName() + "," + minWidth + ")";
+            }
+            return "Value(" + field.getName() + "," + minWidth + "," + maxWidth + "," + signStyle + ")";
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Prints and parses a reduced numeric date-time field.
+     */
+    static final class ReducedPrinterParser extends NumberPrinterParser {
+        private final int baseValue;
+        private final int range;
+
+        /**
+         * Constructor.
+         *
+         * @param field  the field to print, validated not null
+         * @param width  the field width, from 1 to 18
+         * @param baseValue  the base value
+         */
+        ReducedPrinterParser(TemporalField field, int width, int baseValue) {
+            super(field, width, width, SignStyle.NOT_NEGATIVE);
+            if (width < 1 || width > 18) {
+                throw new IllegalArgumentException("The width must be from 1 to 18 inclusive but was " + width);
+            }
+            if (field.range().isValidValue(baseValue) == false) {
+                throw new IllegalArgumentException("The base value must be within the range of the field");
+            }
+            this.baseValue = baseValue;
+            this.range = EXCEED_POINTS[width];
+            if ((((long) baseValue) + range) > Integer.MAX_VALUE) {
+                throw new DateTimeException("Unable to add printer-parser as the range exceeds the capacity of an int");
+            }
+        }
+
+        @Override
+        long getValue(long value) {
+            return Math.abs(value % range);
+        }
+
+        @Override
+        void setValue(DateTimeParseContext context, long value) {
+            int lastPart = baseValue % range;
+            if (baseValue > 0) {
+                value = baseValue - lastPart + value;
+            } else {
+                value = baseValue - lastPart - value;
+            }
+            if (value < baseValue) {
+                value += range;
+            }
+            context.setParsedField(field, value);
+        }
+
+        @Override
+        NumberPrinterParser withFixedWidth() {
+            return this;
+        }
+
+        @Override
+        boolean isFixedWidth() {
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            return "ReducedValue(" + field.getName() + "," + minWidth + "," + baseValue + ")";
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Prints and parses a numeric date-time field with optional padding.
+     */
+    static final class FractionPrinterParser implements DateTimePrinterParser {
+        private final TemporalField field;
+        private final int minWidth;
+        private final int maxWidth;
+        private final boolean decimalPoint;
+
+        /**
+         * Constructor.
+         *
+         * @param field  the field to output, not null
+         * @param minWidth  the minimum width to output, from 0 to 9
+         * @param maxWidth  the maximum width to output, from 0 to 9
+         * @param decimalPoint  whether to output the localized decimal point symbol
+         */
+        FractionPrinterParser(TemporalField field, int minWidth, int maxWidth, boolean decimalPoint) {
+            Objects.requireNonNull(field, "field");
+            if (field.range().isFixed() == false) {
+                throw new IllegalArgumentException("Field must have a fixed set of values: " + field.getName());
+            }
+            if (minWidth < 0 || minWidth > 9) {
+                throw new IllegalArgumentException("Minimum width must be from 0 to 9 inclusive but was " + minWidth);
+            }
+            if (maxWidth < 1 || maxWidth > 9) {
+                throw new IllegalArgumentException("Maximum width must be from 1 to 9 inclusive but was " + maxWidth);
+            }
+            if (maxWidth < minWidth) {
+                throw new IllegalArgumentException("Maximum width must exceed or equal the minimum width but " +
+                        maxWidth + " < " + minWidth);
+            }
+            this.field = field;
+            this.minWidth = minWidth;
+            this.maxWidth = maxWidth;
+            this.decimalPoint = decimalPoint;
+        }
+
+        @Override
+        public boolean print(DateTimePrintContext context, StringBuilder buf) {
+            Long value = context.getValue(field);
+            if (value == null) {
+                return false;
+            }
+            DateTimeFormatSymbols symbols = context.getSymbols();
+            BigDecimal fraction = convertToFraction(value);
+            if (fraction.scale() == 0) {  // scale is zero if value is zero
+                if (minWidth > 0) {
+                    if (decimalPoint) {
+                        buf.append(symbols.getDecimalSeparator());
+                    }
+                    for (int i = 0; i < minWidth; i++) {
+                        buf.append(symbols.getZeroDigit());
+                    }
+                }
+            } else {
+                int outputScale = Math.min(Math.max(fraction.scale(), minWidth), maxWidth);
+                fraction = fraction.setScale(outputScale, RoundingMode.FLOOR);
+                String str = fraction.toPlainString().substring(2);
+                str = symbols.convertNumberToI18N(str);
+                if (decimalPoint) {
+                    buf.append(symbols.getDecimalSeparator());
+                }
+                buf.append(str);
+            }
+            return true;
+        }
+
+        @Override
+        public int parse(DateTimeParseContext context, CharSequence text, int position) {
+            int effectiveMin = (context.isStrict() ? minWidth : 0);
+            int effectiveMax = (context.isStrict() ? maxWidth : 9);
+            int length = text.length();
+            if (position == length) {
+                // valid if whole field is optional, invalid if minimum width
+                return (effectiveMin > 0 ? ~position : position);
+            }
+            if (decimalPoint) {
+                if (text.charAt(position) != context.getSymbols().getDecimalSeparator()) {
+                    // valid if whole field is optional, invalid if minimum width
+                    return (effectiveMin > 0 ? ~position : position);
+                }
+                position++;
+            }
+            int minEndPos = position + effectiveMin;
+            if (minEndPos > length) {
+                return ~position;  // need at least min width digits
+            }
+            int maxEndPos = Math.min(position + effectiveMax, length);
+            int total = 0;  // can use int because we are only parsing up to 9 digits
+            int pos = position;
+            while (pos < maxEndPos) {
+                char ch = text.charAt(pos++);
+                int digit = context.getSymbols().convertToDigit(ch);
+                if (digit < 0) {
+                    if (pos < minEndPos) {
+                        return ~position;  // need at least min width digits
+                    }
+                    pos--;
+                    break;
+                }
+                total = total * 10 + digit;
+            }
+            BigDecimal fraction = new BigDecimal(total).movePointLeft(pos - position);
+            long value = convertFromFraction(fraction);
+            context.setParsedField(field, value);
+            return pos;
+        }
+
+        /**
+         * Converts a value for this field to a fraction between 0 and 1.
+         * <p>
+         * The fractional value is between 0 (inclusive) and 1 (exclusive).
+         * It can only be returned if the {@link java.time.temporal.TemporalField#range() value range} is fixed.
+         * The fraction is obtained by calculation from the field range using 9 decimal
+         * places and a rounding mode of {@link RoundingMode#FLOOR FLOOR}.
+         * The calculation is inaccurate if the values do not run continuously from smallest to largest.
+         * <p>
+         * For example, the second-of-minute value of 15 would be returned as 0.25,
+         * assuming the standard definition of 60 seconds in a minute.
+         *
+         * @param value  the value to convert, must be valid for this rule
+         * @return the value as a fraction within the range, from 0 to 1, not null
+         * @throws DateTimeException if the value cannot be converted to a fraction
+         */
+        private BigDecimal convertToFraction(long value) {
+            ValueRange range = field.range();
+            range.checkValidValue(value, field);
+            BigDecimal minBD = BigDecimal.valueOf(range.getMinimum());
+            BigDecimal rangeBD = BigDecimal.valueOf(range.getMaximum()).subtract(minBD).add(BigDecimal.ONE);
+            BigDecimal valueBD = BigDecimal.valueOf(value).subtract(minBD);
+            BigDecimal fraction = valueBD.divide(rangeBD, 9, RoundingMode.FLOOR);
+            // stripTrailingZeros bug
+            return fraction.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : fraction.stripTrailingZeros();
+        }
+
+        /**
+         * Converts a fraction from 0 to 1 for this field to a value.
+         * <p>
+         * The fractional value must be between 0 (inclusive) and 1 (exclusive).
+         * It can only be returned if the {@link java.time.temporal.TemporalField#range() value range} is fixed.
+         * The value is obtained by calculation from the field range and a rounding
+         * mode of {@link RoundingMode#FLOOR FLOOR}.
+         * The calculation is inaccurate if the values do not run continuously from smallest to largest.
+         * <p>
+         * For example, the fractional second-of-minute of 0.25 would be converted to 15,
+         * assuming the standard definition of 60 seconds in a minute.
+         *
+         * @param fraction  the fraction to convert, not null
+         * @return the value of the field, valid for this rule
+         * @throws DateTimeException if the value cannot be converted
+         */
+        private long convertFromFraction(BigDecimal fraction) {
+            ValueRange range = field.range();
+            BigDecimal minBD = BigDecimal.valueOf(range.getMinimum());
+            BigDecimal rangeBD = BigDecimal.valueOf(range.getMaximum()).subtract(minBD).add(BigDecimal.ONE);
+            BigDecimal valueBD = fraction.multiply(rangeBD).setScale(0, RoundingMode.FLOOR).add(minBD);
+            return valueBD.longValueExact();
+        }
+
+        @Override
+        public String toString() {
+            String decimal = (decimalPoint ? ",DecimalPoint" : "");
+            return "Fraction(" + field.getName() + "," + minWidth + "," + maxWidth + decimal + ")";
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Prints or parses field text.
+     */
+    static final class TextPrinterParser implements DateTimePrinterParser {
+        private final TemporalField field;
+        private final TextStyle textStyle;
+        private final DateTimeTextProvider provider;
+        /**
+         * The cached number printer parser.
+         * Immutable and volatile, so no synchronization needed.
+         */
+        private volatile NumberPrinterParser numberPrinterParser;
+
+        /**
+         * Constructor.
+         *
+         * @param field  the field to output, not null
+         * @param textStyle  the text style, not null
+         * @param provider  the text provider, not null
+         */
+        TextPrinterParser(TemporalField field, TextStyle textStyle, DateTimeTextProvider provider) {
+            // validated by caller
+            this.field = field;
+            this.textStyle = textStyle;
+            this.provider = provider;
+        }
+
+        @Override
+        public boolean print(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 {
+                text = provider.getText(field, value, textStyle, context.getLocale());
+            }
+            if (text == null) {
+                return numberPrinterParser().print(context, buf);
+            }
+            buf.append(text);
+            return true;
+        }
+
+        @Override
+        public int parse(DateTimeParseContext context, CharSequence parseText, int position) {
+            int length = parseText.length();
+            if (position < 0 || position > length) {
+                throw new IndexOutOfBoundsException();
+            }
+            TextStyle style = (context.isStrict() ? textStyle : null);
+            Iterator<Entry<String, Long>> it = provider.getTextIterator(field, style, context.getLocale());
+            if (it != null) {
+                while (it.hasNext()) {
+                    Entry<String, Long> 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();
+                    }
+                }
+                if (context.isStrict()) {
+                    return ~position;
+                }
+            }
+            return numberPrinterParser().parse(context, parseText, position);
+        }
+
+        /**
+         * Create and cache a number printer parser.
+         * @return the number printer parser for this field, not null
+         */
+        private NumberPrinterParser numberPrinterParser() {
+            if (numberPrinterParser == null) {
+                numberPrinterParser = new NumberPrinterParser(field, 1, 19, SignStyle.NORMAL);
+            }
+            return numberPrinterParser;
+        }
+
+        @Override
+        public String toString() {
+            if (textStyle == TextStyle.FULL) {
+                return "Text(" + field.getName() + ")";
+            }
+            return "Text(" + field.getName() + "," + textStyle + ")";
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Prints or parses an ISO-8601 instant.
+     */
+    static final class InstantPrinterParser implements DateTimePrinterParser {
+        // days in a 400 year cycle = 146097
+        // days in a 10,000 year cycle = 146097 * 25
+        // seconds per day = 86400
+        private static final long SECONDS_PER_10000_YEARS = 146097L * 25L * 86400L;
+        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')
+                    .toFormatter().toPrinterParser(false);
+
+        InstantPrinterParser() {
+        }
+
+        @Override
+        public boolean print(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);
+            if (inSecs == null || inNanos == null) {
+                return false;
+            }
+            long inSec = inSecs;
+            int inNano = NANO_OF_SECOND.checkValidIntValue(inNanos);
+            if (inSec >= -SECONDS_0000_TO_1970) {
+                // current era
+                long zeroSecs = inSec - SECONDS_PER_10000_YEARS + SECONDS_0000_TO_1970;
+                long hi = Math.floorDiv(zeroSecs, SECONDS_PER_10000_YEARS) + 1;
+                long lo = Math.floorMod(zeroSecs, SECONDS_PER_10000_YEARS);
+                LocalDateTime ldt = LocalDateTime.ofEpochSecond(lo - SECONDS_0000_TO_1970, inNano, ZoneOffset.UTC);
+                if (hi > 0) {
+                    buf.append('+').append(hi);
+                }
+                buf.append(ldt).append('Z');
+            } else {
+                // before current era
+                long zeroSecs = inSec + SECONDS_0000_TO_1970;
+                long hi = zeroSecs / SECONDS_PER_10000_YEARS;
+                long lo = zeroSecs % SECONDS_PER_10000_YEARS;
+                LocalDateTime ldt = LocalDateTime.ofEpochSecond(lo - SECONDS_0000_TO_1970, inNano, ZoneOffset.UTC);
+                int pos = buf.length();
+                buf.append(ldt).append('Z');
+                if (hi < 0) {
+                    if (ldt.getYear() == -10_000) {
+                        buf.replace(pos, pos + 2, Long.toString(hi - 1));
+                    } else if (lo == 0) {
+                        buf.insert(pos, hi);
+                    } else {
+                        buf.insert(pos + 1, Math.abs(hi));
+                    }
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public int parse(DateTimeParseContext context, CharSequence text, int position) {
+            // new context to avoid overwriting fields like year/month/day
+            DateTimeParseContext newContext = context.copy();
+            int pos = PARSER.parse(newContext, text, position);
+            if (pos < 0) {
+                return pos;
+            }
+            // parser restricts most fields to 2 digits, so definitely int
+            // correctly parsed nano is also guaranteed to be valid
+            long yearParsed = newContext.getParsed(YEAR);
+            int month = newContext.getParsed(MONTH_OF_YEAR).intValue();
+            int day = newContext.getParsed(DAY_OF_MONTH).intValue();
+            int hour = newContext.getParsed(HOUR_OF_DAY).intValue();
+            int min = newContext.getParsed(MINUTE_OF_HOUR).intValue();
+            Long secVal = newContext.getParsed(SECOND_OF_MINUTE);
+            Long nanoVal = newContext.getParsed(NANO_OF_SECOND);
+            int sec = (secVal != null ? secVal.intValue() : 0);
+            int nano = (nanoVal != null ? nanoVal.intValue() : 0);
+            int year = (int) yearParsed % 10_000;
+            long instantSecs;
+            try {
+                LocalDateTime ldt = LocalDateTime.of(year, month, day, hour, min, sec, 0);
+                instantSecs = ldt.toEpochSecond(ZoneOffset.UTC);
+                instantSecs += Math.multiplyExact(yearParsed / 10_000L, SECONDS_PER_10000_YEARS);
+            } catch (RuntimeException ex) {
+                return ~position;
+            }
+            context.setParsedField(INSTANT_SECONDS, instantSecs);
+            context.setParsedField(NANO_OF_SECOND, nano);
+            return text.length();
+        }
+
+        @Override
+        public String toString() {
+            return "Instant()";
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Prints or parses an offset ID.
+     */
+    static final class OffsetIdPrinterParser implements DateTimePrinterParser {
+        static final String[] PATTERNS = new String[] {
+            "+HH", "+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");
+
+        private final String noOffsetText;
+        private final int type;
+
+        /**
+         * Constructor.
+         *
+         * @param noOffsetText  the text to use for UTC, not null
+         * @param pattern  the pattern
+         */
+        OffsetIdPrinterParser(String noOffsetText, String pattern) {
+            Objects.requireNonNull(noOffsetText, "noOffsetText");
+            Objects.requireNonNull(pattern, "pattern");
+            this.noOffsetText = noOffsetText;
+            this.type = checkPattern(pattern);
+        }
+
+        private int checkPattern(String pattern) {
+            for (int i = 0; i < PATTERNS.length; i++) {
+                if (PATTERNS[i].equals(pattern)) {
+                    return i;
+                }
+            }
+            throw new IllegalArgumentException("Invalid zone offset pattern: " + pattern);
+        }
+
+        @Override
+        public boolean print(DateTimePrintContext context, StringBuilder buf) {
+            Long offsetSecs = context.getValue(OFFSET_SECONDS);
+            if (offsetSecs == null) {
+                return false;
+            }
+            int totalSecs = Math.toIntExact(offsetSecs);
+            if (totalSecs == 0) {
+                buf.append(noOffsetText);
+            } else {
+                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);
+                buf.append(totalSecs < 0 ? "-" : "+")
+                    .append((char) (absHours / 10 + '0')).append((char) (absHours % 10 + '0'));
+                if (type >= 1) {
+                    buf.append((type % 2) == 0 ? ":" : "")
+                        .append((char) (absMinutes / 10 + '0')).append((char) (absMinutes % 10 + '0'));
+                    if (type >= 5 || (type >= 3 && absSeconds > 0)) {
+                        buf.append((type % 2) == 0 ? ":" : "")
+                            .append((char) (absSeconds / 10 + '0')).append((char) (absSeconds % 10 + '0'));
+                    }
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public int parse(DateTimeParseContext context, CharSequence text, int position) {
+            int length = text.length();
+            int noOffsetLen = noOffsetText.length();
+            if (noOffsetLen == 0) {
+                if (position == length) {
+                    context.setParsedField(OFFSET_SECONDS, 0);
+                    return position;
+                }
+            } else {
+                if (position == length) {
+                    return ~position;
+                }
+                if (context.subSequenceEquals(text, position, noOffsetText, 0, noOffsetLen)) {
+                    context.setParsedField(OFFSET_SECONDS, 0);
+                    return position + noOffsetLen;
+                }
+            }
+
+            // parse normal plus/minus offset
+            char sign = text.charAt(position);  // IOOBE if invalid position
+            if (sign == '+' || sign == '-') {
+                // starts
+                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;
+                }
+                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;
+            }
+        }
+
+        /**
+         * Parse a two digit zero-prefixed number.
+         *
+         * @param array  the array of parsed data, 0=pos,1=hours,2=mins,3=secs, not null
+         * @param arrayIndex  the index to parse the value into
+         * @param parseText  the offset ID, not null
+         * @param required  whether this number is required
+         * @return true if an error occurred
+         */
+        private boolean parseNumber(int[] array, int arrayIndex, CharSequence parseText, boolean required) {
+            if ((type + 3) / 2 < arrayIndex) {
+                return false;  // ignore seconds/minutes
+            }
+            int pos = array[0];
+            if ((type % 2) == 0 && arrayIndex > 1) {
+                if (pos + 1 > parseText.length() || parseText.charAt(pos) != ':') {
+                    return required;
+                }
+                pos++;
+            }
+            if (pos + 2 > parseText.length()) {
+                return required;
+            }
+            char ch1 = parseText.charAt(pos++);
+            char ch2 = parseText.charAt(pos++);
+            if (ch1 < '0' || ch1 > '9' || ch2 < '0' || ch2 > '9') {
+                return required;
+            }
+            int value = (ch1 - 48) * 10 + (ch2 - 48);
+            if (value < 0 || value > 59) {
+                return required;
+            }
+            array[arrayIndex] = value;
+            array[0] = pos;
+            return false;
+        }
+
+        @Override
+        public String toString() {
+            String converted = noOffsetText.replace("'", "''");
+            return "Offset('" + converted + "'," + PATTERNS[type] + ")";
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Prints or parses a zone ID.
+     */
+    static final class ZoneTextPrinterParser implements DateTimePrinterParser {
+
+        /** The text style to output. */
+        private final TextStyle textStyle;
+
+        ZoneTextPrinterParser(TextStyle textStyle) {
+            this.textStyle = Objects.requireNonNull(textStyle, "textStyle");
+        }
+
+        private static final int STD = 0;
+        private static final int DST = 1;
+        private static final int GENERIC = 2;
+
+        private static final Map<String, SoftReference<Map<Locale, String[]>>> cache =
+            new ConcurrentHashMap<>();
+
+        private static String getDisplayName(String id, int type, TextStyle style, Locale locale) {
+            if (style == TextStyle.NARROW) {
+                return null;
+            }
+            String[] names;
+            SoftReference<Map<Locale, String[]>> ref = cache.get(id);
+            Map<Locale, String[]> perLocale;
+            if (ref == null || (perLocale = ref.get()) == null ||
+                (names = perLocale.get(locale)) == null) {
+                names = TimeZoneNameUtility.retrieveDisplayNames(id, locale);
+                if (names == null) {
+                    return null;
+                }
+                names = Arrays.copyOfRange(names, 0, 7);
+                names[5] =
+                    TimeZoneNameUtility.retrieveGenericDisplayName(id, TimeZone.LONG,locale);
+                if (names[5] == null) {
+                    names[5] = names[0]; // use the id
+                }
+                names[6] =
+                    TimeZoneNameUtility.retrieveGenericDisplayName(id, TimeZone.SHORT,locale);
+                if (names[6] == null) {
+                    names[6] = names[0];
+                }
+                perLocale = new ConcurrentHashMap<>();
+                perLocale.put(locale, names);
+                ref = new SoftReference<>(perLocale);
+                cache.put(id, ref);
+            }
+            switch (type) {
+            case STD:
+                return names[style.ordinal() + 1];
+            case DST:
+                return names[style.ordinal() + 3];
+            }
+            return names[style.ordinal() + 5];
+        }
+
+        @Override
+        public boolean print(DateTimePrintContext context, StringBuilder buf) {
+            ZoneId zone = context.getValue(Queries.zoneId());
+            if (zone == null) {
+                return false;
+            }
+            if (zone instanceof ZoneOffset) {
+                buf.append(zone.getId());
+            } else {
+                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());
+                if (name != null) {
+                    buf.append(name);
+                } else {
+                    buf.append(zone.getId());
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public int parse(DateTimeParseContext context, CharSequence text, int position) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public String toString() {
+            return "ZoneText(" + textStyle + ")";
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Prints or parses a zone ID.
+     */
+    static final class ZoneIdPrinterParser implements DateTimePrinterParser {
+        private final TemporalQuery<ZoneId> query;
+        private final String description;
+
+        ZoneIdPrinterParser(TemporalQuery<ZoneId> query, String description) {
+            this.query = query;
+            this.description = description;
+        }
+
+        //-----------------------------------------------------------------------
+        @Override
+        public boolean print(DateTimePrintContext context, StringBuilder buf) {
+            ZoneId zone = context.getValue(query);
+            if (zone == null) {
+                return false;
+            }
+            buf.append(zone.getId());
+            return true;
+        }
+
+        //-----------------------------------------------------------------------
+        /**
+         * The cached tree to speed up parsing.
+         */
+        private static volatile Entry<Integer, PrefixTree> cachedPrefixTree;
+        private static volatile Entry<Integer, PrefixTree> cachedPrefixTreeCI;
+
+        /**
+         * This implementation looks for the longest matching string.
+         * For example, parsing Etc/GMT-2 will return Etc/GMC-2 rather than just
+         * Etc/GMC although both are valid.
+         */
+        @Override
+        public int parse(DateTimeParseContext context, CharSequence text, int position) {
+            int length = text.length();
+            if (position > length) {
+                throw new IndexOutOfBoundsException();
+            }
+
+            // 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;
+                    }
+                    int offset = (int) (long) newContext.getParsed(OFFSET_SECONDS);
+                    ZoneId zone = ZoneOffset.ofTotalSeconds(offset);
+                    context.setParsed(zone);
+                    return endPos;
+                }
+            }
+
+            // prepare parse tree
+            Set<String> regionIds = ZoneRulesProvider.getAvailableZoneIds();
+            final int regionIdsSize = regionIds.size();
+            Entry<Integer, PrefixTree> 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') {
+                    context.setParsed(ZoneOffset.UTC);
+                    return position + 1;
+                }
+                return ~position;
+            }
+            context.setParsed(ZoneId.of(parsedZoneId));
+            return position + parsedZoneId.length();
+        }
+
+
+        @Override
+        public String toString() {
+            return description;
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * A String based prefix tree for parsing time-zone names.
+     */
+    static class PrefixTree {
+        protected String key;
+        protected String value;
+        protected char c0;    // performance optimization to avoid the
+                              // boundary check cost of key.charat(0)
+        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;
+            this.child = child;
+            if (k.length() == 0){
+                c0 = 0xffff;
+            } else {
+                c0 = key.charAt(0);
+            }
+        }
+
+        /**
+         * Creates a new prefix parsing tree.
+         *
+         * @param type  the type of the prefix tree. One of the three supported
+         *  types, STRICT, CASE_INSENSITIVE and LENIENT
+         * @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");
+            }
+            return tree;
+        }
+
+        /**
+         * 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
+         * @return the tree, not null
+         */
+        public static  PrefixTree newTree(Set<String> keys, int type) {
+            PrefixTree tree = newTree(type);
+            for (String k : keys) {
+                tree.add0(k, k);
+            }
+            return tree;
+        }
+
+        /**
+         * Adds a pair of {key, value} into the prefix tree.
+         *
+         * @param k  the key, not null
+         * @param v  the value, not null
+         * @return  true if the pair is added successfully
+         */
+        public boolean add(String k, String v) {
+            return add0(k, v);
+        }
+
+        private boolean add0(String k, String v) {
+            k = toKey(k);
+            int prefixLen = prefixLength(k);
+            if (prefixLen == key.length()) {
+                if (prefixLen < k.length()) {  // down the tree
+                    String subKey = k.substring(prefixLen);
+                    PrefixTree c = child;
+                    while (c != null) {
+                        if (isEqual(c.c0, subKey.charAt(0))) {
+                            return c.add0(subKey, v);
+                        }
+                        c = c.sibling;
+                    }
+                    // add the node as the child of the current node
+                    c = newNode(subKey, v, null);
+                    c.sibling = child;
+                    child = c;
+                    return true;
+                }
+                // have an existing <key, value> already, keep it.
+                if (value != null) {
+                    return false;
+                }
+                value = v;
+                return true;
+            }
+            // split the existing node
+            PrefixTree n1 = newNode(key.substring(prefixLen), value, child);
+            key = k.substring(0, prefixLen);
+            child = n1;
+            if (prefixLen < k.length()) {
+                PrefixTree n2 = newNode(k.substring(prefixLen), v, null);
+                child.sibling = n2;
+                value = null;
+            } else {
+                value = v;
+            }
+            return true;
+        }
+
+        /**
+         * Match text with the prefix tree.
+         *
+         * @param text  the input text to parse, not null
+         * @param off  the offset position to start parsing at
+         * @param end  the end position to stop parsing
+         * @return the resulting string, or null if no match found.
+         */
+        public String match(CharSequence text, int off, int end) {
+            if (!prefixOf(text, off, end)){
+                return null;
+            }
+            if (child != null && (off += key.length()) != end) {
+                PrefixTree c = child;
+                do {
+                    if (isEqual(c.c0, text.charAt(off))) {
+                        String found = c.match(text, off, end);
+                        if (found != null) {
+                            return found;
+                        }
+                        return value;
+                    }
+                    c = c.sibling;
+                } while (c != null);
+            }
+            return value;
+        }
+
+        /**
+         * Match text with the prefix tree.
+         *
+         * @param text  the input text to parse, not null
+         * @param pos  the position to start parsing at, from 0 to the text
+         *  length. Upon return, position will be updated to the new parse
+         *  position, or unchanged, if no match found.
+         * @return the resulting string, or null if no match found.
+         */
+        public String match(CharSequence text, ParsePosition pos) {
+            int off = pos.getIndex();
+            int end = text.length();
+            if (!prefixOf(text, off, end)){
+                return null;
+            }
+            off += key.length();
+            if (child != null && off != end) {
+                PrefixTree c = child;
+                do {
+                    if (isEqual(c.c0, text.charAt(off))) {
+                        pos.setIndex(off);
+                        String found = c.match(text, pos);
+                        if (found != null) {
+                            return found;
+                        }
+                        break;
+                    }
+                    c = c.sibling;
+                } while (c != null);
+            }
+            pos.setIndex(off);
+            return value;
+        }
+
+        protected String toKey(String k) {
+            return k;
+        }
+
+        protected PrefixTree newNode(String k, String v, PrefixTree child) {
+            return new PrefixTree(k, v, child);
+        }
+
+        protected boolean isEqual(char c1, char c2) {
+            return c1 == c2;
+        }
+
+        protected boolean prefixOf(CharSequence text, int off, int end) {
+            if (text instanceof String) {
+                return ((String)text).startsWith(key, off);
+            }
+            int len = key.length();
+            if (len > end - off) {
+                return false;
+            }
+            int off0 = 0;
+            while (len-- > 0) {
+                if (!isEqual(key.charAt(off0++), text.charAt(off++))) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        private int prefixLength(String k) {
+            int off = 0;
+            while (off < k.length() && off < key.length()) {
+                if (!isEqual(k.charAt(off), key.charAt(off))) {
+                    return off;
+                }
+                off++;
+            }
+            return off;
+        }
+
+        /**
+         * Case Insensitive prefix tree.
+         */
+        private static class CI extends PrefixTree {
+
+            private CI(String k, String v, PrefixTree child) {
+                super(k, v, child);
+            }
+
+            @Override
+            protected CI newNode(String k, String v, PrefixTree child) {
+                return new CI(k, v, child);
+            }
+
+            @Override
+            protected boolean isEqual(char c1, char c2) {
+                return c1 == c2 ||
+                       Character.toUpperCase(c1) == Character.toUpperCase(c2) ||
+                       Character.toLowerCase(c1) == Character.toLowerCase(c2);
+            }
+
+            @Override
+            protected boolean prefixOf(CharSequence text, int off, int end) {
+                int len = key.length();
+                if (len > end - off) {
+                    return false;
+                }
+                int off0 = 0;
+                while (len-- > 0) {
+                    if (!isEqual(key.charAt(off0++), text.charAt(off++))) {
+                        return false;
+                    }
+                }
+                return true;
+            }
+        }
+
+        /**
+         * Lenient prefix tree. Case insensitive and ignores characters
+         * like space, underscore and slash.
+         */
+        private static class LENIENT extends CI {
+
+            private LENIENT(String k, String v, PrefixTree child) {
+                super(k, v, child);
+            }
+
+            @Override
+            protected CI newNode(String k, String v, PrefixTree child) {
+                return new LENIENT(k, v, child);
+            }
+
+            private boolean isLenientChar(char c) {
+                return c == ' ' || c == '_' || c == '/';
+            }
+
+            protected String toKey(String k) {
+                for (int i = 0; i < k.length(); i++) {
+                    if (isLenientChar(k.charAt(i))) {
+                        StringBuilder sb = new StringBuilder(k.length());
+                        sb.append(k, 0, i);
+                        i++;
+                        while (i < k.length()) {
+                            if (!isLenientChar(k.charAt(i))) {
+                                sb.append(k.charAt(i));
+                            }
+                            i++;
+                        }
+                        return sb.toString();
+                    }
+                }
+                return k;
+            }
+
+            @Override
+            public String match(CharSequence text, ParsePosition pos) {
+                int off = pos.getIndex();
+                int end = text.length();
+                int len = key.length();
+                int koff = 0;
+                while (koff < len && off < end) {
+                    if (isLenientChar(text.charAt(off))) {
+                        off++;
+                        continue;
+                    }
+                    if (!isEqual(key.charAt(koff++), text.charAt(off++))) {
+                        return null;
+                    }
+                }
+                if (koff != len) {
+                    return null;
+                }
+                if (child != null && off != end) {
+                    int off0 = off;
+                    while (off0 < end && isLenientChar(text.charAt(off0))) {
+                        off0++;
+                    }
+                    if (off0 < end) {
+                        PrefixTree c = child;
+                        do {
+                            if (isEqual(c.c0, text.charAt(off0))) {
+                                pos.setIndex(off0);
+                                String found = c.match(text, pos);
+                                if (found != null) {
+                                    return found;
+                                }
+                                break;
+                            }
+                            c = c.sibling;
+                        } while (c != null);
+                    }
+                }
+                pos.setIndex(off);
+                return value;
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Prints or parses a chronology.
+     */
+    static final class ChronoPrinterParser implements DateTimePrinterParser {
+        /** The text style to output, null means the ID. */
+        private final TextStyle textStyle;
+
+        ChronoPrinterParser(TextStyle textStyle) {
+            // validated by caller
+            this.textStyle = textStyle;
+        }
+
+        @Override
+        public boolean print(DateTimePrintContext context, StringBuilder buf) {
+            Chrono<?> chrono = context.getValue(Queries.chrono());
+            if (chrono == null) {
+                return false;
+            }
+            if (textStyle == null) {
+                buf.append(chrono.getId());
+            } else {
+                buf.append(chrono.getId());  // TODO: Use symbols
+            }
+            return true;
+        }
+
+        @Override
+        public int parse(DateTimeParseContext context, CharSequence text, int position) {
+            return ~position;  // TODO, including case insensitive
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Prints or parses a localized pattern.
+     */
+    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) {
+            // 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);
+        }
+
+        @Override
+        public int parse(DateTimeParseContext context, CharSequence text, int position) {
+            return formatter(context.getLocale()).toPrinterParser(false).parse(context, text, position);
+        }
+
+        /**
+         * Gets the formatter to use.
+         *
+         * @param locale  the locale to use, not null
+         * @return the formatter, not null
+         * @throws IllegalArgumentException if the formatter cannot be found
+         */
+        private DateTimeFormatter formatter(Locale locale) {
+            return DateTimeFormatStyleProvider.getInstance()
+                                              .getFormatter(dateStyle, timeStyle, chrono, locale);
+        }
+
+        @Override
+        public String toString() {
+            return "Localized(" + (dateStyle != null ? dateStyle : "") + "," +
+                (timeStyle != null ? timeStyle : "") + "," + chrono.getId() + ")";
+        }
+    }
+
+
+    //-----------------------------------------------------------------------
+    /**
+     * Prints or parses a localized pattern from a localized field.
+     * The specific formatter and parameters is not selected until the
+     * the field is to be printed or parsed.
+     * The locale is needed to select the proper WeekFields from which
+     * the field for day-of-week, week-of-month, or week-of-year is selected.
+     */
+    static final class WeekBasedFieldPrinterParser implements DateTimePrinterParser {
+        private char chr;
+        private int count;
+
+        /**
+         * Constructor.
+         *
+         * @param chr the pattern format letter that added this PrinterParser.
+         * @param count the repeat count of the format letter
+         */
+        WeekBasedFieldPrinterParser(char chr, int count) {
+            this.chr = chr;
+            this.count = count;
+        }
+
+        @Override
+        public boolean print(DateTimePrintContext context, StringBuilder buf) {
+            return printerParser(context.getLocale()).print(context, buf);
+        }
+
+        @Override
+        public int parse(DateTimeParseContext context, CharSequence text, int position) {
+            return printerParser(context.getLocale()).parse(context, text, position);
+        }
+
+        /**
+         * Gets the printerParser to use based on the field and the locale.
+         *
+         * @param locale  the locale to use, not null
+         * @return the formatter, not null
+         * @throws IllegalArgumentException if the formatter cannot be found
+         */
+        private DateTimePrinterParser printerParser(Locale locale) {
+            WeekFields weekDef = WeekFields.of(locale);
+            TemporalField field = null;
+            switch (chr) {
+                case 'e':
+                    field = weekDef.dayOfWeek();
+                    break;
+                case 'w':
+                    field = weekDef.weekOfMonth();
+                    break;
+                case 'W':
+                    field = weekDef.weekOfYear();
+                    break;
+                default:
+                    throw new IllegalStateException("unreachable");
+            }
+            return new NumberPrinterParser(field, (count == 2 ? 2 : 1), 2, SignStyle.NOT_NEGATIVE);
+        }
+
+        @Override
+        public String toString() {
+            return String.format("WeekBased(%c%d)", chr, count);
+        }
+    }
+
+
+    //-------------------------------------------------------------------------
+    /**
+     * Length comparator.
+     */
+    static final Comparator<String> LENGTH_SORT = new Comparator<String>() {
+        @Override
+        public int compare(String str1, String str2) {
+            return str1.length() == str2.length() ? str1.compareTo(str2) : str1.length() - str2.length();
+        }
+    };
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/format/DateTimeFormatters.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,972 @@
+/*
+ * 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}.
+ * <p>
+ * This utility class provides three different ways to obtain a formatter.
+ * <p><ul>
+ * <li>Using pattern letters, such as {@code yyyy-MMM-dd}
+ * <li>Using localized styles, such as {@code long} or {@code medium}
+ * <li>Using predefined constants, such as {@code isoLocalDate()}
+ * </ul><p>
+ *
+ * <h3>Specification for implementors</h3>
+ * 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.
+     * <p>
+     * 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'.
+     * <p>
+     * The returned formatter will use the default locale, but this can be changed
+     * using {@link DateTimeFormatter#withLocale(Locale)}.
+     * <p>
+     * All letters 'A' to 'Z' and 'a' to 'z' are reserved as pattern letters.
+     * The following pattern letters are defined:
+     * <pre>
+     *  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
+     * </pre>
+     * <p>
+     * The count of pattern letters determine the format.
+     * <p>
+     * <b>Text</b>: 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}.
+     * <p>
+     * <b>Number</b>: 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)}.
+     * <p>
+     * <b>Number/Text</b>: If the count of pattern letters is 3 or greater, use the Text rules above.
+     * Otherwise use the Number rules above.
+     * <p>
+     * <b>Fraction</b>: 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.
+     * <p>
+     * <b>Year</b>: 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}
+     * <p>
+     * <b>ZoneId</b>: 'I' outputs the zone ID, such as 'Europe/Paris'.
+     * <p>
+     * <b>Offset X</b>: 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'.
+     * <p>
+     * <b>Offset Z</b>: 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'.
+     * <p>
+     * <b>Zone names</b>: Time zone names ('z') cannot be parsed.
+     * <p>
+     * <b>Optional section</b>: The optional section markers work exactly like calling
+     * {@link DateTimeFormatterBuilder#optionalStart()} and {@link DateTimeFormatterBuilder#optionalEnd()}.
+     * <p>
+     * <b>Pad modifier</b>: 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)}.
+     * <p>
+     * For example, 'ppH' outputs the hour-of-day padded on the left with spaces to a width of 2.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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'.
+     * <p>
+     * See {@link #pattern(String)} for details of the pattern.
+     * <p>
+     * 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.
+     * <p>
+     * This returns a formatter that will print/parse a date.
+     * The exact format pattern used varies by locale.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * This returns a formatter that will print/parse a time.
+     * The exact format pattern used varies by locale.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * This returns a formatter that will print/parse a date-time.
+     * The exact format pattern used varies by locale.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * This returns a formatter that will print/parse a date-time.
+     * The exact format pattern used varies by locale.
+     * <p>
+     * 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.
+     * <p>
+     * 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'.
+     * <p>
+     * This returns an immutable formatter capable of printing and parsing
+     * the ISO-8601 extended local date format.
+     * The format consists of:
+     * <p><ul>
+     * <li>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.
+     * <li>A dash
+     * <li>Two digits for the {@link ChronoField#MONTH_OF_YEAR month-of-year}.
+     *  This is pre-padded by zero to ensure two digits.
+     * <li>A dash
+     * <li>Two digits for the {@link ChronoField#DAY_OF_MONTH day-of-month}.
+     *  This is pre-padded by zero to ensure two digits.
+     * </ul><p>
+     *
+     * @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'.
+     * <p>
+     * This returns an immutable formatter capable of printing and parsing
+     * the ISO-8601 extended offset date format.
+     * The format consists of:
+     * <p><ul>
+     * <li>The {@link #isoLocalDate()}
+     * <li>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.
+     * </ul><p>
+     *
+     * @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'.
+     * <p>
+     * This returns an immutable formatter capable of printing and parsing
+     * the ISO-8601 extended date format.
+     * The format consists of:
+     * <p><ul>
+     * <li>The {@link #isoLocalDate()}
+     * <li>If the offset is not available to print/parse then the format is complete.
+     * <li>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.
+     * </ul><p>
+     * 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'.
+     * <p>
+     * This returns an immutable formatter capable of printing and parsing
+     * the ISO-8601 extended local time format.
+     * The format consists of:
+     * <p><ul>
+     * <li>Two digits for the {@link ChronoField#HOUR_OF_DAY hour-of-day}.
+     *  This is pre-padded by zero to ensure two digits.
+     * <li>A colon
+     * <li>Two digits for the {@link ChronoField#MINUTE_OF_HOUR minute-of-hour}.
+     *  This is pre-padded by zero to ensure two digits.
+     * <li>If the second-of-minute is not available to print/parse then the format is complete.
+     * <li>A colon
+     * <li>Two digits for the {@link ChronoField#SECOND_OF_MINUTE second-of-minute}.
+     *  This is pre-padded by zero to ensure two digits.
+     * <li>If the nano-of-second is zero or not available to print/parse then the format is complete.
+     * <li>A decimal point
+     * <li>One to nine digits for the {@link ChronoField#NANO_OF_SECOND nano-of-second}.
+     *  As many digits will be printed as required.
+     * </ul><p>
+     *
+     * @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'.
+     * <p>
+     * This returns an immutable formatter capable of printing and parsing
+     * the ISO-8601 extended offset time format.
+     * The format consists of:
+     * <p><ul>
+     * <li>The {@link #isoLocalTime()}
+     * <li>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.
+     * </ul><p>
+     *
+     * @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'.
+     * <p>
+     * This returns an immutable formatter capable of printing and parsing
+     * the ISO-8601 extended offset time format.
+     * The format consists of:
+     * <p><ul>
+     * <li>The {@link #isoLocalTime()}
+     * <li>If the offset is not available to print/parse then the format is complete.
+     * <li>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.
+     * </ul><p>
+     * 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'.
+     * <p>
+     * This returns an immutable formatter capable of printing and parsing
+     * the ISO-8601 extended offset date-time format.
+     * The format consists of:
+     * <p><ul>
+     * <li>The {@link #isoLocalDate()}
+     * <li>The letter 'T'. Parsing is case insensitive.
+     * <li>The {@link #isoLocalTime()}
+     * </ul><p>
+     *
+     * @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'.
+     * <p>
+     * This returns an immutable formatter capable of printing and parsing
+     * the ISO-8601 extended offset date-time format.
+     * The format consists of:
+     * <p><ul>
+     * <li>The {@link #isoLocalDateTime()}
+     * <li>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.
+     * </ul><p>
+     *
+     * @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]'.
+     * <p>
+     * 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:
+     * <p><ul>
+     * <li>The {@link #isoOffsetDateTime()}
+     * <li>If the zone ID is not available or is a {@code ZoneOffset} then the format is complete.
+     * <li>An open square bracket '['.
+     * <li>The {@link ZoneId#getId() zone ID}. This is not part of the ISO-8601 standard.
+     *  Parsing is case sensitive.
+     * <li>A close square bracket ']'.
+     * </ul><p>
+     *
+     * @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]'.
+     * <p>
+     * This returns an immutable formatter capable of printing and parsing
+     * the ISO-8601 extended offset date-time format.
+     * The format consists of:
+     * <p><ul>
+     * <li>The {@link #isoLocalDateTime()}
+     * <li>If the offset is not available to print/parse then the format is complete.
+     * <li>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.
+     * <li>If the zone ID is not available or is a {@code ZoneOffset} then the format is complete.
+     * <li>An open square bracket '['.
+     * <li>The {@link ZoneId#getId() zone ID}. This is not part of the ISO-8601 standard.
+     *  Parsing is case sensitive.
+     * <li>A close square bracket ']'.
+     * </ul><p>
+     * 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'.
+     * <p>
+     * This returns an immutable formatter capable of printing and parsing
+     * the ISO-8601 extended ordinal date format.
+     * The format consists of:
+     * <p><ul>
+     * <li>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.
+     * <li>A dash
+     * <li>Three digits for the {@link ChronoField#DAY_OF_YEAR day-of-year}.
+     *  This is pre-padded by zero to ensure three digits.
+     * <li>If the offset is not available to print/parse then the format is complete.
+     * <li>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.
+     * </ul><p>
+     * 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'.
+     * <p>
+     * This returns an immutable formatter capable of printing and parsing
+     * the ISO-8601 extended week-based date format.
+     * The format consists of:
+     * <p><ul>
+     * <li>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.
+     * <li>A dash
+     * <li>The letter 'W'. Parsing is case insensitive.
+     * <li>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.
+     * <li>A dash
+     * <li>One digit for the {@link ChronoField#DAY_OF_WEEK day-of-week}.
+     *  The value run from Monday (1) to Sunday (7).
+     * <li>If the offset is not available to print/parse then the format is complete.
+     * <li>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.
+     * </ul><p>
+     * 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.
+     * <p>
+     * This returns an immutable formatter capable of printing and parsing
+     * the ISO-8601 instant format.
+     * The format consists of:
+     * <p><ul>
+     * <li>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.
+     * </ul><p>
+     *
+     * @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'.
+     * <p>
+     * This returns an immutable formatter capable of printing and parsing
+     * the ISO-8601 basic local date format.
+     * The format consists of:
+     * <p><ul>
+     * <li>Four digits for the {@link ChronoField#YEAR year}.
+     *  Only years in the range 0000 to 9999 are supported.
+     * <li>Two digits for the {@link ChronoField#MONTH_OF_YEAR month-of-year}.
+     *  This is pre-padded by zero to ensure two digits.
+     * <li>Two digits for the {@link ChronoField#DAY_OF_MONTH day-of-month}.
+     *  This is pre-padded by zero to ensure two digits.
+     * <li>If the offset is not available to print/parse then the format is complete.
+     * <li>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.
+     * </ul><p>
+     * 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'.
+     * <p>
+     * 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.
+     * <p>
+     * The format consists of:
+     * <p><ul>
+     * <li>If the day-of-week is not available to print/parse then jump to day-of-month.
+     * <li>Three letter {@link ChronoField#DAY_OF_WEEK day-of-week} in English.
+     * <li>A comma
+     * <li>A space
+     * <li>One or two digits for the {@link ChronoField#DAY_OF_MONTH day-of-month}.
+     * <li>A space
+     * <li>Three letter {@link ChronoField#MONTH_OF_YEAR month-of-year} in English.
+     * <li>A space
+     * <li>Four digits for the {@link ChronoField#YEAR year}.
+     *  Only years in the range 0000 to 9999 are supported.
+     * <li>A space
+     * <li>Two digits for the {@link ChronoField#HOUR_OF_DAY hour-of-day}.
+     *  This is pre-padded by zero to ensure two digits.
+     * <li>A colon
+     * <li>Two digits for the {@link ChronoField#MINUTE_OF_HOUR minute-of-hour}.
+     *  This is pre-padded by zero to ensure two digits.
+     * <li>If the second-of-minute is not available to print/parse then jump to the next space.
+     * <li>A colon
+     * <li>Two digits for the {@link ChronoField#SECOND_OF_MINUTE second-of-minute}.
+     *  This is pre-padded by zero to ensure two digits.
+     * <li>A space
+     * <li>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.
+     * </ul><p>
+     * 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<Long, String> 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<Long, String> 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();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/format/DateTimeParseContext.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,409 @@
+/*
+ * 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.time.temporal.TemporalField;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Objects;
+
+/**
+ * Context object used during date and time parsing.
+ * <p>
+ * This class represents the current state of the parse.
+ * It has the ability to store and retrieve the parsed values and manage optional segments.
+ * It also provides key information to the parsing methods.
+ * <p>
+ * Once parsing is complete, the {@link #toBuilder()} is typically used
+ * to obtain a builder that can combine the separate parsed fields into meaningful values.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is a mutable context intended for use from a single thread.
+ * Usage of the class is thread-safe within standard parsing as a new instance of this class
+ * is automatically created for each parse and parsing is single-threaded
+ *
+ * @since 1.8
+ */
+final class DateTimeParseContext {
+
+    /**
+     * The formatter, not null.
+     */
+    private DateTimeFormatter formatter;
+    /**
+     * Whether to parse using case sensitively.
+     */
+    private boolean caseSensitive = true;
+    /**
+     * Whether to parse using strict rules.
+     */
+    private boolean strict = true;
+    /**
+     * The list of parsed data.
+     */
+    private final ArrayList<Parsed> parsed = new ArrayList<>();
+
+    /**
+     * Creates a new instance of the context.
+     *
+     * @param formatter  the formatter controlling the parse, not null
+     */
+    DateTimeParseContext(DateTimeFormatter formatter) {
+        super();
+        this.formatter = formatter;
+        parsed.add(new Parsed());
+    }
+
+    /**
+     * Creates a copy of this context.
+     */
+    DateTimeParseContext copy() {
+        return new DateTimeParseContext(formatter);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the locale.
+     * <p>
+     * This locale is used to control localization in the parse except
+     * where localization is controlled by the symbols.
+     *
+     * @return the locale, not null
+     */
+    public Locale getLocale() {
+        return formatter.getLocale();
+    }
+
+    /**
+     * Gets the formatting symbols.
+     * <p>
+     * The symbols control the localization of numeric parsing.
+     *
+     * @return the formatting symbols, not null
+     */
+    public DateTimeFormatSymbols getSymbols() {
+        return formatter.getSymbols();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if parsing is case sensitive.
+     *
+     * @return true if parsing is case sensitive, false if case insensitive
+     */
+    public boolean isCaseSensitive() {
+        return caseSensitive;
+    }
+
+    /**
+     * Sets whether the parsing is case sensitive or not.
+     *
+     * @param caseSensitive  changes the parsing to be case sensitive or not from now on
+     */
+    public void setCaseSensitive(boolean caseSensitive) {
+        this.caseSensitive = caseSensitive;
+    }
+
+    /**
+     * Helper to compare two {@code CharSequence} instances.
+     * This uses {@link #isCaseSensitive()}.
+     *
+     * @param cs1  the first character sequence, not null
+     * @param offset1  the offset into the first sequence, valid
+     * @param cs2  the second character sequence, not null
+     * @param offset2  the offset into the second sequence, valid
+     * @param length  the length to check, valid
+     * @return true if equal
+     */
+    public boolean subSequenceEquals(CharSequence cs1, int offset1, CharSequence cs2, int offset2, int length) {
+        if (offset1 + length > cs1.length() || offset2 + length > cs2.length()) {
+            return false;
+        }
+        if (isCaseSensitive()) {
+            for (int i = 0; i < length; i++) {
+                char ch1 = cs1.charAt(offset1 + i);
+                char ch2 = cs2.charAt(offset2 + i);
+                if (ch1 != ch2) {
+                    return false;
+                }
+            }
+        } else {
+            for (int i = 0; i < length; i++) {
+                char ch1 = cs1.charAt(offset1 + i);
+                char ch2 = cs2.charAt(offset2 + i);
+                if (ch1 != ch2 && Character.toUpperCase(ch1) != Character.toUpperCase(ch2) &&
+                        Character.toLowerCase(ch1) != Character.toLowerCase(ch2)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if parsing is strict.
+     * <p>
+     * Strict parsing requires exact matching of the text and sign styles.
+     *
+     * @return true if parsing is strict, false if lenient
+     */
+    public boolean isStrict() {
+        return strict;
+    }
+
+    /**
+     * Sets whether parsing is strict or lenient.
+     *
+     * @param strict  changes the parsing to be strict or lenient from now on
+     */
+    public void setStrict(boolean strict) {
+        this.strict = strict;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Starts the parsing of an optional segment of the input.
+     */
+    void startOptional() {
+        parsed.add(currentParsed().copy());
+    }
+
+    /**
+     * Ends the parsing of an optional segment of the input.
+     *
+     * @param successful  whether the optional segment was successfully parsed
+     */
+    void endOptional(boolean successful) {
+        if (successful) {
+            parsed.remove(parsed.size() - 2);
+        } else {
+            parsed.remove(parsed.size() - 1);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the currently active temporal objects.
+     *
+     * @return the current temporal objects, not null
+     */
+    private Parsed currentParsed() {
+        return parsed.get(parsed.size() - 1);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the first value that was parsed for the specified field.
+     * <p>
+     * This searches the results of the parse, returning the first value found
+     * for the specified field. No attempt is made to derive a value.
+     * The field may have an out of range value.
+     * For example, the day-of-month might be set to 50, or the hour to 1000.
+     *
+     * @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.
+     * <p>
+     * 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> T getParsed(Class<T> 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<Object> getParsed() {
+        // package scoped for testing
+        return currentParsed().parsed;
+    }
+
+    /**
+     * Stores the parsed field.
+     * <p>
+     * This stores a field-value pair that has been parsed.
+     * The value stored may be out of range for the field - no checks are performed.
+     *
+     * @param field  the field to set in the field-value map, not null
+     * @param value  the value to set in the field-value map
+     */
+    public void setParsedField(TemporalField field, long value) {
+        Objects.requireNonNull(field, "field");
+        currentParsed().parsed.add(new FieldValue(field, value));
+    }
+
+    /**
+     * Stores the parsed complete object.
+     * <p>
+     * This stores a complete object that has been parsed.
+     * No validation is performed on the date-time other than ensuring it is not null.
+     *
+     * @param object  the parsed object, not null
+     */
+    public <T> void setParsed(Object object) {
+        Objects.requireNonNull(object, "object");
+        currentParsed().parsed.add(object);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a {@code DateTimeBuilder} that can be used to interpret
+     * the results of the parse.
+     * <p>
+     * This method is typically used once parsing is complete to obtain the parsed data.
+     * Parsing will typically result in separate fields, such as year, month and day.
+     * The returned builder can be used to combine the parsed data into meaningful
+     * objects such as {@code LocalDate}, potentially applying complex processing
+     * to handle invalid parsed data.
+     *
+     * @return a new builder with the results of the parse, not null
+     */
+    public DateTimeBuilder toBuilder() {
+        List<Object> cals = currentParsed().parsed;
+        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);
+            }
+        }
+        return builder;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a string version of the context for debugging.
+     *
+     * @return a string representation of the context data, not null
+     */
+    @Override
+    public String toString() {
+        return currentParsed().toString();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Temporary store of parsed data.
+     */
+    private static final class Parsed {
+        final List<Object> parsed = new ArrayList<>();
+        private Parsed() {
+        }
+        protected Parsed copy() {
+            Parsed cloned = new Parsed();
+            cloned.parsed.addAll(this.parsed);
+            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;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/format/DateTimeParseException.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.time.DateTimeException;
+
+/**
+ * An exception thrown when an error occurs during parsing.
+ * <p>
+ * This exception includes the text being parsed and the error index.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is intended for use in a single thread.
+ *
+ * @since 1.8
+ */
+public class DateTimeParseException extends DateTimeException {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 4304633501674722597L;
+
+    /**
+     * The text that was being parsed.
+     */
+    private final String parsedString;
+    /**
+     * The error index in the text.
+     */
+    private final int errorIndex;
+
+    /**
+     * Constructs a new exception with the specified message.
+     *
+     * @param message  the message to use for this exception, may be null
+     * @param parsedData  the parsed text, should not be null
+     * @param errorIndex  the index in the parsed string that was invalid, should be a valid index
+     */
+    public DateTimeParseException(String message, CharSequence parsedData, int errorIndex) {
+        super(message);
+        this.parsedString = parsedData.toString();
+        this.errorIndex = errorIndex;
+    }
+
+    /**
+     * Constructs a new exception with the specified message and cause.
+     *
+     * @param message  the message to use for this exception, may be null
+     * @param parsedData  the parsed text, should not be null
+     * @param errorIndex  the index in the parsed string that was invalid, should be a valid index
+     * @param cause  the cause exception, may be null
+     */
+    public DateTimeParseException(String message, CharSequence parsedData, int errorIndex, Throwable cause) {
+        super(message, cause);
+        this.parsedString = parsedData.toString();
+        this.errorIndex = errorIndex;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns the string that was being parsed.
+     *
+     * @return the string that was being parsed, should not be null.
+     */
+    public String getParsedString() {
+        return parsedString;
+    }
+
+    /**
+     * Returns the index where the error was found.
+     *
+     * @return the index in the parsed string that was invalid, should be a valid index
+     */
+    public int getErrorIndex() {
+        return errorIndex;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/format/DateTimePrintContext.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.format;
+
+import static java.time.temporal.ChronoField.EPOCH_DAY;
+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.temporal.ChronoField;
+import java.time.temporal.ChronoLocalDate;
+import java.time.temporal.Queries;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.ValueRange;
+import java.util.Locale;
+import java.util.Objects;
+
+/**
+ * Context object used during date and time printing.
+ * <p>
+ * This class provides a single wrapper to items used in the print.
+ *
+ * <h3>Specification for implementors</h3>
+ * 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.
+ *
+ * @since 1.8
+ */
+final class DateTimePrintContext {
+
+    /**
+     * The temporal being output.
+     */
+    private TemporalAccessor temporal;
+    /**
+     * The formatter, not null.
+     */
+    private DateTimeFormatter formatter;
+    /**
+     * Whether the current formatter is optional.
+     */
+    private int optional;
+
+    /**
+     * 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
+     */
+    DateTimePrintContext(TemporalAccessor temporal, DateTimeFormatter formatter) {
+        super();
+        this.temporal = adjust(temporal, formatter);
+        this.formatter = formatter;
+    }
+
+    private static TemporalAccessor adjust(final TemporalAccessor temporal, DateTimeFormatter formatter) {
+        // normal case first
+        Chrono<?> overrideChrono = formatter.getChrono();
+        ZoneId overrideZone = formatter.getZone();
+        if (overrideChrono == null && overrideZone == null) {
+            return temporal;
+        }
+
+        // ensure minimal change
+        Chrono<?> temporalChrono = Chrono.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;
+        }
+        if (temporal.isSupported(INSTANT_SECONDS) == false || Objects.equals(overrideZone, temporalZone)) {
+            overrideZone = null;
+        }
+        if (overrideChrono == null && overrideZone == null) {
+            return temporal;
+        }
+
+        // make adjustment
+        if (overrideChrono != null && overrideZone != null) {
+            return overrideChrono.zonedDateTime(Instant.from(temporal), overrideZone);
+        } 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);
+            return new TemporalAccessor() {
+                @Override
+                public boolean isSupported(TemporalField field) {
+                    return temporal.isSupported(field);
+                }
+                @Override
+                public ValueRange range(TemporalField field) {
+                    if (field instanceof ChronoField) {
+                        if (((ChronoField) field).isDateField()) {
+                            return date.range(field);
+                        } else {
+                            return temporal.range(field);
+                        }
+                    }
+                    return field.doRange(this);
+                }
+                @Override
+                public long getLong(TemporalField field) {
+                    if (field instanceof ChronoField) {
+                        if (((ChronoField) field).isDateField()) {
+                            return date.getLong(field);
+                        } else {
+                            return temporal.getLong(field);
+                        }
+                    }
+                    return field.doGet(this);
+                }
+                @Override
+                public <R> R query(TemporalQuery<R> query) {
+                    if (query == Queries.zoneId() || query == Queries.chrono() || query == Queries.precision()) {
+                        return temporal.query(query);
+                    }
+                    return query.queryFrom(this);
+                }
+            };
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the temporal object being output.
+     *
+     * @return the temporal object, not null
+     */
+    TemporalAccessor getTemporal() {
+        return temporal;
+    }
+
+    /**
+     * Gets the locale.
+     * <p>
+     * This locale is used to control localization in the print output except
+     * where localization is controlled by the symbols.
+     *
+     * @return the locale, not null
+     */
+    Locale getLocale() {
+        return formatter.getLocale();
+    }
+
+    /**
+     * Gets the formatting symbols.
+     * <p>
+     * The symbols control the localization of numeric output.
+     *
+     * @return the formatting symbols, not null
+     */
+    DateTimeFormatSymbols getSymbols() {
+        return formatter.getSymbols();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Starts the printing of an optional segment of the input.
+     */
+    void startOptional() {
+        this.optional++;
+    }
+
+    /**
+     * Ends the printing of an optional segment of the input.
+     */
+    void endOptional() {
+        this.optional--;
+    }
+
+    /**
+     * Gets a value using a query.
+     *
+     * @param query  the query to use, not null
+     * @return the result, null if not found and optional is true
+     * @throws DateTimeException if the type is not available and the section is not optional
+     */
+    <R> R getValue(TemporalQuery<R> query) {
+        R result = temporal.query(query);
+        if (result == null && optional == 0) {
+            throw new DateTimeException("Unable to extract value: " + temporal.getClass());
+        }
+        return result;
+    }
+
+    /**
+     * Gets the value of the specified field.
+     * <p>
+     * This will return the value for the specified field.
+     *
+     * @param field  the field to find, not null
+     * @return the value, null if not found and optional is true
+     * @throws DateTimeException if the field is not available and the section is not optional
+     */
+    Long getValue(TemporalField field) {
+        try {
+            return temporal.getLong(field);
+        } catch (DateTimeException ex) {
+            if (optional > 0) {
+                return null;
+            }
+            throw ex;
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a string version of the context for debugging.
+     *
+     * @return a string representation of the context, not null
+     */
+    @Override
+    public String toString() {
+        return temporal.toString();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/format/DateTimePrintException.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ * <p>
+ * This will be triggered by violations specific to printing or an IO exception.
+ *
+ * <h3>Specification for implementors</h3>
+ * 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
+     * <p>
+     * This method is useful if you call a printer with an open stream or
+     * writer and want to ensure that IOExceptions are not lost.
+     * <pre>
+     * try {
+     *   printer.print(writer, dateTime);
+     * } catch (DateTimePrintException ex) {
+     *   ex.rethrowIOException();
+     *   // if code reaches here exception was caused by date-time issues
+     * }
+     * </pre>
+     * 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();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/format/DateTimeTextProvider.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,380 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.format;
+
+import static java.time.temporal.ChronoField.AMPM_OF_DAY;
+import static java.time.temporal.ChronoField.DAY_OF_WEEK;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+
+import java.time.temporal.Chrono;
+import java.time.temporal.ISOChrono;
+import java.time.calendar.JapaneseChrono;
+import java.time.calendar.ThaiBuddhistChrono;
+import java.time.temporal.TemporalField;
+import java.util.AbstractMap.SimpleImmutableEntry;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+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;
+
+/**
+ * A provider to obtain the textual form of a date-time field.
+ *
+ * <h3>Specification for implementors</h3>
+ * Implementations must be thread-safe.
+ * Implementations should cache the textual information.
+ *
+ * @since 1.8
+ */
+class DateTimeTextProvider {
+
+    /** Cache. */
+    private static final ConcurrentMap<Entry<TemporalField, Locale>, Object> CACHE = new ConcurrentHashMap<>(16, 0.75f, 2);
+    /** Comparator. */
+    private static final Comparator<Entry<String, Long>> COMPARATOR = new Comparator<Entry<String, Long>>() {
+        @Override
+        public int compare(Entry<String, Long> obj1, Entry<String, Long> obj2) {
+            return obj2.getKey().length() - obj1.getKey().length();  // longest to shortest
+        }
+    };
+
+    DateTimeTextProvider() {}
+
+    /**
+     * Gets the provider of text.
+     *
+     * @return the provider, not null
+     */
+    static DateTimeTextProvider getInstance() {
+        return new DateTimeTextProvider();
+    }
+
+    /**
+     * Gets the text for the specified field, locale and style
+     * for the purpose of printing.
+     * <p>
+     * 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 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 text for the field value, null if no text found
+     */
+    public String getText(TemporalField field, long value, TextStyle style, Locale locale) {
+        Object store = findStore(field, locale);
+        if (store instanceof LocaleStore) {
+            return ((LocaleStore) store).getText(value, style);
+        }
+        return null;
+    }
+
+    private static int toStyle(TextStyle style) {
+        if (style == TextStyle.FULL) {
+            return Calendar.LONG_FORMAT;
+        } else if (style == TextStyle.SHORT) {
+            return Calendar.SHORT_FORMAT;
+        }
+        return Calendar.NARROW_STANDALONE;
+    }
+
+    /**
+     * Gets the era text for the specified chrono, value, style and locale
+     * for the purpose of printing.
+     * <p>
+     * The era 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 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
+     */
+    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;
+            } else {
+                value += 2;
+            }
+        } else if (chrono == ThaiBuddhistChrono.INSTANCE) {
+            type = "buddhist";
+        } else {
+            return null;
+        }
+        return CalendarDataUtility.retrieveFieldValueName(
+            type, Calendar.ERA, (int)value, toStyle(style), locale);
+    }
+
+    /**
+     * Gets an iterator of text to field for the specified field, locale and style
+     * for the purpose of parsing.
+     * <p>
+     * The iterator must be returned in order from the longest text to the shortest.
+     * <p>
+     * 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 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<Entry<String, Long>> getTextIterator(TemporalField field, TextStyle style, Locale locale) {
+        Object store = findStore(field, locale);
+        if (store instanceof LocaleStore) {
+            return ((LocaleStore) store).getTextIterator(style);
+        }
+        return null;
+    }
+
+    private Object findStore(TemporalField field, Locale locale) {
+        Entry<TemporalField, Locale> key = createEntry(field, locale);
+        Object store = CACHE.get(key);
+        if (store == null) {
+            store = createStore(field, locale);
+            CACHE.putIfAbsent(key, store);
+            store = CACHE.get(key);
+        }
+        return store;
+    }
+
+    private static int toWeekDay(int calWeekDay) {
+        if (calWeekDay == Calendar.SUNDAY) {
+            return 7;
+        } else {
+            return calWeekDay - 1;
+        }
+    }
+
+    private Object createStore(TemporalField field, Locale locale) {
+        CalendarNameProvider provider = LocaleProviderAdapter.getAdapter(CalendarNameProvider.class, locale)
+                                                             .getCalendarNameProvider();
+        Map<TextStyle, Map<Long, String>> styleMap = new HashMap<>();
+        if (field == MONTH_OF_YEAR) {
+            Map<Long, String> map = new HashMap<>();
+            for (Entry<String, Integer> entry :
+                 provider.getDisplayNames("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<String, Integer> entry :
+                 provider.getDisplayNames("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);
+                if (name != null) {
+                    map.put((long)(month + 1), name);
+                }
+            }
+            if (map.size() != 0) {
+                styleMap.put(TextStyle.NARROW, map);
+            }
+            return new LocaleStore(styleMap);
+        }
+        if (field == DAY_OF_WEEK) {
+            Map<Long, String> map = new HashMap<>();
+            for (Entry<String, Integer> entry :
+                 provider.getDisplayNames("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<String, Integer> entry :
+                 provider.getDisplayNames("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));
+            }
+            styleMap.put(TextStyle.NARROW, map);
+            return new LocaleStore(styleMap);
+        }
+        if (field == AMPM_OF_DAY) {
+            Map<Long, String> map = new HashMap<>();
+            for (Entry<String, Integer> entry :
+                 provider.getDisplayNames("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
+    }
+
+    /**
+     * Helper method to create an immutable entry.
+     *
+     * @param text  the text, not null
+     * @param field  the field, not null
+     * @return the entry, not null
+     */
+    private static <A, B> Entry<A, B> createEntry(A text, B field) {
+        return new SimpleImmutableEntry<>(text, field);
+    }
+
+    /**
+     * Stores the text for a single locale.
+     * <p>
+     * Some fields have a textual representation, such as day-of-week or month-of-year.
+     * These textual representations can be captured in this class for printing
+     * and parsing.
+     * <p>
+     * This class is immutable and thread-safe.
+     */
+    static final class LocaleStore {
+        /**
+         * Map of value to text.
+         */
+        private final Map<TextStyle, Map<Long, String>> valueTextMap;
+        /**
+         * Parsable data.
+         */
+        private final Map<TextStyle, List<Entry<String, Long>>> parsable;
+
+        /**
+         * Constructor.
+         *
+         * @param valueTextMap  the map of values to text to store, assigned and not altered, not null
+         */
+        LocaleStore(Map<TextStyle, Map<Long, String>> valueTextMap) {
+            this.valueTextMap = valueTextMap;
+            Map<TextStyle, List<Entry<String, Long>>> map = new HashMap<>();
+            List<Entry<String, Long>> allList = new ArrayList<>();
+            for (TextStyle style : valueTextMap.keySet()) {
+                Map<String, Entry<String, Long>> reverse = new HashMap<>();
+                for (Map.Entry<Long, String> entry : valueTextMap.get(style).entrySet()) {
+                    if (reverse.put(entry.getValue(), createEntry(entry.getValue(), entry.getKey())) != null) {
+                        // TODO: BUG: this has no effect
+                        continue;  // not parsable, try next style
+                    }
+                }
+                List<Entry<String, Long>> list = new ArrayList<>(reverse.values());
+                Collections.sort(list, COMPARATOR);
+                map.put(style, list);
+                allList.addAll(list);
+                map.put(null, allList);
+            }
+            Collections.sort(allList, COMPARATOR);
+            this.parsable = map;
+        }
+
+        /**
+         * Gets the text for the specified field value, locale and style
+         * for the purpose of printing.
+         *
+         * @param value  the value to get text for, not null
+         * @param style  the style to get text for, not null
+         * @return the text for the field value, null if no text found
+         */
+        String getText(long value, TextStyle style) {
+            Map<Long, String> map = valueTextMap.get(style);
+            return map != null ? map.get(value) : null;
+        }
+
+        /**
+         * Gets an iterator of text to field for the specified style for the purpose of parsing.
+         * <p>
+         * The iterator must be returned in order from the longest text to the shortest.
+         *
+         * @param style  the style to get text for, null for all parsable text
+         * @return the iterator of text to field pairs, in order from longest text to shortest text,
+         *  null if the style is not parsable
+         */
+        Iterator<Entry<String, Long>> getTextIterator(TextStyle style) {
+            List<Entry<String, Long>> list = parsable.get(style);
+            return list != null ? list.iterator() : null;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/format/FormatStyle.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,99 @@
+/*
+ * 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;
+
+/**
+ * Enumeration of the style of a localized date, time or date-time formatter.
+ * <p>
+ * These styles are used when obtaining a date-time style from configuration.
+ * See {@link DateTimeFormatters} and {@link DateTimeFormatterBuilder} for usage.
+ *
+ * <h3>Specification for implementors</h3>
+ * This is an immutable and thread-safe enum.
+ *
+ * @since 1.8
+ */
+public enum FormatStyle {
+    // ordered from large to small
+
+    /**
+     * Full text style, with the most detail.
+     * For example, the format might be 'Tuesday, April 12, 1952 AD' or '3:30:42pm PST'.
+     */
+    FULL,
+    /**
+     * Long text style, with lots of detail.
+     * For example, the format might be 'January 12, 1952'.
+     */
+    LONG,
+    /**
+     * Medium text style, with some detail.
+     * For example, the format might be 'Jan 12, 1952'.
+     */
+    MEDIUM,
+    /**
+     * Short text style, typically numeric.
+     * For example, the format might be '12.13.52' or '3:30pm'.
+     */
+    SHORT;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/format/SignStyle.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 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;
+
+/**
+ * Enumeration of ways to handle the positive/negative sign.
+ * <p>
+ * The formatting engine allows the positive and negative signs of numbers
+ * to be controlled using this enum.
+ * See {@link DateTimeFormatterBuilder} for usage.
+ *
+ * <h3>Specification for implementors</h3>
+ * This is an immutable and thread-safe enum.
+ *
+ * @since 1.8
+ */
+public enum SignStyle {
+
+    /**
+     * Style to output the sign only if the value is negative.
+     * <p>
+     * In strict parsing, the negative sign will be accepted and the positive sign rejected.
+     * In lenient parsing, any sign will be accepted.
+     */
+    NORMAL,
+    /**
+     * Style to always output the sign, where zero will output '+'.
+     * <p>
+     * In strict parsing, the absence of a sign will be rejected.
+     * In lenient parsing, any sign will be accepted, with the absence
+     * of a sign treated as a positive number.
+     */
+    ALWAYS,
+    /**
+     * Style to never output sign, only outputting the absolute value.
+     * <p>
+     * In strict parsing, any sign will be rejected.
+     * In lenient parsing, any sign will be accepted unless the width is fixed.
+     */
+    NEVER,
+    /**
+     * Style to block negative values, throwing an exception on printing.
+     * <p>
+     * In strict parsing, any sign will be rejected.
+     * In lenient parsing, any sign will be accepted unless the width is fixed.
+     */
+    NOT_NEGATIVE,
+    /**
+     * Style to always output the sign if the value exceeds the pad width.
+     * A negative value will always output the '-' sign.
+     * <p>
+     * In strict parsing, the sign will be rejected unless the pad width is exceeded.
+     * In lenient parsing, any sign will be accepted, with the absence
+     * of a sign treated as a positive number.
+     */
+    EXCEEDS_PAD;
+
+    /**
+     * Parse helper.
+     *
+     * @param positive  true if positive sign parsed, false for negative sign
+     * @param strict  true if strict, false if lenient
+     * @param fixedWidth  true if fixed width, false if not
+     * @return
+     */
+    boolean parse(boolean positive, boolean strict, boolean fixedWidth) {
+        switch (ordinal()) {
+            case 0: // NORMAL
+                // valid if negative or (positive and lenient)
+                return !positive || !strict;
+            case 1: // ALWAYS
+            case 4: // EXCEEDS_PAD
+                return true;
+            default:
+                // valid if lenient and not fixed width
+                return !strict && !fixedWidth;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/format/TextStyle.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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;
+
+/**
+ * Enumeration of the style of text output to use.
+ * <p>
+ * This defines the "size" of the text to be output.
+ *
+ * <h3>Specification for implementors</h3>
+ * This is immutable and thread-safe enum.
+ *
+ * @since 1.8
+ */
+public enum TextStyle {
+    // ordered from large to small
+
+    /**
+     * Full text, typically the full description.
+     * For example, day-of-week Monday might output "Monday".
+     */
+    FULL,
+    /**
+     * Short text, typically an abbreviation.
+     * For example, day-of-week Monday might output "Mon".
+     */
+    SHORT,
+    /**
+     * Narrow text, typically a single letter.
+     * For example, day-of-week Monday might output "M".
+     */
+    NARROW;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/format/package-info.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.
+ */
+
+/**
+ * <p>
+ * Provides classes to print and parse dates and times.
+ * </p>
+ * <p>
+ * 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.DateTimeFormatterBuilder DateTimeFormatterBuilder}
+ * can be used if more power is needed.
+ * </p>
+ * <p>
+ * Localization occurs by calling
+ * {@link java.time.format.DateTimeFormatter#withLocale(java.util.Locale) withLocale(Locale)}
+ * on the formatter. Further customization is possible using
+ * {@link java.time.format.DateTimeFormatSymbols DateTimeFormatSymbols}.
+ * </p>
+ *
+ * <h3>Package specification</h3>
+ * <p>
+ * 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.
+ * </p>
+ * <p>
+ * All calculations should check for numeric overflow and throw either an {@link java.lang.ArithmeticException}
+ * or a {@link java.time.DateTimeException}.
+ * </p>
+ * @since JDK1.8
+ */
+package java.time.format;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/overview.html	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,174 @@
+<!--
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.
+ */
+-->
+<body>
+    <p>
+        A new Date and Time API for Java.
+        The design includes a relatively large number of classes and methods,
+        however each follows a common design language, especially in method prefixes.
+        Once the prefixes are understood, the API is relatively simple to comprehend.
+    </p>
+    <p>
+        The Java Time API is composed of several packages, each with a primary function:
+    </p>
+    <p>
+        {@link java.time} contains the main API based on the ISO-8601 standard.
+        The classes defined here represent the principal date-time concepts,
+        including instants, durations, dates, times, time-zones and periods.
+        They are based on the ISO calendar system, which is the <i>de facto</i> world
+        calendar following the proleptic Gregorian rules.
+        All the classes are immutable and thread-safe.
+    </p>
+    <p>
+        {@link java.time.temporal} contains the API for accessing the fields and units
+        of date-time. Units are measurable, such as years, months and hours.
+        For example, the expression "2 hours later" uses the hours unit.
+        By contrast, fields are mini-calculations, defining a value.
+        For example, month-of-year, day-of-week and hour-of-day are all fields.
+        The set of supported units and fields can be extended by applications if desired.
+    </p>
+    <p>
+        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.
+    </p>
+    <p>
+        {@link java.time.format} contains the API to print and parse fields into date-time
+        objects and to customize parsing and printing.
+        Formatters can be created in a variety of ways, including constants, patterns,
+        localized styles and a builder.
+        Formatters are immutable and thread-safe.
+    </p>
+    <p>
+        {@link java.time.zone} contains the API to handle time-zones.
+        Detailed information is made available about the rules of each time-zone.
+    </p>
+    <p>
+        The {@link java.time.calendar} package contains alternate calendar systems.
+        This is intended for use by applications that need to use localized calendars.
+        Support is provided for the Hijrah, Japanese, Minguo, and Thai Buddhist Calendars.
+    </p>
+    <h3>Design notes</h3>
+    <p>
+        Where possible, the API avoids the use of null.
+        All methods define whether they accept or return null in the Javadoc.
+        As a general rule, methods do not accept or return null.
+        A key exception is any method that takes an object and returns a boolean, for the purpose
+        of checking or validating, will generally return false for null.
+    </p>
+    <p>
+        The API is designed to be type-safe where reasonable in the main high-level API.
+        Thus, there are separate classes for the distinct concepts of date, time and date-time, plus variants
+        for offset and time-zones. The core 7 date-time classes, plus Instant, handle the needs of most applications.
+        Further classes handle other combinations - year, year-month and month-day in a type-safe manner.
+    </p>
+    <p>
+        In a language like Java, the use of many different types tends to cause API bloat.
+        This is handled here through the use of common method naming patterns throughout the API.
+        The common prefixes are 'of', 'get', 'is', 'with', 'plus', 'minus', 'to' and 'at'.
+        See {@link java.time.LocalDate} for an example of each of these methods.
+    </p>
+    <p>
+        Following type-safety to its logical conclusion would result in more classes, especially for time -
+        hour-minute, hour-minute-second and hour-minute-second-nanosecond.
+        While logically pure, this was not possible in practice, as the additional classes would have
+        excessively complicated the API. Notably, there would be additional combinations at the offset
+        and date-time levels, such as offset-date-hour-minute.
+        To avoid this explosion of types, {@link java.time.LocalTime} is used for all precisions of time.
+        By contrast, some additional classes were used for dates, such as {@link java.time.temporal.YearMonth}.
+        This proved necessary, as the API for year-month is significantly different to that for a date, whereas
+        an absence of nanoseconds in a time can be approximated by returning zero.
+    </p>
+    <p>
+        Similarly, full type-safety might argue for a separate class for each field in date-time,
+        such as a class for HourOfDay and another for DayOfMonth.
+        This approach was tried, but was excessively complicated in the Java language, lacking usability.
+        A similar problem occurs with periods.
+        There is a case for a separate class for each period unit, such as a type for Years and a type for Minutes.
+        However, this yields a lot of classes and a problem of type conversion.
+        As such, general access to fields and units is not wrapped in a class.
+    </p>
+    <p>
+        Multiple calendar systems is an awkward addition to the design challenges.
+        The first principal is that most users want the standard ISO calendar system.
+        As such, the main classes are ISO-only. The second principal is that most of those that want a
+        non-ISO calendar system want it for user interaction, thus it is a UI localization issue.
+        As such, date and time objects should be held as ISO objects in the data model and persistent
+        storage, only being converted to and from a local calendar for display.
+        The calendar system would be stored separately in the user preferences.
+    </p>
+    <p>
+        There are, however, some limited use cases where users believe they need to store and use
+        dates in arbitrary calendar systems throughout the application.
+        This is supported by {@link java.time.temporal.ChronoLocalDate}, however it is vital to read
+        all the associated warnings in the Javadoc of that interface before using it.
+        In summary, applications that require general interoperation between multiple calendar systems
+        typically need to be written in a very different way to those only using the ISO calendar,
+        thus most applications should just use ISO and avoid {@code ChronoLocalDate}.
+    </p>
+    <p>
+        Throughout all of this, a key goal was to allow date-time fields and units to be defined by applications.
+        This has been achieved having tried many different designs.
+    </p>
+</body>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/package-info.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * <p>
+ * The main API for dates, times, instants, and durations.
+ * </p>
+ * <p>
+ * The classes defined here represent the principal date-time concepts,
+ * including instants, durations, dates, times, time-zones and periods.
+ * They are based on the ISO calendar system, which is the <i>de facto</i> world
+ * calendar following the proleptic Gregorian rules.
+ * All the classes are immutable and thread-safe.
+ * </p>
+ * <p>
+ * Each date time instance is composed of fields that are conveniently
+ * made available by the APIs.  For lower level access to the fields refer
+ * to the {@code java.time.temporal} package.
+ * Each class includes support for printing and parsing all manner of dates and times.
+ * Refer to the {@code java.time.format} package for customization options.
+ * </p>
+ * <p>
+ * The {@code java.time.temporal} package also contains the calendar neutral API
+ * {@link java.time.temporal.ChronoLocalDate ChronoLocalDate},
+ * {@link java.time.temporal.ChronoLocalDateTime ChronoLocalDateTime},
+ * {@link java.time.temporal.ChronoZonedDateTime ChronoZonedDateTime} and
+ * {@link java.time.temporal.Era Era}.
+ * This is intended for use by applications that need to use localized calendars.
+ * It is recommended that applications use the ISO-8601 dates and time classes from
+ * this package across system boundaries, such as to the database or across the network.
+ * The calendar neutral API should be reserved for interactions with users.
+ * </p>
+ *
+ * <h3>Dates and Times</h3>
+ * <p>
+ * {@link java.time.Instant} is essentially a numeric timestamp.
+ * The current Instant can be retrieved from a {@link java.time.Clock}.
+ * This is useful for logging and persistence of a point in time
+ * and has in the past been associated with storing the result
+ * from {@link java.lang.System#currentTimeMillis()}.
+ * </p>
+ * <p>
+ * {@link java.time.LocalDate} stores a date without a time.
+ * This stores a date like '2010-12-03' and could be used to store a birthday.
+ * </p>
+ * <p>
+ * {@link java.time.LocalTime} stores a time without a date.
+ * This stores a time like '11:30' and could be used to store an opening or closing time.
+ * </p>
+ * <p>
+ * {@link java.time.LocalDateTime} stores a date and time.
+ * This stores a date-time like '2010-12-03T11:30'.
+ * </p>
+ * <p>
+ * {@link java.time.ZonedDateTime} stores a date and time with a time-zone.
+ * This is useful if you want to perform accurate calculations of
+ * dates and times taking into account the {@link java.time.ZoneId}, such as 'Europe/Paris'.
+ * Where possible, it is recommended to use a simpler class without a time-zone.
+ * The widespread use of time-zones tends to add considerable complexity to an application.
+ * </p>
+ *
+ * <h3>Duration and Period</h3>
+ * <p>
+ * Beyond dates and times, the API also allows the storage of period and durations of time.
+ * A {@link java.time.Duration} is a simple measure of time along the time-line in nanoseconds.
+ * A {@link java.time.Period} expresses an amount of time in units meaningful to humans, such as years or hours.
+ * </p>
+ *
+ * <h3>Additional value types</h3>
+ * <p>
+ * {@link java.time.Month} stores a month on its own.
+ * This stores a single month-of-year in isolation, such as 'DECEMBER'.
+ * </p>
+ * <p>
+ * {@link java.time.DayOfWeek} stores a day-of-week on its own.
+ * This stores a single day-of-week in isolation, such as 'TUESDAY'.
+ * </p>
+ * <p>
+ * {@link java.time.temporal.Year} stores a year on its own.
+ * This stores a single year in isolation, such as '2010'.
+ * </p>
+ * <p>
+ * {@link java.time.temporal.YearMonth} stores a year and month without a day or time.
+ * This stores a year and month, such as '2010-12' and could be used for a credit card expiry.
+ * </p>
+ * <p>
+ * {@link java.time.temporal.MonthDay} stores a month and day without a year or time.
+ * This stores a month and day-of-month, such as '--12-03' and
+ * could be used to store an annual event like a birthday without storing the year.
+ * </p>
+ * <p>
+ * {@link java.time.temporal.OffsetTime} stores a time and offset from UTC without a date.
+ * This stores a date like '11:30+01:00'.
+ * The {@link java.time.ZoneOffset ZoneOffset} is of the form '+01:00'.
+ * </p>
+ * <p>
+ * {@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'.
+ * </p>
+ * <p>
+ * {@link java.time.temporal.OffsetDateTime} stores a date and time and offset from UTC.
+ * This stores a date-time like '2010-12-03T11:30+01:00'.
+ * This is sometimes found in XML messages and other forms of persistence,
+ * but contains less information than a full time-zone.
+ * </p>
+ *
+ * <h3>Package specification</h3>
+ * <p>
+ * 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.
+ * </p>
+ * <p>
+ * All calculations should check for numeric overflow and throw either an {@link java.lang.ArithmeticException}
+ * or a {@link java.time.DateTimeException}.
+ * </p>
+ *
+ * <h3>Design notes (non normative)</h3>
+ * <p>
+ * The API has been designed to reject null early and to be clear about this behavior.
+ * A key exception is any method that takes an object and returns a boolean, for the purpose
+ * of checking or validating, will generally return false for null.
+ * </p>
+ * <p>
+ * The API is designed to be type-safe where reasonable in the main high-level API.
+ * Thus, there are separate classes for the distinct concepts of date, time and date-time,
+ * plus variants for offset and time-zone.
+ * This can seem like a lot of classes, but most applications can begin with just five date/time types.
+ * <ul>
+ * <li>{@link java.time.Instant} - a timestamp</li>
+ * <li>{@link java.time.LocalDate} - a date without a time, or any reference to an offset or time-zone</li>
+ * <li>{@link java.time.LocalTime} - a time without a date, or any reference to an offset or time-zone</li>
+ * <li>{@link java.time.LocalDateTime} - combines date and time, but still without any offset or time-zone</li>
+ * <li>{@link java.time.ZonedDateTime} - a "full" date-time with time-zone and resolved offset from UTC/Greenwich</li>
+ * </ul>
+ * <p>
+ * {@code Instant} is the closest equivalent class to {@code java.util.Date}.
+ * {@code ZonedDateTime} is the closest equivalent class to {@code java.util.GregorianCalendar}.
+ * </p>
+ * <p>
+ * Where possible, applications should use {@code LocalDate}, {@code LocalTime} and {@code LocalDateTime}
+ * to better model the domain. For example, a birthday should be stored in a code {@code LocalDate}.
+ * Bear in mind that any use of a {@linkplain java.time.ZoneId time-zone}, such as 'Europe/Paris', adds
+ * considerable complexity to a calculation.
+ * Many applications can be written only using {@code LocalDate}, {@code LocalTime} and {@code Instant},
+ * with the time-zone added at the user interface (UI) layer.
+ * </p>
+ * <p>
+ * The offset-based date-time types, {@code OffsetDate}, {@code OffsetTime} and {@code OffsetDateTime},
+ * are intended primarily for use with network protocols and database access.
+ * For example, most databases cannot automatically store a time-zone like 'Europe/Paris', but
+ * they can store an offset like '+02:00'.
+ * </p>
+ * <p>
+ * Classes are also provided for the most important sub-parts of a date, including {@code Month},
+ * {@code DayOfWeek}, {@code Year}, {@code YearMonth} and {@code MonthDay}.
+ * These can be used to model more complex date-time concepts.
+ * For example, {@code YearMonth} is useful for representing a credit card expiry.
+ * </p>
+ * <p>
+ * Note that while there are a large number of classes representing different aspects of dates,
+ * there are relatively few dealing with different aspects of time.
+ * Following type-safety to its logical conclusion would have resulted in classes for
+ * hour-minute, hour-minute-second and hour-minute-second-nanosecond.
+ * While logically pure, this was not a practical option as it would have almost tripled the
+ * number of classes due to the combinations of date and time.
+ * Thus, {@code LocalTime} is used for all precisions of time, with zeroes used to imply lower precision.
+ * </p>
+ * <p>
+ * Following full type-safety to its ultimate conclusion might also argue for a separate class
+ * for each field in date-time, such as a class for HourOfDay and another for DayOfMonth.
+ * This approach was tried, but was excessively complicated in the Java language, lacking usability.
+ * A similar problem occurs with periods.
+ * There is a case for a separate class for each period unit, such as a type for Years and a type for Minutes.
+ * However, this yields a lot of classes and a problem of type conversion.
+ * Thus, the set of date-time types provided is a compromise between purity and practicality.
+ * </p>
+ * <p>
+ * The API has a relatively large surface area in terms of number of methods.
+ * This is made manageable through the use of consistent method prefixes.
+ * <ul>
+ * <li>{@code of} - static factory method</li>
+ * <li>{@code parse} - static factory method focussed on parsing</li>
+ * <li>{@code get} - gets the value of something</li>
+ * <li>{@code is} - checks if something is true</li>
+ * <li>{@code with} - the immutable equivalent of a setter</li>
+ * <li>{@code plus} - adds an amount to an object</li>
+ * <li>{@code minus} - subtracts an amount from an object</li>
+ * <li>{@code to} - converts this object to another type</li>
+ * <li>{@code at} - combines this object with another, such as {@code date.atTime(time)}</li>
+ * </ul>
+ * <p>
+ * Multiple calendar systems is an awkward addition to the design challenges.
+ * The first principal is that most users want the standard ISO calendar system.
+ * As such, the main classes are ISO-only. The second principal is that most of those that want a
+ * non-ISO calendar system want it for user interaction, thus it is a UI localization issue.
+ * As such, date and time objects should be held as ISO objects in the data model and persistent
+ * storage, only being converted to and from a local calendar for display.
+ * The calendar system would be stored separately in the user preferences.
+ * </p>
+ * <p>
+ * There are, however, some limited use cases where users believe they need to store and use
+ * dates in arbitrary calendar systems throughout the application.
+ * This is supported by {@link java.time.temporal.ChronoLocalDate}, however it is vital to read
+ * all the associated warnings in the Javadoc of that interface before using it.
+ * In summary, applications that require general interoperation between multiple calendar systems
+ * typically need to be written in a very different way to those only using the ISO calendar,
+ * thus most applications should just use ISO and avoid {@code ChronoLocalDate}.
+ * </p>
+ * <p>
+ * The API is also designed for user extensibility, as there are many ways of calculating time.
+ * The {@linkplain java.time.temporal.TemporalField field} and {@linkplain java.time.temporal.TemporalUnit unit}
+ * API, accessed via {@link java.time.temporal.TemporalAccessor TemporalAccessor} and
+ * {@link java.time.temporal.Temporal Temporal} provide considerable flexibility to applications.
+ * In addition, the {@link java.time.temporal.TemporalQuery TemporalQuery} and
+ * {@link java.time.temporal.TemporalAdjuster TemporalAdjuster} interfaces provide day-to-day
+ * power, allowing code to read close to business requirements:
+ * </p>
+ * <pre>
+ *   LocalDate customerBirthday = customer.loadBirthdayFromDatabase();
+ *   LocalDate today = LocalDate.now();
+ *   if (customerBirthday.equals(today)) {
+ *     LocalDate specialOfferExpiryDate = today.plusWeeks(2).with(next(FRIDAY));
+ *     customer.sendBirthdaySpecialOffer(specialOfferExpiryDate);
+ *   }
+ *
+ * </pre>
+ *
+ * @since JDK1.8
+ */
+package java.time;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/Adjusters.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,502 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.DAY_OF_WEEK;
+import static java.time.temporal.ChronoField.DAY_OF_YEAR;
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.MONTHS;
+import static java.time.temporal.ChronoUnit.YEARS;
+
+import java.time.DayOfWeek;
+import java.util.Objects;
+
+/**
+ * Common implementations of {@code TemporalAdjuster}.
+ * <p>
+ * This class provides common implementations of {@link TemporalAdjuster}.
+ * They are especially useful to document the intent of business logic and
+ * often link well to requirements.
+ * For example, these two pieces of code do the same thing, but the second
+ * one is clearer (assuming that there is a static import of this class):
+ * <pre>
+ *  // direct manipulation
+ *  date.withDayOfMonth(1).plusMonths(1).minusDays(1);
+ *  // use of an adjuster from this class
+ *  date.with(lastDayOfMonth());
+ * </pre>
+ * There are two equivalent ways of using a {@code TemporalAdjuster}.
+ * The first is to invoke the method on the interface directly.
+ * The second is to use {@link Temporal#with(TemporalAdjuster)}:
+ * <pre>
+ *   // these two lines are equivalent, but the second approach is recommended
+ *   dateTime = adjuster.adjustInto(dateTime);
+ *   dateTime = dateTime.with(adjuster);
+ * </pre>
+ * It is recommended to use the second approach, {@code with(TemporalAdjuster)},
+ * as it is a lot clearer to read in code.
+ *
+ * <h3>Specification for implementors</h3>
+ * This is a thread-safe utility class.
+ * All returned adjusters are immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class Adjusters {
+
+    /**
+     * Private constructor since this is a utility class.
+     */
+    private Adjusters() {
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns the "first day of month" adjuster, which returns a new date set to
+     * the first day of the current month.
+     * <p>
+     * The ISO calendar system behaves as follows:<br>
+     * The input 2011-01-15 will return 2011-01-01.<br>
+     * The input 2011-02-15 will return 2011-02-01.
+     * <p>
+     * The behavior is suitable for use with most calendar systems.
+     * It is equivalent to:
+     * <pre>
+     *  temporal.with(DAY_OF_MONTH, 1);
+     * </pre>
+     *
+     * @return the first day-of-month adjuster, not null
+     */
+    public static TemporalAdjuster firstDayOfMonth() {
+        return Impl.FIRST_DAY_OF_MONTH;
+    }
+
+    /**
+     * Returns the "last day of month" adjuster, which returns a new date set to
+     * the last day of the current month.
+     * <p>
+     * The ISO calendar system behaves as follows:<br>
+     * The input 2011-01-15 will return 2011-01-31.<br>
+     * The input 2011-02-15 will return 2011-02-28.<br>
+     * The input 2012-02-15 will return 2012-02-29 (leap year).<br>
+     * The input 2011-04-15 will return 2011-04-30.
+     * <p>
+     * The behavior is suitable for use with most calendar systems.
+     * It is equivalent to:
+     * <pre>
+     *  long lastDay = temporal.range(DAY_OF_MONTH).getMaximum();
+     *  temporal.with(DAY_OF_MONTH, lastDay);
+     * </pre>
+     *
+     * @return the last day-of-month adjuster, not null
+     */
+    public static TemporalAdjuster lastDayOfMonth() {
+        return Impl.LAST_DAY_OF_MONTH;
+    }
+
+    /**
+     * Returns the "first day of next month" adjuster, which returns a new date set to
+     * the first day of the next month.
+     * <p>
+     * The ISO calendar system behaves as follows:<br>
+     * The input 2011-01-15 will return 2011-02-01.<br>
+     * The input 2011-02-15 will return 2011-03-01.
+     * <p>
+     * The behavior is suitable for use with most calendar systems.
+     * It is equivalent to:
+     * <pre>
+     *  temporal.with(DAY_OF_MONTH, 1).plus(1, MONTHS);
+     * </pre>
+     *
+     * @return the first day of next month adjuster, not null
+     */
+    public static TemporalAdjuster firstDayOfNextMonth() {
+        return Impl.FIRST_DAY_OF_NEXT_MONTH;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns the "first day of year" adjuster, which returns a new date set to
+     * the first day of the current year.
+     * <p>
+     * The ISO calendar system behaves as follows:<br>
+     * The input 2011-01-15 will return 2011-01-01.<br>
+     * The input 2011-02-15 will return 2011-01-01.<br>
+     * <p>
+     * The behavior is suitable for use with most calendar systems.
+     * It is equivalent to:
+     * <pre>
+     *  temporal.with(DAY_OF_YEAR, 1);
+     * </pre>
+     *
+     * @return the first day-of-year adjuster, not null
+     */
+    public static TemporalAdjuster firstDayOfYear() {
+        return Impl.FIRST_DAY_OF_YEAR;
+    }
+
+    /**
+     * Returns the "last day of year" adjuster, which returns a new date set to
+     * the last day of the current year.
+     * <p>
+     * The ISO calendar system behaves as follows:<br>
+     * The input 2011-01-15 will return 2011-12-31.<br>
+     * The input 2011-02-15 will return 2011-12-31.<br>
+     * <p>
+     * The behavior is suitable for use with most calendar systems.
+     * It is equivalent to:
+     * <pre>
+     *  long lastDay = temporal.range(DAY_OF_YEAR).getMaximum();
+     *  temporal.with(DAY_OF_YEAR, lastDay);
+     * </pre>
+     *
+     * @return the last day-of-year adjuster, not null
+     */
+    public static TemporalAdjuster lastDayOfYear() {
+        return Impl.LAST_DAY_OF_YEAR;
+    }
+
+    /**
+     * Returns the "first day of next year" adjuster, which returns a new date set to
+     * the first day of the next year.
+     * <p>
+     * The ISO calendar system behaves as follows:<br>
+     * The input 2011-01-15 will return 2012-01-01.
+     * <p>
+     * The behavior is suitable for use with most calendar systems.
+     * It is equivalent to:
+     * <pre>
+     *  temporal.with(DAY_OF_YEAR, 1).plus(1, YEARS);
+     * </pre>
+     *
+     * @return the first day of next month adjuster, not null
+     */
+    public static TemporalAdjuster firstDayOfNextYear() {
+        return Impl.FIRST_DAY_OF_NEXT_YEAR;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Enum implementing the adjusters.
+     */
+    private static class Impl implements TemporalAdjuster {
+        /** First day of month adjuster. */
+        private static final Impl FIRST_DAY_OF_MONTH = new Impl(0);
+        /** Last day of month adjuster. */
+        private static final Impl LAST_DAY_OF_MONTH = new Impl(1);
+        /** First day of next month adjuster. */
+        private static final Impl FIRST_DAY_OF_NEXT_MONTH = new Impl(2);
+        /** First day of year adjuster. */
+        private static final Impl FIRST_DAY_OF_YEAR = new Impl(3);
+        /** Last day of year adjuster. */
+        private static final Impl LAST_DAY_OF_YEAR = new Impl(4);
+        /** First day of next month adjuster. */
+        private static final Impl FIRST_DAY_OF_NEXT_YEAR = new Impl(5);
+        /** The ordinal. */
+        private final int ordinal;
+        private Impl(int ordinal) {
+            this.ordinal = ordinal;
+        }
+        @Override
+        public Temporal adjustInto(Temporal temporal) {
+            switch (ordinal) {
+                case 0: return temporal.with(DAY_OF_MONTH, 1);
+                case 1: return temporal.with(DAY_OF_MONTH, temporal.range(DAY_OF_MONTH).getMaximum());
+                case 2: return temporal.with(DAY_OF_MONTH, 1).plus(1, MONTHS);
+                case 3: return temporal.with(DAY_OF_YEAR, 1);
+                case 4: return temporal.with(DAY_OF_YEAR, temporal.range(DAY_OF_YEAR).getMaximum());
+                case 5: return temporal.with(DAY_OF_YEAR, 1).plus(1, YEARS);
+            }
+            throw new IllegalStateException("Unreachable");
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns the first in month adjuster, which returns a new date
+     * in the same month with the first matching day-of-week.
+     * This is used for expressions like 'first Tuesday in March'.
+     * <p>
+     * The ISO calendar system behaves as follows:<br>
+     * The input 2011-12-15 for (MONDAY) will return 2011-12-05.<br>
+     * The input 2011-12-15 for (FRIDAY) will return 2011-12-02.<br>
+     * <p>
+     * The behavior is suitable for use with most calendar systems.
+     * It uses the {@code DAY_OF_WEEK} and {@code DAY_OF_MONTH} fields
+     * and the {@code DAYS} unit, and assumes a seven day week.
+     *
+     * @param dayOfWeek  the day-of-week, not null
+     * @return the first in month adjuster, not null
+     */
+    public static TemporalAdjuster firstInMonth(DayOfWeek dayOfWeek) {
+        Objects.requireNonNull(dayOfWeek, "dayOfWeek");
+        return new DayOfWeekInMonth(1, dayOfWeek);
+    }
+
+    /**
+     * Returns the last in month adjuster, which returns a new date
+     * in the same month with the last matching day-of-week.
+     * This is used for expressions like 'last Tuesday in March'.
+     * <p>
+     * The ISO calendar system behaves as follows:<br>
+     * The input 2011-12-15 for (MONDAY) will return 2011-12-26.<br>
+     * The input 2011-12-15 for (FRIDAY) will return 2011-12-30.<br>
+     * <p>
+     * The behavior is suitable for use with most calendar systems.
+     * It uses the {@code DAY_OF_WEEK} and {@code DAY_OF_MONTH} fields
+     * and the {@code DAYS} unit, and assumes a seven day week.
+     *
+     * @param dayOfWeek  the day-of-week, not null
+     * @return the first in month adjuster, not null
+     */
+    public static TemporalAdjuster lastInMonth(DayOfWeek dayOfWeek) {
+        Objects.requireNonNull(dayOfWeek, "dayOfWeek");
+        return new DayOfWeekInMonth(-1, dayOfWeek);
+    }
+
+    /**
+     * Returns the day-of-week in month adjuster, which returns a new date
+     * in the same month with the ordinal day-of-week.
+     * This is used for expressions like the 'second Tuesday in March'.
+     * <p>
+     * The ISO calendar system behaves as follows:<br>
+     * The input 2011-12-15 for (1,TUESDAY) will return 2011-12-06.<br>
+     * The input 2011-12-15 for (2,TUESDAY) will return 2011-12-13.<br>
+     * The input 2011-12-15 for (3,TUESDAY) will return 2011-12-20.<br>
+     * The input 2011-12-15 for (4,TUESDAY) will return 2011-12-27.<br>
+     * The input 2011-12-15 for (5,TUESDAY) will return 2012-01-03.<br>
+     * The input 2011-12-15 for (-1,TUESDAY) will return 2011-12-27 (last in month).<br>
+     * The input 2011-12-15 for (-4,TUESDAY) will return 2011-12-06 (3 weeks before last in month).<br>
+     * The input 2011-12-15 for (-5,TUESDAY) will return 2011-11-29 (4 weeks before last in month).<br>
+     * The input 2011-12-15 for (0,TUESDAY) will return 2011-11-29 (last in previous month).<br>
+     * <p>
+     * For a positive or zero ordinal, the algorithm is equivalent to finding the first
+     * day-of-week that matches within the month and then adding a number of weeks to it.
+     * For a negative ordinal, the algorithm is equivalent to finding the last
+     * day-of-week that matches within the month and then subtracting a number of weeks to it.
+     * The ordinal number of weeks is not validated and is interpreted leniently
+     * according to this algorithm. This definition means that an ordinal of zero finds
+     * the last matching day-of-week in the previous month.
+     * <p>
+     * The behavior is suitable for use with most calendar systems.
+     * It uses the {@code DAY_OF_WEEK} and {@code DAY_OF_MONTH} fields
+     * and the {@code DAYS} unit, and assumes a seven day week.
+     *
+     * @param ordinal  the week within the month, unbound but typically from -5 to 5
+     * @param dayOfWeek  the day-of-week, not null
+     * @return the day-of-week in month adjuster, not null
+     * @throws IllegalArgumentException if the ordinal is invalid
+     */
+    public static TemporalAdjuster dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek) {
+        Objects.requireNonNull(dayOfWeek, "dayOfWeek");
+        return new DayOfWeekInMonth(ordinal, dayOfWeek);
+    }
+
+    /**
+     * Class implementing day-of-week in month adjuster.
+     */
+    private static final class DayOfWeekInMonth implements TemporalAdjuster {
+        /** The ordinal. */
+        private final int ordinal;
+        /** The day-of-week value, from 1 to 7. */
+        private final int dowValue;
+
+        private DayOfWeekInMonth(int ordinal, DayOfWeek dow) {
+            super();
+            this.ordinal = ordinal;
+            this.dowValue = dow.getValue();
+        }
+        @Override
+        public Temporal adjustInto(Temporal temporal) {
+            if (ordinal >= 0) {
+                Temporal temp = temporal.with(DAY_OF_MONTH, 1);
+                int curDow = temp.get(DAY_OF_WEEK);
+                int dowDiff = (dowValue - curDow + 7) % 7;
+                dowDiff += (ordinal - 1L) * 7L;  // safe from overflow
+                return temp.plus(dowDiff, DAYS);
+            } else {
+                Temporal temp = temporal.with(DAY_OF_MONTH, temporal.range(DAY_OF_MONTH).getMaximum());
+                int curDow = temp.get(DAY_OF_WEEK);
+                int daysDiff = dowValue - curDow;
+                daysDiff = (daysDiff == 0 ? 0 : (daysDiff > 0 ? daysDiff - 7 : daysDiff));
+                daysDiff -= (-ordinal - 1L) * 7L;  // safe from overflow
+                return temp.plus(daysDiff, DAYS);
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns the next day-of-week adjuster, which adjusts the date to the
+     * first occurrence of the specified day-of-week after the date being adjusted.
+     * <p>
+     * The ISO calendar system behaves as follows:<br>
+     * The input 2011-01-15 (a Saturday) for parameter (MONDAY) will return 2011-01-17 (two days later).<br>
+     * The input 2011-01-15 (a Saturday) for parameter (WEDNESDAY) will return 2011-01-19 (four days later).<br>
+     * The input 2011-01-15 (a Saturday) for parameter (SATURDAY) will return 2011-01-22 (seven days later).
+     * <p>
+     * The behavior is suitable for use with most calendar systems.
+     * It uses the {@code DAY_OF_WEEK} field and the {@code DAYS} unit,
+     * and assumes a seven day week.
+     *
+     * @param dayOfWeek  the day-of-week to move the date to, not null
+     * @return the next day-of-week adjuster, not null
+     */
+    public static TemporalAdjuster next(DayOfWeek dayOfWeek) {
+        return new RelativeDayOfWeek(2, dayOfWeek);
+    }
+
+    /**
+     * Returns the next-or-same day-of-week adjuster, which adjusts the date to the
+     * first occurrence of the specified day-of-week after the date being adjusted
+     * unless it is already on that day in which case the same object is returned.
+     * <p>
+     * The ISO calendar system behaves as follows:<br>
+     * The input 2011-01-15 (a Saturday) for parameter (MONDAY) will return 2011-01-17 (two days later).<br>
+     * The input 2011-01-15 (a Saturday) for parameter (WEDNESDAY) will return 2011-01-19 (four days later).<br>
+     * The input 2011-01-15 (a Saturday) for parameter (SATURDAY) will return 2011-01-15 (same as input).
+     * <p>
+     * The behavior is suitable for use with most calendar systems.
+     * It uses the {@code DAY_OF_WEEK} field and the {@code DAYS} unit,
+     * and assumes a seven day week.
+     *
+     * @param dayOfWeek  the day-of-week to check for or move the date to, not null
+     * @return the next-or-same day-of-week adjuster, not null
+     */
+    public static TemporalAdjuster nextOrSame(DayOfWeek dayOfWeek) {
+        return new RelativeDayOfWeek(0, dayOfWeek);
+    }
+
+    /**
+     * Returns the previous day-of-week adjuster, which adjusts the date to the
+     * first occurrence of the specified day-of-week before the date being adjusted.
+     * <p>
+     * The ISO calendar system behaves as follows:<br>
+     * The input 2011-01-15 (a Saturday) for parameter (MONDAY) will return 2011-01-10 (five days earlier).<br>
+     * The input 2011-01-15 (a Saturday) for parameter (WEDNESDAY) will return 2011-01-12 (three days earlier).<br>
+     * The input 2011-01-15 (a Saturday) for parameter (SATURDAY) will return 2011-01-08 (seven days earlier).
+     * <p>
+     * The behavior is suitable for use with most calendar systems.
+     * It uses the {@code DAY_OF_WEEK} field and the {@code DAYS} unit,
+     * and assumes a seven day week.
+     *
+     * @param dayOfWeek  the day-of-week to move the date to, not null
+     * @return the previous day-of-week adjuster, not null
+     */
+    public static TemporalAdjuster previous(DayOfWeek dayOfWeek) {
+        return new RelativeDayOfWeek(3, dayOfWeek);
+    }
+
+    /**
+     * Returns the previous-or-same day-of-week adjuster, which adjusts the date to the
+     * first occurrence of the specified day-of-week before the date being adjusted
+     * unless it is already on that day in which case the same object is returned.
+     * <p>
+     * The ISO calendar system behaves as follows:<br>
+     * The input 2011-01-15 (a Saturday) for parameter (MONDAY) will return 2011-01-10 (five days earlier).<br>
+     * The input 2011-01-15 (a Saturday) for parameter (WEDNESDAY) will return 2011-01-12 (three days earlier).<br>
+     * The input 2011-01-15 (a Saturday) for parameter (SATURDAY) will return 2011-01-15 (same as input).
+     * <p>
+     * The behavior is suitable for use with most calendar systems.
+     * It uses the {@code DAY_OF_WEEK} field and the {@code DAYS} unit,
+     * and assumes a seven day week.
+     *
+     * @param dayOfWeek  the day-of-week to check for or move the date to, not null
+     * @return the previous-or-same day-of-week adjuster, not null
+     */
+    public static TemporalAdjuster previousOrSame(DayOfWeek dayOfWeek) {
+        return new RelativeDayOfWeek(1, dayOfWeek);
+    }
+
+    /**
+     * Implementation of next, previous or current day-of-week.
+     */
+    private static final class RelativeDayOfWeek implements TemporalAdjuster {
+        /** Whether the current date is a valid answer. */
+        private final int relative;
+        /** The day-of-week value, from 1 to 7. */
+        private final int dowValue;
+
+        private RelativeDayOfWeek(int relative, DayOfWeek dayOfWeek) {
+            Objects.requireNonNull(dayOfWeek, "dayOfWeek");
+            this.relative = relative;
+            this.dowValue = dayOfWeek.getValue();
+        }
+
+        @Override
+        public Temporal adjustInto(Temporal temporal) {
+            int calDow = temporal.get(DAY_OF_WEEK);
+            if (relative < 2 && calDow == dowValue) {
+                return temporal;
+            }
+            if ((relative & 1) == 0) {
+                int daysDiff = calDow - dowValue;
+                return temporal.plus(daysDiff >= 0 ? 7 - daysDiff : -daysDiff, DAYS);
+            } else {
+                int daysDiff = dowValue - calDow;
+                return temporal.minus(daysDiff >= 0 ? 7 - daysDiff : -daysDiff, DAYS);
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/Chrono.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,858 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.calendar.HijrahChrono;
+import java.time.calendar.JapaneseChrono;
+import java.time.calendar.MinguoChrono;
+import java.time.calendar.ThaiBuddhistChrono;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.TextStyle;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.ServiceLoader;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * A calendar system, used to organize and identify dates.
+ * <p>
+ * The main date and time API is built on the ISO calendar system.
+ * This class operates behind the scenes to represent the general concept of a calendar system.
+ * For example, the Japanese, Minguo, Thai Buddhist and others.
+ * <p>
+ * Most other calendar systems also operate on the shared concepts of year, month and day,
+ * linked to the cycles of the Earth around the Sun, and the Moon around the Earth.
+ * These shared concepts are defined by {@link ChronoField} and are availalbe
+ * for use by any {@code Chrono} implementation:
+ * <pre>
+ *   LocalDate isoDate = ...
+ *   ChronoLocalDate&lt;ThaiBuddhistChrono&gt; thaiDate = ...
+ *   int isoYear = isoDate.get(ChronoField.YEAR);
+ *   int thaiYear = thaiDate.get(ChronoField.YEAR);
+ * </pre>
+ * As shown, although the date objects are in different calendar systems, represented by different
+ * {@code Chrono} instances, both can be queried using the same constant on {@code ChronoField}.
+ * For a full discussion of the implications of this, see {@link ChronoLocalDate}.
+ * In general, the advice is to use the known ISO-based {@code LocalDate}, rather than
+ * {@code ChronoLocalDate}.
+ * <p>
+ * While a {@code Chrono} object typically uses {@code ChronoField} and is based on
+ * an era, year-of-era, month-of-year, day-of-month model of a date, this is not required.
+ * A {@code Chrono} instance may represent a totally different kind of calendar system,
+ * such as the Mayan.
+ * <p>
+ * In practical terms, the {@code Chrono} instance also acts as a factory.
+ * The {@link #of(String)} method allows an instance to be looked up by identifier,
+ * while the {@link #ofLocale(Locale)} method allows lookup by locale.
+ * <p>
+ * The {@code Chrono} instance provides a set of methods to create {@code ChronoLocalDate} instances.
+ * The date classes are used to manipulate specific dates.
+ * <p><ul>
+ * <li> {@link #dateNow() dateNow()}
+ * <li> {@link #dateNow(Clock) dateNow(clock)}
+ * <li> {@link #dateNow(ZoneId) dateNow(zone)}
+ * <li> {@link #date(int, int, int) date(yearProleptic, month, day)}
+ * <li> {@link #date(Era, int, int, int) date(era, yearOfEra, month, day)}
+ * <li> {@link #dateYearDay(int, int) dateYearDay(yearProleptic, dayOfYear)}
+ * <li> {@link #dateYearDay(Era, int, int) dateYearDay(era, yearOfEra, dayOfYear)}
+ * <li> {@link #date(TemporalAccessor) date(TemporalAccessor)}
+ * </ul><p>
+ *
+ * <p id="addcalendars">Adding New Calendars</p>
+ * The set of available chronologies can be extended by applications.
+ * Adding a new calendar system requires the writing of an implementation of
+ * {@code Chrono}, {@code ChronoLocalDate} and {@code Era}.
+ * The majority of the logic specific to the calendar system will be in
+ * {@code ChronoLocalDate}. The {@code Chrono} subclass acts as a factory.
+ * <p>
+ * To permit the discovery of additional chronologies, the {@link java.util.ServiceLoader ServiceLoader}
+ * is used. A file must be added to the {@code META-INF/services} directory with the
+ * name 'java.time.temporal.Chrono' listing the implementation classes.
+ * See the ServiceLoader for more details on service loading.
+ * For lookup by id or calendarType, the system provided calendars are found
+ * first followed by application provided calendars.
+ * <p>
+ * Each chronology must define a chronology ID that is unique within the system.
+ * If the chronology represents a calendar system defined by the
+ * <em>Unicode Locale Data Markup Language (LDML)</em> specification then that
+ * calendar type should also be specified.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class must be implemented with care to ensure other classes operate correctly.
+ * All implementations that can be instantiated must be final, immutable and thread-safe.
+ * Subclasses should be Serializable wherever possible.
+ *
+ * @param <C> the type of the implementing subclass
+ * @since 1.8
+ */
+public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?>> {
+
+    /**
+     * Map of available calendars by ID.
+     */
+    private static final ConcurrentHashMap<String, Chrono<?>> CHRONOS_BY_ID = new ConcurrentHashMap<>();
+    /**
+     * Map of available calendars by calendar type.
+     */
+    private static final ConcurrentHashMap<String, Chrono<?>> CHRONOS_BY_TYPE = new ConcurrentHashMap<>();
+
+    /**
+     * Register a Chrono by ID and type for lookup by {@link #of(java.lang.String)}.
+     * Chronos must not be registered until they are completely constructed.
+     * Specifically, not in the constructor of Chrono.
+     * @param chrono the chronology to register; not null
+     */
+    private static void registerChrono(Chrono chrono) {
+        Chrono<?> prev = CHRONOS_BY_ID.putIfAbsent(chrono.getId(), chrono);
+        if (prev == null) {
+            String type = chrono.getCalendarType();
+            if (type != null) {
+                CHRONOS_BY_TYPE.putIfAbsent(type, chrono);
+            }
+        }
+    }
+
+    /**
+     * Initialization of the maps from id and type to Chrono.
+     * The ServiceLoader is used to find and register any implementations
+     * of {@link javax.time.temporal.Chrono} found in the bootclass loader.
+     * The built-in chronologies are registered explicitly.
+     * Calendars configured via the Thread's context classloader are local
+     * to that thread and are ignored.
+     * <p>
+     * The initialization is done only once using the registration
+     * of the ISOChrono as the test and the final step.
+     * Multiple threads may perform the initialization concurrently.
+     * Only the first registration of each Chrono is retained by the
+     * ConcurrentHashMap.
+     * @return true if the cache was initialized
+     */
+    private static boolean initCache() {
+        if (CHRONOS_BY_ID.get("ISO") == null) {
+            // Initialization is incomplete
+            @SuppressWarnings("rawtypes")
+            ServiceLoader<Chrono> loader =  ServiceLoader.load(Chrono.class, null);
+            for (Chrono<?> chrono : loader) {
+                registerChrono(chrono);
+            }
+
+            // Register these calendars; the ServiceLoader configuration is not used
+            registerChrono(HijrahChrono.INSTANCE);
+            registerChrono(JapaneseChrono.INSTANCE);
+            registerChrono(MinguoChrono.INSTANCE);
+            registerChrono(ThaiBuddhistChrono.INSTANCE);
+
+            // finally, register ISOChrono to mark initialization is complete
+            registerChrono(ISOChrono.INSTANCE);
+            return true;
+        }
+        return false;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Chrono} from a temporal object.
+     * <p>
+     * A {@code TemporalAccessor} represents some form of date and time information.
+     * This factory converts the arbitrary temporal object to an instance of {@code Chrono}.
+     * If the specified temporal object does not have a chronology, {@link ISOChrono} is returned.
+     * <p>
+     * The conversion will obtain the chronology using {@link Queries#chrono()}.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used in queries via method reference, {@code Chrono::from}.
+     *
+     * @param temporal  the temporal to convert, not null
+     * @return the chronology, not null
+     * @throws DateTimeException if unable to convert to an {@code Chrono}
+     */
+    public static Chrono<?> from(TemporalAccessor temporal) {
+        Objects.requireNonNull(temporal, "temporal");
+        Chrono<?> obj = temporal.query(Queries.chrono());
+        return (obj != null ? obj : ISOChrono.INSTANCE);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Chrono} from a locale.
+     * <p>
+     * The locale can be used to identify a calendar.
+     * This uses {@link Locale#getUnicodeLocaleType(String)} to obtain the "ca" key
+     * to identify the calendar system.
+     * <p>
+     * If the locale does not contain calendar system information, the standard
+     * ISO calendar system is used.
+     *
+     * @param locale  the locale to use to obtain the calendar system, not null
+     * @return the calendar system associated with the locale, not null
+     * @throws DateTimeException if the locale-specified calendar cannot be found
+     */
+    public static Chrono<?> ofLocale(Locale locale) {
+        Objects.requireNonNull(locale, "locale");
+        String type = locale.getUnicodeLocaleType("ca");
+        if (type == null) {
+            return ISOChrono.INSTANCE;
+        } else if ("iso".equals(type) || "iso8601".equals(type)) {
+            return ISOChrono.INSTANCE;
+        } else {
+            Chrono<?> chrono = CHRONOS_BY_TYPE.get(type);
+            if (chrono == null) {
+                throw new DateTimeException("Unknown calendar system: " + type);
+            }
+            return chrono;
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Chrono} from a chronology ID or
+     * calendar system type.
+     * <p>
+     * This returns a chronology based on either the ID or the type.
+     * The {@link #getId() chronology ID} uniquely identifies the chronology.
+     * The {@link #getCalendarType() calendar system type} is defined by the LDML specification.
+     * <p>
+     * The chronology may be a system chronology or a chronology
+     * provided by the application via ServiceLoader configuration.
+     * <p>
+     * Since some calendars can be customized, the ID or type typically refers
+     * to the default customization. For example, the Gregorian calendar can have multiple
+     * cutover dates from the Julian, but the lookup only provides the default cutover date.
+     *
+     * @param id  the chronology ID or calendar system type, not null
+     * @return the chronology with the identifier requested, not null
+     * @throws DateTimeException if the chronology cannot be found
+     */
+    public static Chrono<?> of(String id) {
+        Objects.requireNonNull(id, "id");
+        do {
+            Chrono chrono = of0(id);
+            if (chrono != null) {
+                return chrono;
+            }
+            // If not found, do the initialization (once) and repeat the lookup
+        } while (initCache());
+
+        // Look for a Chrono using ServiceLoader of the Thread's ContextClassLoader
+        // Application provided Chronologies must not be cached
+        @SuppressWarnings("rawtypes")
+        ServiceLoader<Chrono> loader = ServiceLoader.load(Chrono.class);
+        for (Chrono<?> chrono : loader) {
+            if (id.equals(chrono.getId()) || id.equals(chrono.getCalendarType())) {
+                return chrono;
+            }
+        }
+        throw new DateTimeException("Unknown chronology: " + id);
+    }
+
+    /**
+     * Obtains an instance of {@code Chrono} from a chronology ID or
+     * calendar system type.
+     *
+     * @param id  the chronology ID or calendar system type, not null
+     * @return the chronology with the identifier requested, or {@code null} if not found
+     */
+    private static Chrono<?> of0(String id) {
+        Chrono<?> chrono = CHRONOS_BY_ID.get(id);
+        if (chrono == null) {
+            chrono = CHRONOS_BY_TYPE.get(id);
+        }
+        return chrono;
+    }
+
+    /**
+     * Returns the available chronologies.
+     * <p>
+     * Each returned {@code Chrono} is available for use in the system.
+     * The set of chronologies includes the system chronologies and
+     * any chronologies provided by the application via ServiceLoader
+     * configuration.
+     *
+     * @return the independent, modifiable set of the available chronology IDs, not null
+     */
+    public static Set<Chrono<?>> getAvailableChronologies() {
+        initCache();       // force initialization
+        HashSet<Chrono<?>> chronos = new HashSet<>(CHRONOS_BY_ID.values());
+
+        /// Add in Chronologies from the ServiceLoader configuration
+        @SuppressWarnings("rawtypes")
+        ServiceLoader<Chrono> loader = ServiceLoader.load(Chrono.class);
+        for (Chrono<?> chrono : loader) {
+            chronos.add(chrono);
+        }
+        return chronos;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a local date-time from the a date and time.
+     * <p>
+     * This combines a {@link ChronoLocalDate}, which provides the {@code Chrono},
+     * with a {@link LocalTime} to produce a {@link ChronoLocalDateTime}.
+     * <p>
+     * This method is intended for chronology implementations.
+     * It uses a standard implementation that is shared for all chronologies.
+     *
+     * @param <R>  the chronology of the date
+     * @param date  the date, not null
+     * @param time  the time, not null
+     * @return the local date-time combining the input date and time, not null
+     */
+    public static <R extends Chrono<R>> ChronoLocalDateTime<R> dateTime(ChronoLocalDate<R> date, LocalTime time) {
+        return ChronoLocalDateTimeImpl.of(date, time);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Creates an instance.
+     */
+    protected Chrono() {
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Casts the {@code Temporal} to {@code ChronoLocalDate} with the same chronology.
+     *
+     * @param temporal  a date-time to cast, not null
+     * @return the date-time checked and cast to {@code ChronoLocalDate}, not null
+     * @throws ClassCastException if the date-time cannot be cast to ChronoLocalDate
+     *  or the chronology is not equal this Chrono
+     */
+    ChronoLocalDate<C> ensureChronoLocalDate(Temporal temporal) {
+        @SuppressWarnings("unchecked")
+        ChronoLocalDate<C> other = (ChronoLocalDate<C>) temporal;
+        if (this.equals(other.getChrono()) == false) {
+            throw new ClassCastException("Chrono mismatch, expected: " + getId() + ", actual: " + other.getChrono().getId());
+        }
+        return other;
+    }
+
+    /**
+     * Casts the {@code Temporal} to {@code ChronoLocalDateTime} with the same chronology.
+     *
+     * @param temporal   a date-time to cast, not null
+     * @return the date-time checked and cast to {@code ChronoLocalDateTime}, not null
+     * @throws ClassCastException if the date-time cannot be cast to ChronoLocalDateTimeImpl
+     *  or the chronology is not equal this Chrono
+     */
+    ChronoLocalDateTimeImpl<C> ensureChronoLocalDateTime(Temporal temporal) {
+        @SuppressWarnings("unchecked")
+        ChronoLocalDateTimeImpl<C> other = (ChronoLocalDateTimeImpl<C>) temporal;
+        if (this.equals(other.getDate().getChrono()) == false) {
+            throw new ClassCastException("Chrono mismatch, required: " + getId()
+                    + ", supplied: " + other.getDate().getChrono().getId());
+        }
+        return other;
+    }
+
+    /**
+     * Casts the {@code Temporal} to {@code ChronoZonedDateTimeImpl} with the same chronology.
+     *
+     * @param temporal  a date-time to cast, not null
+     * @return the date-time checked and cast to {@code ChronoZonedDateTimeImpl}, not null
+     * @throws ClassCastException if the date-time cannot be cast to ChronoZonedDateTimeImpl
+     *  or the chronology is not equal this Chrono
+     */
+    ChronoZonedDateTimeImpl<C> ensureChronoZonedDateTime(Temporal temporal) {
+        @SuppressWarnings("unchecked")
+        ChronoZonedDateTimeImpl<C> other = (ChronoZonedDateTimeImpl<C>) temporal;
+        if (this.equals(other.getDate().getChrono()) == false) {
+            throw new ClassCastException("Chrono mismatch, required: " + getId()
+                    + ", supplied: " + other.getDate().getChrono().getId());
+        }
+        return other;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the ID of the chronology.
+     * <p>
+     * The ID uniquely identifies the {@code Chrono}.
+     * It can be used to lookup the {@code Chrono} using {@link #of(String)}.
+     *
+     * @return the chronology ID, not null
+     * @see #getCalendarType()
+     */
+    public abstract String getId();
+
+    /**
+     * Gets the calendar type of the underlying calendar system.
+     * <p>
+     * The calendar type is an identifier defined by the
+     * <em>Unicode Locale Data Markup Language (LDML)</em> specification.
+     * It can be used to lookup the {@code Chrono} using {@link #of(String)}.
+     * It can also be used as part of a locale, accessible via
+     * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
+     *
+     * @return the calendar system type, null if the calendar is not defined by LDML
+     * @see #getId()
+     */
+    public abstract String getCalendarType();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a local date in this chronology from the era, year-of-era,
+     * month-of-year and day-of-month fields.
+     *
+     * @param era  the era of the correct type for the chronology, not null
+     * @param yearOfEra  the chronology year-of-era
+     * @param month  the chronology month-of-year
+     * @param dayOfMonth  the chronology day-of-month
+     * @return the local date in this chronology, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    public ChronoLocalDate<C> date(Era<C> era, int yearOfEra, int month, int dayOfMonth) {
+        return date(prolepticYear(era, yearOfEra), month, dayOfMonth);
+    }
+
+    /**
+     * Obtains a local date in this chronology from the proleptic-year,
+     * month-of-year and day-of-month fields.
+     *
+     * @param prolepticYear  the chronology proleptic-year
+     * @param month  the chronology month-of-year
+     * @param dayOfMonth  the chronology day-of-month
+     * @return the local date in this chronology, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    public abstract ChronoLocalDate<C> date(int prolepticYear, int month, int dayOfMonth);
+
+    /**
+     * Obtains a local date in this chronology from the era, year-of-era and
+     * day-of-year fields.
+     *
+     * @param era  the era of the correct type for the chronology, not null
+     * @param yearOfEra  the chronology year-of-era
+     * @param dayOfYear  the chronology day-of-year
+     * @return the local date in this chronology, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    public ChronoLocalDate<C> dateYearDay(Era<C> era, int yearOfEra, int dayOfYear) {
+        return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear);
+    }
+
+    /**
+     * Obtains a local date in this chronology from the proleptic-year and
+     * day-of-year fields.
+     *
+     * @param prolepticYear  the chronology proleptic-year
+     * @param dayOfYear  the chronology day-of-year
+     * @return the local date in this chronology, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    public abstract ChronoLocalDate<C> dateYearDay(int prolepticYear, int dayOfYear);
+
+    /**
+     * Obtains a local date in this chronology from another temporal object.
+     * <p>
+     * This creates a date in this chronology based on the specified {@code TemporalAccessor}.
+     * <p>
+     * The standard mechanism for conversion between date types is the
+     * {@link ChronoField#EPOCH_DAY local epoch-day} field.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the local date in this chronology, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    public abstract ChronoLocalDate<C> date(TemporalAccessor temporal);
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains the current local date in this chronology from the system clock in the default time-zone.
+     * <p>
+     * This will query the {@link Clock#systemDefaultZone() system clock} in the default
+     * time-zone to obtain the current date.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     * <p>
+     * This implementation uses {@link #dateNow(Clock)}.
+     *
+     * @return the current local date using the system clock and default time-zone, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    public ChronoLocalDate<C> dateNow() {
+        return dateNow(Clock.systemDefaultZone());
+    }
+
+    /**
+     * Obtains the current local date in this chronology from the system clock in the specified time-zone.
+     * <p>
+     * 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.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @param zone  the zone ID to use, not null
+     * @return the current local date using the system clock, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    public ChronoLocalDate<C> dateNow(ZoneId zone) {
+        return dateNow(Clock.system(zone));
+    }
+
+    /**
+     * Obtains the current local date in this chronology from the specified clock.
+     * <p>
+     * This will query the specified clock to obtain the current date - today.
+     * Using this method allows the use of an alternate clock for testing.
+     * The alternate clock may be introduced using {@link Clock dependency injection}.
+     *
+     * @param clock  the clock to use, not null
+     * @return the current local date, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    public ChronoLocalDate<C> dateNow(Clock clock) {
+        Objects.requireNonNull(clock, "clock");
+        return date(LocalDate.now(clock));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a local date-time in this chronology from another temporal object.
+     * <p>
+     * This creates a date-time in this chronology based on the specified {@code TemporalAccessor}.
+     * <p>
+     * The date of the date-time should be equivalent to that obtained by calling
+     * {@link #date(TemporalAccessor)}.
+     * The standard mechanism for conversion between time types is the
+     * {@link ChronoField#NANO_OF_DAY nano-of-day} field.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the local date-time in this chronology, not null
+     * @throws DateTimeException if unable to create the date-time
+     */
+    public ChronoLocalDateTime<C> localDateTime(TemporalAccessor temporal) {
+        try {
+            return date(temporal).atTime(LocalTime.from(temporal));
+        } catch (DateTimeException ex) {
+            throw new DateTimeException("Unable to obtain ChronoLocalDateTime from TemporalAccessor: " + temporal.getClass(), ex);
+        }
+    }
+
+    /**
+     * Obtains a zoned date-time in this chronology from another temporal object.
+     * <p>
+     * This creates a date-time in this chronology based on the specified {@code TemporalAccessor}.
+     * <p>
+     * This should obtain a {@code ZoneId} using {@link ZoneId#from(TemporalAccessor)}.
+     * The date-time should be obtained by obtaining an {@code Instant}.
+     * If that fails, the local date-time should be used.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the zoned date-time in this chronology, not null
+     * @throws DateTimeException if unable to create the date-time
+     */
+    public ChronoZonedDateTime<C> zonedDateTime(TemporalAccessor temporal) {
+        try {
+            ZoneId zone = ZoneId.from(temporal);
+            try {
+                Instant instant = Instant.from(temporal);
+                return zonedDateTime(instant, zone);
+
+            } catch (DateTimeException ex1) {
+                ChronoLocalDateTimeImpl<C> cldt = ensureChronoLocalDateTime(localDateTime(temporal));
+                return ChronoZonedDateTimeImpl.ofBest(cldt, zone, null);
+            }
+        } catch (DateTimeException ex) {
+            throw new DateTimeException("Unable to obtain ChronoZonedDateTime from TemporalAccessor: " + temporal.getClass(), ex);
+        }
+    }
+
+    /**
+     * Obtains a zoned date-time in this chronology from an {@code Instant}.
+     * <p>
+     * This creates a zoned date-time with the same instant as that specified.
+     *
+     * @param instant  the instant to create the date-time from, not null
+     * @param zone  the time-zone, not null
+     * @return the zoned date-time, not null
+     * @throws DateTimeException if the result exceeds the supported range
+     */
+    public ChronoZonedDateTime<C> zonedDateTime(Instant instant, ZoneId zone) {
+        return ChronoZonedDateTimeImpl.ofInstant(this, instant, zone);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified year is a leap year.
+     * <p>
+     * A leap-year is a year of a longer length than normal.
+     * The exact meaning is determined by the chronology according to the following constraints.
+     * <p><ul>
+     * <li>a leap-year must imply a year-length longer than a non leap-year.
+     * <li>a chronology that does not support the concept of a year must return false.
+     * </ul><p>
+     *
+     * @param prolepticYear  the proleptic-year to check, not validated for range
+     * @return true if the year is a leap year
+     */
+    public abstract boolean isLeapYear(long prolepticYear);
+
+    /**
+     * Calculates the proleptic-year given the era and year-of-era.
+     * <p>
+     * This combines the era and year-of-era into the single proleptic-year field.
+     *
+     * @param era  the era of the correct type for the chronology, not null
+     * @param yearOfEra  the chronology year-of-era
+     * @return the proleptic-year
+     * @throws DateTimeException if unable to convert
+     */
+    public abstract int prolepticYear(Era<C> era, int yearOfEra);
+
+    /**
+     * Creates the chronology era object from the numeric value.
+     * <p>
+     * The era is, conceptually, the largest division of the time-line.
+     * Most calendar systems have a single epoch dividing the time-line into two eras.
+     * However, some have multiple eras, such as one for the reign of each leader.
+     * The exact meaning is determined by the chronology according to the following constraints.
+     * <p>
+     * The era in use at 1970-01-01 must have the value 1.
+     * Later eras must have sequentially higher values.
+     * Earlier eras must have sequentially lower values.
+     * Each chronology must refer to an enum or similar singleton to provide the era values.
+     * <p>
+     * This method returns the singleton era of the correct type for the specified era value.
+     *
+     * @param eraValue  the era value
+     * @return the calendar system era, not null
+     * @throws DateTimeException if unable to create the era
+     */
+    public abstract Era<C> eraOf(int eraValue);
+
+    /**
+     * Gets the list of eras for the chronology.
+     * <p>
+     * Most calendar systems have an era, within which the year has meaning.
+     * If the calendar system does not support the concept of eras, an empty
+     * list must be returned.
+     *
+     * @return the list of eras for the chronology, may be immutable, not null
+     */
+    public abstract List<Era<C>> eras();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * All fields can be expressed as a {@code long} integer.
+     * This method returns an object that describes the valid range for that value.
+     * <p>
+     * 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.
+     * <p>
+     * This method will return a result whether or not the chronology supports the field.
+     *
+     * @param field  the field to get the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     */
+    public abstract ValueRange range(ChronoField field);
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the textual representation of this chronology.
+     * <p>
+     * This returns the textual name used to identify the chronology.
+     * The parameters control the style of the returned text and the locale.
+     *
+     * @param style  the style of the text required, not null
+     * @param locale  the locale to use, not null
+     * @return the text value of the chronology, not null
+     */
+    public String getText(TextStyle style, Locale locale) {
+        return new DateTimeFormatterBuilder().appendChronoText(style).toFormatter(locale).print(new TemporalAccessor() {
+            @Override
+            public boolean isSupported(TemporalField field) {
+                return false;
+            }
+            @Override
+            public long getLong(TemporalField field) {
+                throw new DateTimeException("Unsupported field: " + field);
+            }
+            @SuppressWarnings("unchecked")
+            @Override
+            public <R> R query(TemporalQuery<R> query) {
+                if (query == Queries.chrono()) {
+                    return (R) Chrono.this;
+                }
+                return TemporalAccessor.super.query(query);
+            }
+        });
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this chronology to another chronology.
+     * <p>
+     * The comparison order first by the chronology ID string, then by any
+     * additional information specific to the subclass.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     * <p>
+     * The default implementation compares the chronology ID.
+     * Subclasses must compare any additional state that they store.
+     *
+     * @param other  the other chronology to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     */
+    @Override
+    public int compareTo(Chrono<?> other) {
+        return getId().compareTo(other.getId());
+    }
+
+    /**
+     * Checks if this chronology is equal to another chronology.
+     * <p>
+     * The comparison is based on the entire state of the object.
+     * <p>
+     * The default implementation checks the type and calls {@link #compareTo(Chrono)}.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other chronology
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+           return true;
+        }
+        if (obj instanceof Chrono) {
+            return compareTo((Chrono<?>) obj) == 0;
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this chronology.
+     * <p>
+     * The default implementation is based on the ID and class.
+     * Subclasses should add any additional state that they store.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return getClass().hashCode() ^ getId().hashCode();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this chronology as a {@code String}, using the ID.
+     *
+     * @return a string representation of this chronology, not null
+     */
+    @Override
+    public String toString() {
+        return getId();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>.
+     * <pre>
+     *  out.writeByte(7);  // identifies this as a Chrono
+     * out.writeUTF(chronoId);
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.CHRONO_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     * @return never
+     * @throws InvalidObjectException always
+     */
+    private Object readResolve() throws ObjectStreamException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        out.writeUTF(getId());
+    }
+
+    static Chrono<?> readExternal(DataInput in) throws IOException {
+        String id = in.readUTF();
+        return Chrono.of(id);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/ChronoField.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,610 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.ERAS;
+import static java.time.temporal.ChronoUnit.FOREVER;
+import static java.time.temporal.ChronoUnit.HALF_DAYS;
+import static java.time.temporal.ChronoUnit.HOURS;
+import static java.time.temporal.ChronoUnit.MICROS;
+import static java.time.temporal.ChronoUnit.MILLIS;
+import static java.time.temporal.ChronoUnit.MINUTES;
+import static java.time.temporal.ChronoUnit.MONTHS;
+import static java.time.temporal.ChronoUnit.NANOS;
+import static java.time.temporal.ChronoUnit.SECONDS;
+import static java.time.temporal.ChronoUnit.WEEKS;
+import static java.time.temporal.ChronoUnit.YEARS;
+
+import java.time.DayOfWeek;
+import java.time.Instant;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeBuilder;
+
+/**
+ * A standard set of fields.
+ * <p>
+ * This set of fields provide field-based access to manipulate a date, time or date-time.
+ * The standard set of fields can be extended by implementing {@link TemporalField}.
+ * <p>
+ * These fields are intended to be applicable in multiple calendar systems.
+ * For example, most non-ISO calendar systems define dates as a year, month and day,
+ * just with slightly different rules.
+ * The documentation of each field explains how it operates.
+ *
+ * <h3>Specification for implementors</h3>
+ * This is a final, immutable and thread-safe enum.
+ *
+ * @since 1.8
+ */
+public enum ChronoField implements TemporalField {
+
+    /**
+     * The nano-of-second.
+     * <p>
+     * This counts the nanosecond within the second, from 0 to 999,999,999.
+     * This field has the same meaning for all calendar systems.
+     * <p>
+     * This field is used to represent the nano-of-second handling any fraction of the second.
+     * Implementations of {@code TemporalAccessor} should provide a value for this field if
+     * they can return a value for {@link #SECOND_OF_MINUTE}, {@link #SECOND_OF_DAY} or
+     * {@link #INSTANT_SECONDS} filling unknown precision with zero.
+     * <p>
+     * When this field is used for setting a value, it should set as much precision as the
+     * object stores, using integer division to remove excess precision.
+     * For example, if the {@code TemporalAccessor} stores time to millisecond precision,
+     * then the nano-of-second must be divided by 1,000,000 before replacing the milli-of-second.
+     */
+    NANO_OF_SECOND("NanoOfSecond", NANOS, SECONDS, ValueRange.of(0, 999_999_999)),
+    /**
+     * The nano-of-day.
+     * <p>
+     * This counts the nanosecond within the day, from 0 to (24 * 60 * 60 * 1,000,000,000) - 1.
+     * This field has the same meaning for all calendar systems.
+     * <p>
+     * This field is used to represent the nano-of-day handling any fraction of the second.
+     * Implementations of {@code TemporalAccessor} should provide a value for this field if
+     * they can return a value for {@link #SECOND_OF_DAY} filling unknown precision with zero.
+     */
+    NANO_OF_DAY("NanoOfDay", NANOS, DAYS, ValueRange.of(0, 86400L * 1000_000_000L - 1)),
+    /**
+     * The micro-of-second.
+     * <p>
+     * This counts the microsecond within the second, from 0 to 999,999.
+     * This field has the same meaning for all calendar systems.
+     * <p>
+     * This field is used to represent the micro-of-second handling any fraction of the second.
+     * Implementations of {@code TemporalAccessor} should provide a value for this field if
+     * they can return a value for {@link #SECOND_OF_MINUTE}, {@link #SECOND_OF_DAY} or
+     * {@link #INSTANT_SECONDS} filling unknown precision with zero.
+     * <p>
+     * When this field is used for setting a value, it should behave in the same way as
+     * setting {@link #NANO_OF_SECOND} with the value multiplied by 1,000.
+     */
+    MICRO_OF_SECOND("MicroOfSecond", MICROS, SECONDS, ValueRange.of(0, 999_999)),
+    /**
+     * The micro-of-day.
+     * <p>
+     * This counts the microsecond within the day, from 0 to (24 * 60 * 60 * 1,000,000) - 1.
+     * This field has the same meaning for all calendar systems.
+     * <p>
+     * This field is used to represent the micro-of-day handling any fraction of the second.
+     * Implementations of {@code TemporalAccessor} should provide a value for this field if
+     * they can return a value for {@link #SECOND_OF_DAY} filling unknown precision with zero.
+     * <p>
+     * When this field is used for setting a value, it should behave in the same way as
+     * setting {@link #NANO_OF_DAY} with the value multiplied by 1,000.
+     */
+    MICRO_OF_DAY("MicroOfDay", MICROS, DAYS, ValueRange.of(0, 86400L * 1000_000L - 1)),
+    /**
+     * The milli-of-second.
+     * <p>
+     * This counts the millisecond within the second, from 0 to 999.
+     * This field has the same meaning for all calendar systems.
+     * <p>
+     * This field is used to represent the milli-of-second handling any fraction of the second.
+     * Implementations of {@code TemporalAccessor} should provide a value for this field if
+     * they can return a value for {@link #SECOND_OF_MINUTE}, {@link #SECOND_OF_DAY} or
+     * {@link #INSTANT_SECONDS} filling unknown precision with zero.
+     * <p>
+     * When this field is used for setting a value, it should behave in the same way as
+     * setting {@link #NANO_OF_SECOND} with the value multiplied by 1,000,000.
+     */
+    MILLI_OF_SECOND("MilliOfSecond", MILLIS, SECONDS, ValueRange.of(0, 999)),
+    /**
+     * The milli-of-day.
+     * <p>
+     * This counts the millisecond within the day, from 0 to (24 * 60 * 60 * 1,000) - 1.
+     * This field has the same meaning for all calendar systems.
+     * <p>
+     * This field is used to represent the milli-of-day handling any fraction of the second.
+     * Implementations of {@code TemporalAccessor} should provide a value for this field if
+     * they can return a value for {@link #SECOND_OF_DAY} filling unknown precision with zero.
+     * <p>
+     * When this field is used for setting a value, it should behave in the same way as
+     * setting {@link #NANO_OF_DAY} with the value multiplied by 1,000,000.
+     */
+    MILLI_OF_DAY("MilliOfDay", MILLIS, DAYS, ValueRange.of(0, 86400L * 1000L - 1)),
+    /**
+     * The second-of-minute.
+     * <p>
+     * This counts the second within the minute, from 0 to 59.
+     * This field has the same meaning for all calendar systems.
+     */
+    SECOND_OF_MINUTE("SecondOfMinute", SECONDS, MINUTES, ValueRange.of(0, 59)),
+    /**
+     * The second-of-day.
+     * <p>
+     * This counts the second within the day, from 0 to (24 * 60 * 60) - 1.
+     * This field has the same meaning for all calendar systems.
+     */
+    SECOND_OF_DAY("SecondOfDay", SECONDS, DAYS, ValueRange.of(0, 86400L - 1)),
+    /**
+     * The minute-of-hour.
+     * <p>
+     * This counts the minute within the hour, from 0 to 59.
+     * This field has the same meaning for all calendar systems.
+     */
+    MINUTE_OF_HOUR("MinuteOfHour", MINUTES, HOURS, ValueRange.of(0, 59)),
+    /**
+     * The minute-of-day.
+     * <p>
+     * This counts the minute within the day, from 0 to (24 * 60) - 1.
+     * This field has the same meaning for all calendar systems.
+     */
+    MINUTE_OF_DAY("MinuteOfDay", MINUTES, DAYS, ValueRange.of(0, (24 * 60) - 1)),
+    /**
+     * The hour-of-am-pm.
+     * <p>
+     * This counts the hour within the AM/PM, from 0 to 11.
+     * This is the hour that would be observed on a standard 12-hour digital clock.
+     * This field has the same meaning for all calendar systems.
+     */
+    HOUR_OF_AMPM("HourOfAmPm", HOURS, HALF_DAYS, ValueRange.of(0, 11)),
+    /**
+     * The clock-hour-of-am-pm.
+     * <p>
+     * This counts the hour within the AM/PM, from 1 to 12.
+     * This is the hour that would be observed on a standard 12-hour analog wall clock.
+     * This field has the same meaning for all calendar systems.
+     */
+    CLOCK_HOUR_OF_AMPM("ClockHourOfAmPm", HOURS, HALF_DAYS, ValueRange.of(1, 12)),
+    /**
+     * The hour-of-day.
+     * <p>
+     * This counts the hour within the day, from 0 to 23.
+     * This is the hour that would be observed on a standard 24-hour digital clock.
+     * This field has the same meaning for all calendar systems.
+     */
+    HOUR_OF_DAY("HourOfDay", HOURS, DAYS, ValueRange.of(0, 23)),
+    /**
+     * The clock-hour-of-day.
+     * <p>
+     * This counts the hour within the AM/PM, from 1 to 24.
+     * This is the hour that would be observed on a 24-hour analog wall clock.
+     * This field has the same meaning for all calendar systems.
+     */
+    CLOCK_HOUR_OF_DAY("ClockHourOfDay", HOURS, DAYS, ValueRange.of(1, 24)),
+    /**
+     * The am-pm-of-day.
+     * <p>
+     * This counts the AM/PM within the day, from 0 (AM) to 1 (PM).
+     * This field has the same meaning for all calendar systems.
+     */
+    AMPM_OF_DAY("AmPmOfDay", HALF_DAYS, DAYS, ValueRange.of(0, 1)),
+    /**
+     * The day-of-week, such as Tuesday.
+     * <p>
+     * This represents the standard concept of the day of the week.
+     * In the default ISO calendar system, this has values from Monday (1) to Sunday (7).
+     * The {@link DayOfWeek} class can be used to interpret the result.
+     * <p>
+     * Most non-ISO calendar systems also define a seven day week that aligns with ISO.
+     * Those calendar systems must also use the same numbering system, from Monday (1) to
+     * Sunday (7), which allows {@code DayOfWeek} to be used.
+     * <p>
+     * Calendar systems that do not have a standard seven day week should implement this field
+     * if they have a similar concept of named or numbered days within a period similar
+     * to a week. It is recommended that the numbering starts from 1.
+     */
+    DAY_OF_WEEK("DayOfWeek", DAYS, WEEKS, ValueRange.of(1, 7)),
+    /**
+     * The aligned day-of-week within a month.
+     * <p>
+     * This represents concept of the count of days within the period of a week
+     * where the weeks are aligned to the start of the month.
+     * This field is typically used with {@link #ALIGNED_WEEK_OF_MONTH}.
+     * <p>
+     * For example, in a calendar systems with a seven day week, the first aligned-week-of-month
+     * starts on day-of-month 1, the second aligned-week starts on day-of-month 8, and so on.
+     * Within each of these aligned-weeks, the days are numbered from 1 to 7 and returned
+     * as the value of this field.
+     * As such, day-of-month 1 to 7 will have aligned-day-of-week values from 1 to 7.
+     * And day-of-month 8 to 14 will repeat this with aligned-day-of-week values from 1 to 7.
+     * <p>
+     * Calendar systems that do not have a seven day week should typically implement this
+     * field in the same way, but using the alternate week length.
+     */
+    ALIGNED_DAY_OF_WEEK_IN_MONTH("AlignedDayOfWeekInMonth", DAYS, WEEKS, ValueRange.of(1, 7)),
+    /**
+     * The aligned day-of-week within a year.
+     * <p>
+     * This represents concept of the count of days within the period of a week
+     * where the weeks are aligned to the start of the year.
+     * This field is typically used with {@link #ALIGNED_WEEK_OF_YEAR}.
+     * <p>
+     * For example, in a calendar systems with a seven day week, the first aligned-week-of-year
+     * starts on day-of-year 1, the second aligned-week starts on day-of-year 8, and so on.
+     * Within each of these aligned-weeks, the days are numbered from 1 to 7 and returned
+     * as the value of this field.
+     * As such, day-of-year 1 to 7 will have aligned-day-of-week values from 1 to 7.
+     * And day-of-year 8 to 14 will repeat this with aligned-day-of-week values from 1 to 7.
+     * <p>
+     * Calendar systems that do not have a seven day week should typically implement this
+     * field in the same way, but using the alternate week length.
+     */
+    ALIGNED_DAY_OF_WEEK_IN_YEAR("AlignedDayOfWeekInYear", DAYS, WEEKS, ValueRange.of(1, 7)),
+    /**
+     * The day-of-month.
+     * <p>
+     * This represents the concept of the day within the month.
+     * In the default ISO calendar system, this has values from 1 to 31 in most months.
+     * April, June, September, November have days from 1 to 30, while February has days
+     * from 1 to 28, or 29 in a leap year.
+     * <p>
+     * Non-ISO calendar systems should implement this field using the most recognized
+     * day-of-month values for users of the calendar system.
+     * Normally, this is a count of days from 1 to the length of the month.
+     */
+    DAY_OF_MONTH("DayOfMonth", DAYS, MONTHS, ValueRange.of(1, 28, 31)),
+    /**
+     * The day-of-year.
+     * <p>
+     * This represents the concept of the day within the year.
+     * In the default ISO calendar system, this has values from 1 to 365 in standard
+     * years and 1 to 366 in leap years.
+     * <p>
+     * Non-ISO calendar systems should implement this field using the most recognized
+     * day-of-year values for users of the calendar system.
+     * Normally, this is a count of days from 1 to the length of the year.
+     */
+    DAY_OF_YEAR("DayOfYear", DAYS, YEARS, ValueRange.of(1, 365, 366)),
+    /**
+     * The epoch-day, based on the Java epoch of 1970-01-01 (ISO).
+     * <p>
+     * This field is the sequential count of days where 1970-01-01 (ISO) is zero.
+     * Note that this uses the <i>local</i> time-line, ignoring offset and time-zone.
+     * <p>
+     * This field is strictly defined to have the same meaning in all calendar systems.
+     * This is necessary to ensure interoperation between calendars.
+     */
+    EPOCH_DAY("EpochDay", DAYS, FOREVER, ValueRange.of((long) (Year.MIN_VALUE * 365.25), (long) (Year.MAX_VALUE * 365.25))),
+    /**
+     * The aligned week within a month.
+     * <p>
+     * This represents concept of the count of weeks within the period of a month
+     * where the weeks are aligned to the start of the month.
+     * This field is typically used with {@link #ALIGNED_DAY_OF_WEEK_IN_MONTH}.
+     * <p>
+     * For example, in a calendar systems with a seven day week, the first aligned-week-of-month
+     * starts on day-of-month 1, the second aligned-week starts on day-of-month 8, and so on.
+     * Thus, day-of-month values 1 to 7 are in aligned-week 1, while day-of-month values
+     * 8 to 14 are in aligned-week 2, and so on.
+     * <p>
+     * Calendar systems that do not have a seven day week should typically implement this
+     * field in the same way, but using the alternate week length.
+     */
+    ALIGNED_WEEK_OF_MONTH("AlignedWeekOfMonth", WEEKS, MONTHS, ValueRange.of(1, 4, 5)),
+    /**
+     * The aligned week within a year.
+     * <p>
+     * This represents concept of the count of weeks within the period of a year
+     * where the weeks are aligned to the start of the year.
+     * This field is typically used with {@link #ALIGNED_DAY_OF_WEEK_IN_YEAR}.
+     * <p>
+     * For example, in a calendar systems with a seven day week, the first aligned-week-of-year
+     * starts on day-of-year 1, the second aligned-week starts on day-of-year 8, and so on.
+     * Thus, day-of-year values 1 to 7 are in aligned-week 1, while day-of-year values
+     * 8 to 14 are in aligned-week 2, and so on.
+     * <p>
+     * Calendar systems that do not have a seven day week should typically implement this
+     * field in the same way, but using the alternate week length.
+     */
+    ALIGNED_WEEK_OF_YEAR("AlignedWeekOfYear", WEEKS, YEARS, ValueRange.of(1, 53)),
+    /**
+     * The month-of-year, such as March.
+     * <p>
+     * This represents the concept of the month within the year.
+     * In the default ISO calendar system, this has values from January (1) to December (12).
+     * <p>
+     * Non-ISO calendar systems should implement this field using the most recognized
+     * month-of-year values for users of the calendar system.
+     * Normally, this is a count of months starting from 1.
+     */
+    MONTH_OF_YEAR("MonthOfYear", MONTHS, YEARS, ValueRange.of(1, 12)),
+    /**
+     * The epoch-month based on the Java epoch of 1970-01-01.
+     * <p>
+     * This field is the sequential count of months where January 1970 (ISO) is zero.
+     * Note that this uses the <i>local</i> time-line, ignoring offset and time-zone.
+     * <p>
+     * Non-ISO calendar systems should also implement this field to represent a sequential
+     * count of months. It is recommended to define zero as the month of 1970-01-01 (ISO).
+     */
+    EPOCH_MONTH("EpochMonth", MONTHS, FOREVER, ValueRange.of((Year.MIN_VALUE - 1970L) * 12, (Year.MAX_VALUE - 1970L) * 12L - 1L)),
+    /**
+     * The year within the era.
+     * <p>
+     * This represents the concept of the year within the era.
+     * This field is typically used with {@link #ERA}.
+     * <p>
+     * The standard mental model for a date is based on three concepts - year, month and day.
+     * These map onto the {@code YEAR}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} fields.
+     * Note that there is no reference to eras.
+     * The full model for a date requires four concepts - era, year, month and day. These map onto
+     * the {@code ERA}, {@code YEAR_OF_ERA}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} fields.
+     * Whether this field or {@code YEAR} is used depends on which mental model is being used.
+     * See {@link ChronoLocalDate} for more discussion on this topic.
+     * <p>
+     * In the default ISO calendar system, there are two eras defined, 'BCE' and 'CE'.
+     * The era 'CE' is the one currently in use and year-of-era runs from 1 to the maximum value.
+     * The era 'BCE' is the previous era, and the year-of-era runs backwards.
+     * <p>
+     * For example, subtracting a year each time yield the following:<br>
+     * - year-proleptic 2  = 'CE' year-of-era 2<br>
+     * - year-proleptic 1  = 'CE' year-of-era 1<br>
+     * - year-proleptic 0  = 'BCE' year-of-era 1<br>
+     * - year-proleptic -1 = 'BCE' year-of-era 2<br>
+     * <p>
+     * Note that the ISO-8601 standard does not actually define eras.
+     * Note also that the ISO eras do not align with the well-known AD/BC eras due to the
+     * change between the Julian and Gregorian calendar systems.
+     * <p>
+     * Non-ISO calendar systems should implement this field using the most recognized
+     * year-of-era value for users of the calendar system.
+     * Since most calendar systems have only two eras, the year-of-era numbering approach
+     * will typically be the same as that used by the ISO calendar system.
+     * The year-of-era value should typically always be positive, however this is not required.
+     */
+    YEAR_OF_ERA("YearOfEra", YEARS, FOREVER, ValueRange.of(1, Year.MAX_VALUE, Year.MAX_VALUE + 1)),
+    /**
+     * The proleptic year, such as 2012.
+     * <p>
+     * This represents the concept of the year, counting sequentially and using negative numbers.
+     * The proleptic year is not interpreted in terms of the era.
+     * See {@link #YEAR_OF_ERA} for an example showing the mapping from proleptic year to year-of-era.
+     * <p>
+     * The standard mental model for a date is based on three concepts - year, month and day.
+     * These map onto the {@code YEAR}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} fields.
+     * Note that there is no reference to eras.
+     * The full model for a date requires four concepts - era, year, month and day. These map onto
+     * the {@code ERA}, {@code YEAR_OF_ERA}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} fields.
+     * Whether this field or {@code YEAR_OF_ERA} is used depends on which mental model is being used.
+     * See {@link ChronoLocalDate} for more discussion on this topic.
+     * <p>
+     * Non-ISO calendar systems should implement this field as follows.
+     * If the calendar system has only two eras, before and after a fixed date, then the
+     * proleptic-year value must be the same as the year-of-era value for the later era,
+     * and increasingly negative for the earlier era.
+     * If the calendar system has more than two eras, then the proleptic-year value may be
+     * defined with any appropriate value, although defining it to be the same as ISO may be
+     * the best option.
+     */
+    YEAR("Year", YEARS, FOREVER, ValueRange.of(Year.MIN_VALUE, Year.MAX_VALUE)),
+    /**
+     * The era.
+     * <p>
+     * This represents the concept of the era, which is the largest division of the time-line.
+     * This field is typically used with {@link #YEAR_OF_ERA}.
+     * <p>
+     * In the default ISO calendar system, there are two eras defined, 'BCE' and 'CE'.
+     * The era 'CE' is the one currently in use and year-of-era runs from 1 to the maximum value.
+     * The era 'BCE' is the previous era, and the year-of-era runs backwards.
+     * See {@link #YEAR_OF_ERA} for a full example.
+     * <p>
+     * Non-ISO calendar systems should implement this field to define eras.
+     * The value of the era that was active on 1970-01-01 (ISO) must be assigned the value 1.
+     * Earlier eras must have sequentially smaller values.
+     * Later eras must have sequentially larger values,
+     */
+    ERA("Era", ERAS, FOREVER, ValueRange.of(0, 1)),
+    /**
+     * The instant epoch-seconds.
+     * <p>
+     * This represents the concept of the sequential count of seconds where
+     * 1970-01-01T00:00Z (ISO) is zero.
+     * This field may be used with {@link #NANO_OF_DAY} to represent the fraction of the day.
+     * <p>
+     * An {@link Instant} represents an instantaneous point on the time-line.
+     * On their own they have no elements which allow a local date-time to be obtained.
+     * Only when paired with an offset or time-zone can the local date or time be found.
+     * This field allows the seconds part of the instant to be queried.
+     * <p>
+     * This field is strictly defined to have the same meaning in all calendar systems.
+     * This is necessary to ensure interoperation between calendars.
+     */
+    INSTANT_SECONDS("InstantSeconds", SECONDS, FOREVER, ValueRange.of(Long.MIN_VALUE, Long.MAX_VALUE)),
+    /**
+     * The offset from UTC/Greenwich.
+     * <p>
+     * This represents the concept of the offset in seconds of local time from UTC/Greenwich.
+     * <p>
+     * A {@link ZoneOffset} represents the period of time that local time differs from UTC/Greenwich.
+     * This is usually a fixed number of hours and minutes.
+     * It is equivalent to the {@link ZoneOffset#getTotalSeconds() total amount} of the offset in seconds.
+     * For example, during the winter Paris has an offset of {@code +01:00}, which is 3600 seconds.
+     * <p>
+     * This field is strictly defined to have the same meaning in all calendar systems.
+     * This is necessary to ensure interoperation between calendars.
+     */
+    OFFSET_SECONDS("OffsetSeconds", SECONDS, FOREVER, ValueRange.of(-18 * 3600, 18 * 3600));
+
+    private final String name;
+    private final TemporalUnit baseUnit;
+    private final TemporalUnit rangeUnit;
+    private final ValueRange range;
+
+    private ChronoField(String name, TemporalUnit baseUnit, TemporalUnit rangeUnit, ValueRange range) {
+        this.name = name;
+        this.baseUnit = baseUnit;
+        this.rangeUnit = rangeUnit;
+        this.range = range;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public TemporalUnit getBaseUnit() {
+        return baseUnit;
+    }
+
+    @Override
+    public TemporalUnit getRangeUnit() {
+        return rangeUnit;
+    }
+
+    @Override
+    public ValueRange range() {
+        return range;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this field represents a component of a date.
+     *
+     * @return true if it is a component of a date
+     */
+    public boolean isDateField() {
+        return ordinal() >= DAY_OF_WEEK.ordinal() && ordinal() <= ERA.ordinal();
+    }
+
+    /**
+     * Checks if this field represents a component of a time.
+     *
+     * @return true if it is a component of a time
+     */
+    public boolean isTimeField() {
+        return ordinal() < DAY_OF_WEEK.ordinal();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks that the specified value is valid for this field.
+     * <p>
+     * This validates that the value is within the outer range of valid values
+     * returned by {@link #range()}.
+     *
+     * @param value  the value to check
+     * @return the value that was passed in
+     */
+    public long checkValidValue(long value) {
+        return range().checkValidValue(value, this);
+    }
+
+    /**
+     * Checks that the specified value is valid and fits in an {@code int}.
+     * <p>
+     * This validates that the value is within the outer range of valid values
+     * returned by {@link #range()}.
+     * It also checks that all valid values are within the bounds of an {@code int}.
+     *
+     * @param value  the value to check
+     * @return the value that was passed in
+     */
+    public int checkValidIntValue(long value) {
+        return range().checkValidIntValue(value, this);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public boolean doIsSupported(TemporalAccessor temporal) {
+        return temporal.isSupported(this);
+    }
+
+    @Override
+    public ValueRange doRange(TemporalAccessor temporal) {
+        return temporal.range(this);
+    }
+
+    @Override
+    public long doGet(TemporalAccessor temporal) {
+        return temporal.getLong(this);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <R extends Temporal> R doWith(R temporal, long newValue) {
+        return (R) temporal.with(this, newValue);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public boolean resolve(DateTimeBuilder builder, long value) {
+        return false;  // resolve implemented in builder
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public String toString() {
+        return getName();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/ChronoLocalDate.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,691 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import static java.time.temporal.ChronoField.EPOCH_DAY;
+import static java.time.temporal.ChronoField.ERA;
+import static java.time.temporal.ChronoField.YEAR;
+import static java.time.temporal.ChronoUnit.DAYS;
+
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Comparator;
+import java.util.Objects;
+
+/**
+ * A date without time-of-day or time-zone in an arbitrary chronology, intended
+ * for advanced globalization use cases.
+ * <p>
+ * <b>Most applications should declare method signatures, fields and variables
+ * as {@link LocalDate}, not this interface.</b>
+ * <p>
+ * A {@code ChronoLocalDate} is the abstract representation of a date where the
+ * {@code Chrono chronology}, or calendar system, is pluggable.
+ * The date is defined in terms of fields expressed by {@link TemporalField},
+ * where most common implementations are defined in {@link ChronoField}.
+ * The chronology defines how the calendar system operates and the meaning of
+ * the standard fields.
+ *
+ * <h3>When to use this interface</h3>
+ * The design of the API encourages the use of {@code LocalDate} rather than this
+ * interface, even in the case where the application needs to deal with multiple
+ * calendar systems. The rationale for this is explored in the following documentation.
+ * <p>
+ * The primary use case where this interface should be used is where the generic
+ * type parameter {@code <C>} is fully defined as a specific chronology.
+ * In that case, the assumptions of that chronology are known at development
+ * time and specified in the code.
+ * <p>
+ * When the chronology is defined in the generic type parameter as ? or otherwise
+ * unknown at development time, the rest of the discussion below applies.
+ * <p>
+ * To emphasize the point, declaring a method signature, field or variable as this
+ * interface type can initially seem like the sensible way to globalize an application,
+ * however it is usually the wrong approach.
+ * As such, it should be considered an application-wide architectural decision to choose
+ * to use this interface as opposed to {@code LocalDate}.
+ *
+ * <h3>Architectural issues to consider</h3>
+ * These are some of the points that must be considered before using this interface
+ * throughout an application.
+ * <p>
+ * 1) Applications using this interface, as opposed to using just {@code LocalDate},
+ * face a significantly higher probability of bugs. This is because the calendar system
+ * in use is not known at development time. A key cause of bugs is where the developer
+ * applies assumptions from their day-to-day knowledge of the ISO calendar system
+ * to code that is intended to deal with any arbitrary calendar system.
+ * The section below outlines how those assumptions can cause problems
+ * The primary mechanism for reducing this increased risk of bugs is a strong code review process.
+ * This should also be considered a extra cost in maintenance for the lifetime of the code.
+ * <p>
+ * 2) This interface does not enforce immutability of implementations.
+ * While the implementation notes indicate that all implementations must be immutable
+ * there is nothing in the code or type system to enforce this. Any method declared
+ * to accept a {@code ChronoLocalDate} could therefore be passed a poorly or
+ * maliciously written mutable implementation.
+ * <p>
+ * 3) Applications using this interface  must consider the impact of eras.
+ * {@code LocalDate} shields users from the concept of eras, by ensuring that {@code getYear()}
+ * returns the proleptic year. That decision ensures that developers can think of
+ * {@code LocalDate} instances as consisting of three fields - year, month-of-year and day-of-month.
+ * By contrast, users of this interface must think of dates as consisting of four fields -
+ * era, year-of-era, month-of-year and day-of-month. The extra era field is frequently
+ * forgotten, yet it is of vital importance to dates in an arbitrary calendar system.
+ * For example, in the Japanese calendar system, the era represents the reign of an Emperor.
+ * Whenever one reign ends and another starts, the year-of-era is reset to one.
+ * <p>
+ * 4) The only agreed international standard for passing a date between two systems
+ * is the ISO-8601 standard which requires the ISO calendar system. Using this interface
+ * throughout the application will inevitably lead to the requirement to pass the date
+ * across a network or component boundary, requiring an application specific protocol or format.
+ * <p>
+ * 5) Long term persistence, such as a database, will almost always only accept dates in the
+ * ISO-8601 calendar system (or the related Julian-Gregorian). Passing around dates in other
+ * calendar systems increases the complications of interacting with persistence.
+ * <p>
+ * 6) Most of the time, passing a {@code ChronoLocalDate} throughout an application
+ * is unnecessary, as discussed in the last section below.
+ *
+ * <h3>False assumptions causing bugs in multi-calendar system code</h3>
+ * As indicated above, there are many issues to consider when try to use and manipulate a
+ * date in an arbitrary calendar system. These are some of the key issues.
+ * <p>
+ * Code that queries the day-of-month and assumes that the value will never be more than
+ * 31 is invalid. Some calendar systems have more than 31 days in some months.
+ * <p>
+ * Code that adds 12 months to a date and assumes that a year has been added is invalid.
+ * Some calendar systems have a different number of months, such as 13 in the Coptic or Ethiopic.
+ * <p>
+ * Code that adds one month to a date and assumes that the month-of-year value will increase
+ * by one or wrap to the next year is invalid. Some calendar systems have a variable number
+ * of months in a year, such as the Hebrew.
+ * <p>
+ * Code that adds one month, then adds a second one month and assumes that the day-of-month
+ * will remain close to its original value is invalid. Some calendar systems have a large difference
+ * between the length of the longest month and the length of the shortest month.
+ * For example, the Coptic or Ethiopic have 12 months of 30 days and 1 month of 5 days.
+ * <p>
+ * Code that adds seven days and assumes that a week has been added is invalid.
+ * Some calendar systems have weeks of other than seven days, such as the French Revolutionary.
+ * <p>
+ * Code that assumes that because the year of {@code date1} is greater than the year of {@code date2}
+ * then {@code date1} is after {@code date2} is invalid. This is invalid for all calendar systems
+ * when referring to the year-of-era, and especially untrue of the Japanese calendar system
+ * where the year-of-era restarts with the reign of every new Emperor.
+ * <p>
+ * Code that treats month-of-year one and day-of-month one as the start of the year is invalid.
+ * Not all calendar systems start the year when the month value is one.
+ * <p>
+ * In general, manipulating a date, and even querying a date, is wide open to bugs when the
+ * calendar system is unknown at development time. This is why it is essential that code using
+ * this interface is subjected to additional code reviews. It is also why an architectural
+ * decision to avoid this interface type is usually the correct one.
+ *
+ * <h3>Using LocalDate instead</h3>
+ * The primary alternative to using this interface throughout your application is as follows.
+ * <p><ul>
+ * <li>Declare all method signatures referring to dates in terms of {@code LocalDate}.
+ * <li>Either store the chronology (calendar system) in the user profile or lookup
+ *  the chronology from the user locale
+ * <li>Convert the ISO {@code LocalDate} to and from the user's preferred calendar system during
+ *  printing and parsing
+ * </ul><p>
+ * This approach treats the problem of globalized calendar systems as a localization issue
+ * and confines it to the UI layer. This approach is in keeping with other localization
+ * issues in the java platform.
+ * <p>
+ * As discussed above, performing calculations on a date where the rules of the calendar system
+ * are pluggable requires skill and is not recommended.
+ * Fortunately, the need to perform calculations on a date in an arbitrary calendar system
+ * is extremely rare. For example, it is highly unlikely that the business rules of a library
+ * book rental scheme will allow rentals to be for one month, where meaning of the month
+ * is dependent on the user's preferred calendar system.
+ * <p>
+ * A key use case for calculations on a date in an arbitrary calendar system is producing
+ * a month-by-month calendar for display and user interaction. Again, this is a UI issue,
+ * and use of this interface solely within a few methods of the UI layer may be justified.
+ * <p>
+ * In any other part of the system, where a date must be manipulated in a calendar system
+ * other than ISO, the use case will generally specify the calendar system to use.
+ * For example, an application may need to calculate the next Islamic or Hebrew holiday
+ * which may require manipulating the date.
+ * This kind of use case can be handled as follows:
+ * <p><ul>
+ * <li>start from the ISO {@code LocalDate} being passed to the method
+ * <li>convert the date to the alternate calendar system, which for this use case is known
+ *  rather than arbitrary
+ * <li>perform the calculation
+ * <li>convert back to {@code LocalDate}
+ * </ul><p>
+ * Developers writing low-level frameworks or libraries should also avoid this interface.
+ * Instead, one of the two general purpose access interfaces should be used.
+ * Use {@link TemporalAccessor} if read-only access is required, or use {@link Temporal}
+ * if read-write access is required.
+ *
+ * <h3>Specification for implementors</h3>
+ * This interface must be implemented with care to ensure other classes operate correctly.
+ * All implementations that can be instantiated must be final, immutable and thread-safe.
+ * Subclasses should be Serializable wherever possible.
+ * <p>
+ * Additional calendar systems may be added to the system.
+ * See {@link Chrono} for more details.
+ *
+ * @param <C> the chronology of this date
+ * @since 1.8
+ */
+public interface ChronoLocalDate<C extends Chrono<C>>
+        extends Temporal, TemporalAdjuster, Comparable<ChronoLocalDate<?>> {
+
+    /**
+     * Comparator for two {@code ChronoLocalDate}s ignoring the chronology.
+     * <p>
+     * This comparator differs from the comparison in {@link #compareTo} in that it
+     * only compares the underlying date and not the chronology.
+     * This allows dates in different calendar systems to be compared based
+     * on the time-line position.
+     * This is equivalent to using {@code Long.compare(date1.toEpochDay(),  date2.toEpochDay())}.
+     *
+     * @see #isAfter
+     * @see #isBefore
+     * @see #isEqual
+     */
+    public static final Comparator<ChronoLocalDate<?>> DATE_COMPARATOR =
+            new Comparator<ChronoLocalDate<?>>() {
+        @Override
+        public int compare(ChronoLocalDate<?> date1, ChronoLocalDate<?> date2) {
+            return Long.compare(date1.toEpochDay(), date2.toEpochDay());
+        }
+    };
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the chronology of this date.
+     * <p>
+     * The {@code Chrono} represents the calendar system in use.
+     * The era and other fields in {@link ChronoField} are defined by the chronology.
+     *
+     * @return the chronology, not null
+     */
+    C getChrono();
+
+    /**
+     * Gets the era, as defined by the chronology.
+     * <p>
+     * The era is, conceptually, the largest division of the time-line.
+     * Most calendar systems have a single epoch dividing the time-line into two eras.
+     * However, some have multiple eras, such as one for the reign of each leader.
+     * The exact meaning is determined by the {@code Chrono}.
+     * <p>
+     * All correctly implemented {@code Era} classes are singletons, thus it
+     * is valid code to write {@code date.getEra() == SomeChrono.ERA_NAME)}.
+     * <p>
+     * This default implementation uses {@link Chrono#eraOf(int)}.
+     *
+     * @return the chronology specific era constant applicable at this date, not null
+     */
+    public default Era<C> getEra() {
+        return getChrono().eraOf(get(ERA));
+    }
+
+    /**
+     * Checks if the year is a leap year, as defined by the calendar system.
+     * <p>
+     * A leap-year is a year of a longer length than normal.
+     * The exact meaning is determined by the chronology with the constraint that
+     * a leap-year must imply a year-length longer than a non leap-year.
+     * <p>
+     * This default implementation uses {@link Chrono#isLeapYear(long)}.
+     *
+     * @return true if this date is in a leap year, false otherwise
+     */
+    public default boolean isLeapYear() {
+        return getChrono().isLeapYear(getLong(YEAR));
+    }
+
+    /**
+     * Returns the length of the month represented by this date, as defined by the calendar system.
+     * <p>
+     * This returns the length of the month in days.
+     *
+     * @return the length of the month in days
+     */
+    int lengthOfMonth();
+
+    /**
+     * Returns the length of the year represented by this date, as defined by the calendar system.
+     * <p>
+     * This returns the length of the year in days.
+     * <p>
+     * The default implementation uses {@link #isLeapYear()} and returns 365 or 366.
+     *
+     * @return the length of the year in days
+     */
+    public default int lengthOfYear() {
+        return (isLeapYear() ? 366 : 365);
+    }
+
+    @Override
+    public default boolean isSupported(TemporalField field) {
+        if (field instanceof ChronoField) {
+            return ((ChronoField) field).isDateField();
+        }
+        return field != null && field.doIsSupported(this);
+    }
+
+    //-----------------------------------------------------------------------
+    // override for covariant return type
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public default ChronoLocalDate<C> with(TemporalAdjuster adjuster) {
+        return getChrono().ensureChronoLocalDate(Temporal.super.with(adjuster));
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public default ChronoLocalDate<C> with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            throw new DateTimeException("Unsupported field: " + field.getName());
+        }
+        return getChrono().ensureChronoLocalDate(field.doWith(this, newValue));
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public default ChronoLocalDate<C> plus(TemporalAdder adder) {
+        return getChrono().ensureChronoLocalDate(Temporal.super.plus(adder));
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public default ChronoLocalDate<C> plus(long amountToAdd, TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            throw new DateTimeException("Unsupported unit: " + unit.getName());
+        }
+        return getChrono().ensureChronoLocalDate(unit.doPlus(this, amountToAdd));
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public default ChronoLocalDate<C> minus(TemporalSubtractor subtractor) {
+        return getChrono().ensureChronoLocalDate(Temporal.super.minus(subtractor));
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public default ChronoLocalDate<C> minus(long amountToSubtract, TemporalUnit unit) {
+        return getChrono().ensureChronoLocalDate(Temporal.super.minus(amountToSubtract, unit));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this date using the specified query.
+     * <p>
+     * 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.
+     * <p>
+     * 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 <R> the type of the result
+     * @param query  the query to invoke, not null
+     * @return the query result, null may be returned (defined by the query)
+     * @throws DateTimeException if unable to query (defined by the query)
+     * @throws ArithmeticException if numeric overflow occurs (defined by the query)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public default <R> R query(TemporalQuery<R> query) {
+        if (query == Queries.chrono()) {
+            return (R) getChrono();
+        }
+        if (query == Queries.precision()) {
+            return (R) DAYS;
+        }
+        // inline TemporalAccessor.super.query(query) as an optimization
+        if (query == Queries.zoneId() || query == Queries.zone() || query == Queries.offset()) {
+            return null;
+        }
+        return query.queryFrom(this);
+    }
+
+    /**
+     * Adjusts the specified temporal object to have the same date as this object.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with the date changed to be the same as this.
+     * <p>
+     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+     * passing {@link ChronoField#EPOCH_DAY} as the field.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisLocalDate.adjustInto(temporal);
+     *   temporal = temporal.with(thisLocalDate);
+     * </pre>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param temporal  the target object to be adjusted, not null
+     * @return the adjusted object, not null
+     * @throws DateTimeException if unable to make the adjustment
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public default Temporal adjustInto(Temporal temporal) {
+        return temporal.with(EPOCH_DAY, toEpochDay());
+    }
+
+    /**
+     * Calculates the period between this date and another date in
+     * terms of the specified unit.
+     * <p>
+     * This calculates the period between two dates in terms of a single unit.
+     * The start and end points are {@code this} and the specified date.
+     * The result will be negative if the end is before the start.
+     * The {@code Temporal} passed to this method must be a
+     * {@code ChronoLocalDate} in the same chronology.
+     * The calculation returns a whole number, representing the number of
+     * complete units between the two dates.
+     * For example, the period in days between two dates can be calculated
+     * using {@code startDate.periodUntil(endDate, DAYS)}.
+     * <p>
+     * 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:
+     * <pre>
+     *   long period = start.periodUntil(end, MONTHS);   // this method
+     *   dateTime.plus(MONTHS.between(start, end));      // use in plus/minus
+     * </pre>
+     * <p>
+     * The calculation is implemented in this method for {@link ChronoUnit}.
+     * The units {@code DAYS}, {@code WEEKS}, {@code MONTHS}, {@code YEARS},
+     * {@code DECADES}, {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS}
+     * should be supported by all implementations.
+     * Other {@code ChronoUnit} values will throw an exception.
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param endDate  the end date, which must be a {@code ChronoLocalDate}
+     *  in the same chronology, not null
+     * @param unit  the unit to measure the period in, not null
+     * @return the amount of the period between this date and the end date
+     * @throws DateTimeException if the period cannot be calculated
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override  // override for Javadoc
+    public abstract long periodUntil(Temporal endDate, TemporalUnit unit);
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a date-time formed from this date at the specified time.
+     * <p>
+     * This merges the two objects - {@code this} and the specified time -
+     * to form an instance of {@code ChronoLocalDateTime}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     * <p>
+     * This default implementation creates the date-time.
+     *
+     * @param localTime  the local time to use, not null
+     * @return the local date-time formed from this date and the specified time, not null
+     */
+    public default ChronoLocalDateTime<C> atTime(LocalTime localTime) {
+        return Chrono.dateTime(this, localTime);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Converts this date to the Epoch Day.
+     * <p>
+     * The {@link ChronoField#EPOCH_DAY Epoch Day count} is a simple
+     * incrementing count of days where day 0 is 1970-01-01 (ISO).
+     * This definition is the same for all chronologies, enabling conversion.
+     * <p>
+     * This default implementation queries the {@code EPOCH_DAY} field.
+     *
+     * @return the Epoch Day equivalent to this date
+     */
+    public default long toEpochDay() {
+        return getLong(EPOCH_DAY);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this date to another date, including the chronology.
+     * <p>
+     * The comparison is based first on the underlying time-line date, then
+     * on the chronology.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     * <p>
+     * For example, the following is the comparator order:
+     * <ol>
+     * <li>{@code 2012-12-03 (ISO)}</li>
+     * <li>{@code 2012-12-04 (ISO)}</li>
+     * <li>{@code 2555-12-04 (ThaiBuddhist)}</li>
+     * <li>{@code 2012-12-05 (ISO)}</li>
+     * </ol>
+     * Values #2 and #3 represent the same date on the time-line.
+     * When two values represent the same date, the chronology ID is compared to distinguish them.
+     * This step is needed to make the ordering "consistent with equals".
+     * <p>
+     * If all the date objects being compared are in the same chronology, then the
+     * additional chronology stage is not required and only the local date is used.
+     * To compare the dates of two {@code TemporalAccessor} instances, including dates
+     * in two different chronologies, use {@link ChronoField#EPOCH_DAY} as a comparator.
+     * <p>
+     * This default implementation performs the comparison defined above.
+     *
+     * @param other  the other date to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     */
+    @Override
+    public default int compareTo(ChronoLocalDate<?> other) {
+        int cmp = Long.compare(toEpochDay(), other.toEpochDay());
+        if (cmp == 0) {
+            cmp = getChrono().compareTo(other.getChrono());
+        }
+        return cmp;
+    }
+
+    /**
+     * Checks if this date is after the specified date ignoring the chronology.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} in that it
+     * only compares the underlying date and not the chronology.
+     * This allows dates in different calendar systems to be compared based
+     * on the time-line position.
+     * This is equivalent to using {@code date1.toEpochDay() &gt; date2.toEpochDay()}.
+     * <p>
+     * This default implementation performs the comparison based on the epoch-day.
+     *
+     * @param other  the other date to compare to, not null
+     * @return true if this is after the specified date
+     */
+    public default boolean isAfter(ChronoLocalDate<?> other) {
+        return this.toEpochDay() > other.toEpochDay();
+    }
+
+    /**
+     * Checks if this date is before the specified date ignoring the chronology.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} in that it
+     * only compares the underlying date and not the chronology.
+     * This allows dates in different calendar systems to be compared based
+     * on the time-line position.
+     * This is equivalent to using {@code date1.toEpochDay() &lt; date2.toEpochDay()}.
+     * <p>
+     * This default implementation performs the comparison based on the epoch-day.
+     *
+     * @param other  the other date to compare to, not null
+     * @return true if this is before the specified date
+     */
+    public default boolean isBefore(ChronoLocalDate<?> other) {
+        return this.toEpochDay() < other.toEpochDay();
+    }
+
+    /**
+     * Checks if this date is equal to the specified date ignoring the chronology.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} in that it
+     * only compares the underlying date and not the chronology.
+     * This allows dates in different calendar systems to be compared based
+     * on the time-line position.
+     * This is equivalent to using {@code date1.toEpochDay() == date2.toEpochDay()}.
+     * <p>
+     * This default implementation performs the comparison based on the epoch-day.
+     *
+     * @param other  the other date to compare to, not null
+     * @return true if the underlying date is equal to the specified date
+     */
+    public default boolean isEqual(ChronoLocalDate<?> other) {
+        return this.toEpochDay() == other.toEpochDay();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this date is equal to another date, including the chronology.
+     * <p>
+     * Compares this date with another ensuring that the date and chronology are the same.
+     * <p>
+     * To compare the dates of two {@code TemporalAccessor} instances, including dates
+     * in two different chronologies, use {@link ChronoField#EPOCH_DAY} as a comparator.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other date
+     */
+    @Override
+    boolean equals(Object obj);
+
+    /**
+     * A hash code for this date.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    int hashCode();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this date as a {@code String}.
+     * <p>
+     * The output will include the full local date and the chronology ID.
+     *
+     * @return the formatted date, not null
+     */
+    @Override
+    String toString();
+
+    /**
+     * Outputs this date as a {@code String} using the formatter.
+     * <p>
+     * The default implementation must behave as follows:
+     * <pre>
+     *  return formatter.print(this);
+     * </pre>
+     *
+     * @param formatter  the formatter to use, not null
+     * @return the formatted date string, not null
+     * @throws DateTimeException if an error occurs during printing
+     */
+    public default String toString(DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.print(this);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/ChronoLocalDateTime.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,499 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import static java.time.temporal.ChronoField.EPOCH_DAY;
+import static java.time.temporal.ChronoField.NANO_OF_DAY;
+import static java.time.temporal.ChronoUnit.NANOS;
+
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.time.zone.ZoneRules;
+import java.util.Comparator;
+import java.util.Objects;
+
+/**
+ * A date-time without a time-zone in an arbitrary chronology, intended
+ * for advanced globalization use cases.
+ * <p>
+ * <b>Most applications should declare method signatures, fields and variables
+ * as {@link LocalDateTime}, not this interface.</b>
+ * <p>
+ * A {@code ChronoLocalDateTime} is the abstract representation of a local date-time
+ * where the {@code Chrono chronology}, or calendar system, is pluggable.
+ * The date-time is defined in terms of fields expressed by {@link TemporalField},
+ * where most common implementations are defined in {@link ChronoField}.
+ * The chronology defines how the calendar system operates and the meaning of
+ * the standard fields.
+ *
+ * <h3>When to use this interface</h3>
+ * The design of the API encourages the use of {@code LocalDateTime} rather than this
+ * interface, even in the case where the application needs to deal with multiple
+ * calendar systems. The rationale for this is explored in detail in {@link ChronoLocalDate}.
+ * <p>
+ * Ensure that the discussion in {@code ChronoLocalDate} has been read and understood
+ * before using this interface.
+ *
+ * <h3>Specification for implementors</h3>
+ * This interface must be implemented with care to ensure other classes operate correctly.
+ * All implementations that can be instantiated must be final, immutable and thread-safe.
+ * Subclasses should be Serializable wherever possible.
+ *
+ * @param <C> the chronology of this date-time
+ * @since 1.8
+ */
+public interface ChronoLocalDateTime<C extends Chrono<C>>
+        extends Temporal, TemporalAdjuster, Comparable<ChronoLocalDateTime<?>> {
+
+    /**
+     * Comparator for two {@code ChronoLocalDateTime} instances ignoring the chronology.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} in that it
+     * only compares the underlying date and not the chronology.
+     * This allows dates in different calendar systems to be compared based
+     * on the time-line position.
+     *
+     * @see #isAfter
+     * @see #isBefore
+     * @see #isEqual
+     */
+    Comparator<ChronoLocalDateTime<?>> DATE_TIME_COMPARATOR =
+            new Comparator<ChronoLocalDateTime<?>>() {
+        @Override
+        public int compare(ChronoLocalDateTime<?> datetime1, ChronoLocalDateTime<?> datetime2) {
+            int cmp = Long.compare(datetime1.getDate().toEpochDay(), datetime2.getDate().toEpochDay());
+            if (cmp == 0) {
+                cmp = Long.compare(datetime1.getTime().toNanoOfDay(), datetime2.getTime().toNanoOfDay());
+            }
+            return cmp;
+        }
+    };
+
+    /**
+     * Gets the local date part of this date-time.
+     * <p>
+     * This returns a local date with the same year, month and day
+     * as this date-time.
+     *
+     * @return the date part of this date-time, not null
+     */
+    ChronoLocalDate<C> getDate() ;
+
+    /**
+     * Gets the local time part of this date-time.
+     * <p>
+     * This returns a local time with the same hour, minute, second and
+     * nanosecond as this date-time.
+     *
+     * @return the time part of this date-time, not null
+     */
+    LocalTime getTime();
+
+
+    //-----------------------------------------------------------------------
+    // override for covariant return type
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public default ChronoLocalDateTime<C> with(TemporalAdjuster adjuster) {
+        return getDate().getChrono().ensureChronoLocalDateTime(Temporal.super.with(adjuster));
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    ChronoLocalDateTime<C> with(TemporalField field, long newValue);
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public default ChronoLocalDateTime<C> plus(TemporalAdder adder) {
+        return getDate().getChrono().ensureChronoLocalDateTime(Temporal.super.plus(adder));
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    ChronoLocalDateTime<C> plus(long amountToAdd, TemporalUnit unit);
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public default ChronoLocalDateTime<C> minus(TemporalSubtractor subtractor) {
+        return getDate().getChrono().ensureChronoLocalDateTime(Temporal.super.minus(subtractor));
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public default ChronoLocalDateTime<C> minus(long amountToSubtract, TemporalUnit unit) {
+        return getDate().getChrono().ensureChronoLocalDateTime(Temporal.super.minus(amountToSubtract, unit));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this date-time using the specified query.
+     * <p>
+     * This queries this date-time using the specified query strategy object.
+     * The {@code TemporalQuery} object defines the logic to be used to
+     * obtain the result. Read the documentation of the query to understand
+     * what the result of this method will be.
+     * <p>
+     * The result of this method is obtained by invoking the
+     * {@link java.time.temporal.TemporalQuery#queryFrom(TemporalAccessor)} method on the
+     * specified query passing {@code this} as the argument.
+     *
+     * @param <R> the type of the result
+     * @param query  the query to invoke, not null
+     * @return the query result, null may be returned (defined by the query)
+     * @throws DateTimeException if unable to query (defined by the query)
+     * @throws ArithmeticException if numeric overflow occurs (defined by the query)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public default <R> R query(TemporalQuery<R> query) {
+        if (query == Queries.chrono()) {
+            return (R) getDate().getChrono();
+        }
+        if (query == Queries.precision()) {
+            return (R) NANOS;
+        }
+        // inline TemporalAccessor.super.query(query) as an optimization
+        if (query == Queries.zoneId() || query == Queries.zone() || query == Queries.offset()) {
+            return null;
+        }
+        return query.queryFrom(this);
+    }
+
+    /**
+     * Adjusts the specified temporal object to have the same date and time as this object.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with the date and time changed to be the same as this.
+     * <p>
+     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+     * twice, passing {@link ChronoField#EPOCH_DAY} and
+     * {@link ChronoField#NANO_OF_DAY} as the fields.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisLocalDateTime.adjustInto(temporal);
+     *   temporal = temporal.with(thisLocalDateTime);
+     * </pre>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param temporal  the target object to be adjusted, not null
+     * @return the adjusted object, not null
+     * @throws DateTimeException if unable to make the adjustment
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public default Temporal adjustInto(Temporal temporal) {
+        return temporal
+                .with(EPOCH_DAY, getDate().toEpochDay())
+                .with(NANO_OF_DAY, getTime().toNanoOfDay());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a zoned date-time formed from this date-time and the specified time-zone.
+     * <p>
+     * This creates a zoned date-time matching the input date-time as closely as possible.
+     * Time-zone rules, such as daylight savings, mean that not every local date-time
+     * is valid for the specified zone, thus the local date-time may be adjusted.
+     * <p>
+     * The local date-time is resolved to a single instant on the time-line.
+     * This is achieved by finding a valid offset from UTC/Greenwich for the local
+     * date-time as defined by the {@link ZoneRules rules} of the zone ID.
+     *<p>
+     * In most cases, there is only one valid offset for a local date-time.
+     * In the case of an overlap, where clocks are set back, there are two valid offsets.
+     * This method uses the earlier offset typically corresponding to "summer".
+     * <p>
+     * In the case of a gap, where clocks jump forward, there is no valid offset.
+     * Instead, the local date-time is adjusted to be later by the length of the gap.
+     * For a typical one hour daylight savings change, the local date-time will be
+     * moved one hour later into the offset typically corresponding to "summer".
+     * <p>
+     * To obtain the later offset during an overlap, call
+     * {@link ChronoZonedDateTime#withLaterOffsetAtOverlap()} on the result of this method.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param zone  the time-zone to use, not null
+     * @return the zoned date-time formed from this date-time, not null
+     */
+    ChronoZonedDateTime<C> atZone(ZoneId zone);
+
+    //-----------------------------------------------------------------------
+    /**
+     * Converts this date-time to an {@code Instant}.
+     * <p>
+     * This combines this local date-time and the specified offset to form
+     * an {@code Instant}.
+     * <p>
+     * This default implementation calculates from the epoch-day of the date and the
+     * second-of-day of the time.
+     *
+     * @param offset  the offset to use for the conversion, not null
+     * @return an {@code Instant} representing the same instant, not null
+     */
+    public default Instant toInstant(ZoneOffset offset) {
+        return Instant.ofEpochSecond(toEpochSecond(offset), getTime().getNano());
+    }
+
+    /**
+     * Converts this date-time to the number of seconds from the epoch
+     * of 1970-01-01T00:00:00Z.
+     * <p>
+     * This combines this local date-time and the specified offset to calculate the
+     * epoch-second value, which is the number of elapsed seconds from 1970-01-01T00:00:00Z.
+     * Instants on the time-line after the epoch are positive, earlier are negative.
+     * <p>
+     * This default implementation calculates from the epoch-day of the date and the
+     * second-of-day of the time.
+     *
+     * @param offset  the offset to use for the conversion, not null
+     * @return the number of seconds from the epoch of 1970-01-01T00:00:00Z
+     */
+    public default long toEpochSecond(ZoneOffset offset) {
+        Objects.requireNonNull(offset, "offset");
+        long epochDay = getDate().toEpochDay();
+        long secs = epochDay * 86400 + getTime().toSecondOfDay();
+        secs -= offset.getTotalSeconds();
+        return secs;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this date-time to another date-time, including the chronology.
+     * <p>
+     * The comparison is based first on the underlying time-line date-time, then
+     * on the chronology.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     * <p>
+     * For example, the following is the comparator order:
+     * <ol>
+     * <li>{@code 2012-12-03T12:00 (ISO)}</li>
+     * <li>{@code 2012-12-04T12:00 (ISO)}</li>
+     * <li>{@code 2555-12-04T12:00 (ThaiBuddhist)}</li>
+     * <li>{@code 2012-12-05T12:00 (ISO)}</li>
+     * </ol>
+     * Values #2 and #3 represent the same date-time on the time-line.
+     * When two values represent the same date-time, the chronology ID is compared to distinguish them.
+     * This step is needed to make the ordering "consistent with equals".
+     * <p>
+     * If all the date-time objects being compared are in the same chronology, then the
+     * additional chronology stage is not required and only the local date-time is used.
+     * <p>
+     * This default implementation performs the comparison defined above.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     */
+    @Override
+    public default int compareTo(ChronoLocalDateTime<?> other) {
+        int cmp = getDate().compareTo(other.getDate());
+        if (cmp == 0) {
+            cmp = getTime().compareTo(other.getTime());
+            if (cmp == 0) {
+                cmp = getDate().getChrono().compareTo(other.getDate().getChrono());
+            }
+        }
+        return cmp;
+    }
+
+    /**
+     * Checks if this date-time is after the specified date-time ignoring the chronology.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} in that it
+     * only compares the underlying date-time and not the chronology.
+     * This allows dates in different calendar systems to be compared based
+     * on the time-line position.
+     * <p>
+     * This default implementation performs the comparison based on the epoch-day
+     * and nano-of-day.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return true if this is after the specified date-time
+     */
+    public default boolean isAfter(ChronoLocalDateTime<?> other) {
+        long thisEpDay = this.getDate().toEpochDay();
+        long otherEpDay = other.getDate().toEpochDay();
+        return thisEpDay > otherEpDay ||
+            (thisEpDay == otherEpDay && this.getTime().toNanoOfDay() > other.getTime().toNanoOfDay());
+    }
+
+    /**
+     * Checks if this date-time is before the specified date-time ignoring the chronology.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} in that it
+     * only compares the underlying date-time and not the chronology.
+     * This allows dates in different calendar systems to be compared based
+     * on the time-line position.
+     * <p>
+     * This default implementation performs the comparison based on the epoch-day
+     * and nano-of-day.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return true if this is before the specified date-time
+     */
+    public default boolean isBefore(ChronoLocalDateTime<?> other) {
+        long thisEpDay = this.getDate().toEpochDay();
+        long otherEpDay = other.getDate().toEpochDay();
+        return thisEpDay < otherEpDay ||
+            (thisEpDay == otherEpDay && this.getTime().toNanoOfDay() < other.getTime().toNanoOfDay());
+    }
+
+    /**
+     * Checks if this date-time is equal to the specified date-time ignoring the chronology.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} in that it
+     * only compares the underlying date and time and not the chronology.
+     * This allows date-times in different calendar systems to be compared based
+     * on the time-line position.
+     * <p>
+     * This default implementation performs the comparison based on the epoch-day
+     * and nano-of-day.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return true if the underlying date-time is equal to the specified date-time on the timeline
+     */
+    public default boolean isEqual(ChronoLocalDateTime<?> other) {
+        // Do the time check first, it is cheaper than computing EPOCH day.
+        return this.getTime().toNanoOfDay() == other.getTime().toNanoOfDay() &&
+               this.getDate().toEpochDay() == other.getDate().toEpochDay();
+    }
+
+    /**
+     * Checks if this date-time is equal to another date-time, including the chronology.
+     * <p>
+     * Compares this date-time with another ensuring that the date-time and chronology are the same.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other date
+     */
+    @Override
+    boolean equals(Object obj);
+
+    /**
+     * A hash code for this date-time.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    int hashCode();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this date-time as a {@code String}.
+     * <p>
+     * The output will include the full local date-time and the chronology ID.
+     *
+     * @return a string representation of this date-time, not null
+     */
+    @Override
+    String toString();
+
+    /**
+     * Outputs this date-time as a {@code String} using the formatter.
+     * <p>
+     * The default implementation must behave as follows:
+     * <pre>
+     *  return formatter.print(this);
+     * </pre>
+     *
+     * @param formatter  the formatter to use, not null
+     * @return the formatted date-time string, not null
+     * @throws DateTimeException if an error occurs during printing
+     */
+    public default String toString(DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.print(this);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/ChronoLocalDateTimeImpl.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import static java.time.temporal.ChronoField.EPOCH_DAY;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.time.DateTimeException;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.util.Objects;
+
+/**
+ * A date-time without a time-zone for the calendar neutral API.
+ * <p>
+ * {@code ChronoLocalDateTime} is an immutable date-time object that represents a date-time, often
+ * viewed as year-month-day-hour-minute-second. This object can also access other
+ * fields such as day-of-year, day-of-week and week-of-year.
+ * <p>
+ * This class stores all date and time fields, to a precision of nanoseconds.
+ * It does not store or represent a time-zone. For example, the value
+ * "2nd October 2007 at 13:45.30.123456789" can be stored in an {@code ChronoLocalDateTime}.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @param <C> the chronology of this date
+ * @since 1.8
+ */
+final class ChronoLocalDateTimeImpl<C extends Chrono<C>>
+        implements  ChronoLocalDateTime<C>, Temporal, TemporalAdjuster, Serializable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 4556003607393004514L;
+    /**
+     * Hours per day.
+     */
+    static final int HOURS_PER_DAY = 24;
+    /**
+     * Minutes per hour.
+     */
+    static final int MINUTES_PER_HOUR = 60;
+    /**
+     * Minutes per day.
+     */
+    static final int MINUTES_PER_DAY = MINUTES_PER_HOUR * HOURS_PER_DAY;
+    /**
+     * Seconds per minute.
+     */
+    static final int SECONDS_PER_MINUTE = 60;
+    /**
+     * Seconds per hour.
+     */
+    static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;
+    /**
+     * Seconds per day.
+     */
+    static final int SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY;
+    /**
+     * Milliseconds per day.
+     */
+    static final long MILLIS_PER_DAY = SECONDS_PER_DAY * 1000L;
+    /**
+     * Microseconds per day.
+     */
+    static final long MICROS_PER_DAY = SECONDS_PER_DAY * 1000_000L;
+    /**
+     * Nanos per second.
+     */
+    static final long NANOS_PER_SECOND = 1000_000_000L;
+    /**
+     * Nanos per minute.
+     */
+    static final long NANOS_PER_MINUTE = NANOS_PER_SECOND * SECONDS_PER_MINUTE;
+    /**
+     * Nanos per hour.
+     */
+    static final long NANOS_PER_HOUR = NANOS_PER_MINUTE * MINUTES_PER_HOUR;
+    /**
+     * Nanos per day.
+     */
+    static final long NANOS_PER_DAY = NANOS_PER_HOUR * HOURS_PER_DAY;
+
+    /**
+     * The date part.
+     */
+    private final ChronoLocalDate<C> date;
+    /**
+     * The time part.
+     */
+    private final LocalTime time;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ChronoLocalDateTime} from a date and time.
+     *
+     * @param date  the local date, not null
+     * @param time  the local time, not null
+     * @return the local date-time, not null
+     */
+    static <R extends Chrono<R>> ChronoLocalDateTimeImpl<R> of(ChronoLocalDate<R> date, LocalTime time) {
+        return new ChronoLocalDateTimeImpl<>(date, time);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param date  the date part of the date-time, not null
+     * @param time  the time part of the date-time, not null
+     */
+    private ChronoLocalDateTimeImpl(ChronoLocalDate<C> date, LocalTime time) {
+        Objects.requireNonNull(date, "date");
+        Objects.requireNonNull(time, "time");
+        this.date = date;
+        this.time = time;
+    }
+
+    /**
+     * Returns a copy of this date-time with the new date and time, checking
+     * to see if a new object is in fact required.
+     *
+     * @param newDate  the date of the new date-time, not null
+     * @param newTime  the time of the new date-time, not null
+     * @return the date-time, not null
+     */
+    private ChronoLocalDateTimeImpl<C> with(Temporal newDate, LocalTime newTime) {
+        if (date == newDate && time == newTime) {
+            return this;
+        }
+        // Validate that the new Temporal is a ChronoLocalDate (and not something else)
+        ChronoLocalDate<C> cd = date.getChrono().ensureChronoLocalDate(newDate);
+        return new ChronoLocalDateTimeImpl<>(cd, newTime);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ChronoLocalDate<C> getDate() {
+        return date;
+    }
+
+    @Override
+    public LocalTime getTime() {
+        return time;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public boolean isSupported(TemporalField field) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            return f.isDateField() || f.isTimeField();
+        }
+        return field != null && field.doIsSupported(this);
+    }
+
+    @Override
+    public ValueRange range(TemporalField field) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            return (f.isTimeField() ? time.range(field) : date.range(field));
+        }
+        return field.doRange(this);
+    }
+
+    @Override
+    public int get(TemporalField field) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            return (f.isTimeField() ? time.get(field) : date.get(field));
+        }
+        return range(field).checkValidIntValue(getLong(field), field);
+    }
+
+    @Override
+    public long getLong(TemporalField field) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            return (f.isTimeField() ? time.getLong(field) : date.getLong(field));
+        }
+        return field.doGet(this);
+    }
+
+    //-----------------------------------------------------------------------
+    @SuppressWarnings("unchecked")
+    @Override
+    public ChronoLocalDateTimeImpl<C> with(TemporalAdjuster adjuster) {
+        if (adjuster instanceof ChronoLocalDate) {
+            // The Chrono is checked in with(date,time)
+            return with((ChronoLocalDate<C>) adjuster, time);
+        } else if (adjuster instanceof LocalTime) {
+            return with(date, (LocalTime) adjuster);
+        } else if (adjuster instanceof ChronoLocalDateTimeImpl) {
+            return date.getChrono().ensureChronoLocalDateTime((ChronoLocalDateTimeImpl<?>) adjuster);
+        }
+        return date.getChrono().ensureChronoLocalDateTime((ChronoLocalDateTimeImpl<?>) adjuster.adjustInto(this));
+    }
+
+    @Override
+    public ChronoLocalDateTimeImpl<C> with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            if (f.isTimeField()) {
+                return with(date, time.with(field, newValue));
+            } else {
+                return with(date.with(field, newValue), time);
+            }
+        }
+        return date.getChrono().ensureChronoLocalDateTime(field.doWith(this, newValue));
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ChronoLocalDateTimeImpl<C> plus(long amountToAdd, TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            ChronoUnit f = (ChronoUnit) unit;
+            switch (f) {
+                case NANOS: return plusNanos(amountToAdd);
+                case MICROS: return plusDays(amountToAdd / MICROS_PER_DAY).plusNanos((amountToAdd % MICROS_PER_DAY) * 1000);
+                case MILLIS: return plusDays(amountToAdd / MILLIS_PER_DAY).plusNanos((amountToAdd % MILLIS_PER_DAY) * 1000000);
+                case SECONDS: return plusSeconds(amountToAdd);
+                case MINUTES: return plusMinutes(amountToAdd);
+                case HOURS: return plusHours(amountToAdd);
+                case HALF_DAYS: return plusDays(amountToAdd / 256).plusHours((amountToAdd % 256) * 12);  // no overflow (256 is multiple of 2)
+            }
+            return with(date.plus(amountToAdd, unit), time);
+        }
+        return date.getChrono().ensureChronoLocalDateTime(unit.doPlus(this, amountToAdd));
+    }
+
+    private ChronoLocalDateTimeImpl<C> plusDays(long days) {
+        return with(date.plus(days, ChronoUnit.DAYS), time);
+    }
+
+    private ChronoLocalDateTimeImpl<C> plusHours(long hours) {
+        return plusWithOverflow(date, hours, 0, 0, 0);
+    }
+
+    private ChronoLocalDateTimeImpl<C> plusMinutes(long minutes) {
+        return plusWithOverflow(date, 0, minutes, 0, 0);
+    }
+
+    ChronoLocalDateTimeImpl<C> plusSeconds(long seconds) {
+        return plusWithOverflow(date, 0, 0, seconds, 0);
+    }
+
+    private ChronoLocalDateTimeImpl<C> plusNanos(long nanos) {
+        return plusWithOverflow(date, 0, 0, 0, nanos);
+    }
+
+    //-----------------------------------------------------------------------
+    private ChronoLocalDateTimeImpl<C> plusWithOverflow(ChronoLocalDate<C> newDate, long hours, long minutes, long seconds, long nanos) {
+        // 9223372036854775808 long, 2147483648 int
+        if ((hours | minutes | seconds | nanos) == 0) {
+            return with(newDate, time);
+        }
+        long totDays = nanos / NANOS_PER_DAY +             //   max/24*60*60*1B
+                seconds / SECONDS_PER_DAY +                //   max/24*60*60
+                minutes / MINUTES_PER_DAY +                //   max/24*60
+                hours / HOURS_PER_DAY;                     //   max/24
+        long totNanos = nanos % NANOS_PER_DAY +                    //   max  86400000000000
+                (seconds % SECONDS_PER_DAY) * NANOS_PER_SECOND +   //   max  86400000000000
+                (minutes % MINUTES_PER_DAY) * NANOS_PER_MINUTE +   //   max  86400000000000
+                (hours % HOURS_PER_DAY) * NANOS_PER_HOUR;          //   max  86400000000000
+        long curNoD = time.toNanoOfDay();                          //   max  86400000000000
+        totNanos = totNanos + curNoD;                              // total 432000000000000
+        totDays += Math.floorDiv(totNanos, NANOS_PER_DAY);
+        long newNoD = Math.floorMod(totNanos, NANOS_PER_DAY);
+        LocalTime newTime = (newNoD == curNoD ? time : LocalTime.ofNanoOfDay(newNoD));
+        return with(newDate.plus(totDays, ChronoUnit.DAYS), newTime);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ChronoZonedDateTime<C> atZone(ZoneId zone) {
+        return ChronoZonedDateTimeImpl.ofBest(this, zone, null);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public long periodUntil(Temporal endDateTime, TemporalUnit unit) {
+        if (endDateTime instanceof ChronoLocalDateTime == false) {
+            throw new DateTimeException("Unable to calculate period between objects of two different types");
+        }
+        @SuppressWarnings("unchecked")
+        ChronoLocalDateTime<C> end = (ChronoLocalDateTime<C>) endDateTime;
+        if (getDate().getChrono().equals(end.getDate().getChrono()) == false) {
+            throw new DateTimeException("Unable to calculate period between two different chronologies");
+        }
+        if (unit instanceof ChronoUnit) {
+            ChronoUnit f = (ChronoUnit) unit;
+            if (f.isTimeUnit()) {
+                long amount = end.getLong(EPOCH_DAY) - date.getLong(EPOCH_DAY);
+                switch (f) {
+                    case NANOS: amount = Math.multiplyExact(amount, NANOS_PER_DAY); break;
+                    case MICROS: amount = Math.multiplyExact(amount, MICROS_PER_DAY); break;
+                    case MILLIS: amount = Math.multiplyExact(amount, MILLIS_PER_DAY); break;
+                    case SECONDS: amount = Math.multiplyExact(amount, SECONDS_PER_DAY); break;
+                    case MINUTES: amount = Math.multiplyExact(amount, MINUTES_PER_DAY); break;
+                    case HOURS: amount = Math.multiplyExact(amount, HOURS_PER_DAY); break;
+                    case HALF_DAYS: amount = Math.multiplyExact(amount, 2); break;
+                }
+                return Math.addExact(amount, time.periodUntil(end.getTime(), unit));
+            }
+            ChronoLocalDate<C> endDate = end.getDate();
+            if (end.getTime().isBefore(time)) {
+                endDate = endDate.minus(1, ChronoUnit.DAYS);
+            }
+            return date.periodUntil(endDate, unit);
+        }
+        return unit.between(this, endDateTime).getAmount();
+    }
+
+    //-----------------------------------------------------------------------
+    private Object writeReplace() {
+        return new Ser(Ser.CHRONO_LOCAL_DATE_TIME_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     * @return never
+     * @throws InvalidObjectException always
+     */
+    private Object readResolve() throws ObjectStreamException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    void writeExternal(ObjectOutput out) throws IOException {
+        out.writeObject(date);
+        out.writeObject(time);
+    }
+
+    static ChronoLocalDateTime<?> readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+        ChronoLocalDate<?> date = (ChronoLocalDate<?>) in.readObject();
+        LocalTime time = (LocalTime) in.readObject();
+        return date.atTime(time);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof ChronoLocalDateTime) {
+            return compareTo((ChronoLocalDateTime<?>) obj) == 0;
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return getDate().hashCode() ^ getTime().hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return getDate().toString() + 'T' + getTime().toString();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/ChronoUnit.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import java.time.Duration;
+
+/**
+ * A standard set of date periods units.
+ * <p>
+ * This set of units provide unit-based access to manipulate a date, time or date-time.
+ * The standard set of units can be extended by implementing {@link TemporalUnit}.
+ * <p>
+ * These units are intended to be applicable in multiple calendar systems.
+ * For example, most non-ISO calendar systems define units of years, months and days,
+ * just with slightly different rules.
+ * The documentation of each unit explains how it operates.
+ *
+ * <h3>Specification for implementors</h3>
+ * This is a final, immutable and thread-safe enum.
+ *
+ * @since 1.8
+ */
+public enum ChronoUnit implements TemporalUnit {
+
+    /**
+     * Unit that represents the concept of a nanosecond, the smallest supported unit of time.
+     * For the ISO calendar system, it is equal to the 1,000,000,000th part of the second unit.
+     */
+    NANOS("Nanos", Duration.ofNanos(1)),
+    /**
+     * Unit that represents the concept of a microsecond.
+     * For the ISO calendar system, it is equal to the 1,000,000th part of the second unit.
+     */
+    MICROS("Micros", Duration.ofNanos(1000)),
+    /**
+     * Unit that represents the concept of a millisecond.
+     * For the ISO calendar system, it is equal to the 1000th part of the second unit.
+     */
+    MILLIS("Millis", Duration.ofNanos(1000_000)),
+    /**
+     * Unit that represents the concept of a second.
+     * For the ISO calendar system, it is equal to the second in the SI system
+     * of units, except around a leap-second.
+     */
+    SECONDS("Seconds", Duration.ofSeconds(1)),
+    /**
+     * Unit that represents the concept of a minute.
+     * For the ISO calendar system, it is equal to 60 seconds.
+     */
+    MINUTES("Minutes", Duration.ofSeconds(60)),
+    /**
+     * Unit that represents the concept of an hour.
+     * For the ISO calendar system, it is equal to 60 minutes.
+     */
+    HOURS("Hours", Duration.ofSeconds(3600)),
+    /**
+     * Unit that represents the concept of half a day, as used in AM/PM.
+     * For the ISO calendar system, it is equal to 12 hours.
+     */
+    HALF_DAYS("HalfDays", Duration.ofSeconds(43200)),
+    /**
+     * Unit that represents the concept of a day.
+     * For the ISO calendar system, it is the standard day from midnight to midnight.
+     * The estimated duration of a day is {@code 24 Hours}.
+     * <p>
+     * When used with other calendar systems it must correspond to the day defined by
+     * the rising and setting of the Sun on Earth. It is not required that days begin
+     * at midnight - when converting between calendar systems, the date should be
+     * equivalent at midday.
+     */
+    DAYS("Days", Duration.ofSeconds(86400)),
+    /**
+     * Unit that represents the concept of a week.
+     * For the ISO calendar system, it is equal to 7 days.
+     * <p>
+     * When used with other calendar systems it must correspond to an integral number of days.
+     */
+    WEEKS("Weeks", Duration.ofSeconds(7 * 86400L)),
+    /**
+     * Unit that represents the concept of a month.
+     * For the ISO calendar system, the length of the month varies by month-of-year.
+     * The estimated duration of a month is one twelfth of {@code 365.2425 Days}.
+     * <p>
+     * When used with other calendar systems it must correspond to an integral number of days.
+     */
+    MONTHS("Months", Duration.ofSeconds(31556952L / 12)),
+    /**
+     * Unit that represents the concept of a year.
+     * For the ISO calendar system, it is equal to 12 months.
+     * The estimated duration of a year is {@code 365.2425 Days}.
+     * <p>
+     * When used with other calendar systems it must correspond to an integral number of days
+     * or months roughly equal to a year defined by the passage of the Earth around the Sun.
+     */
+    YEARS("Years", Duration.ofSeconds(31556952L)),
+    /**
+     * Unit that represents the concept of a decade.
+     * For the ISO calendar system, it is equal to 10 years.
+     * <p>
+     * When used with other calendar systems it must correspond to an integral number of days
+     * and is normally an integral number of years.
+     */
+    DECADES("Decades", Duration.ofSeconds(31556952L * 10L)),
+    /**
+     * Unit that represents the concept of a century.
+     * For the ISO calendar system, it is equal to 100 years.
+     * <p>
+     * When used with other calendar systems it must correspond to an integral number of days
+     * and is normally an integral number of years.
+     */
+    CENTURIES("Centuries", Duration.ofSeconds(31556952L * 100L)),
+    /**
+     * Unit that represents the concept of a millennium.
+     * For the ISO calendar system, it is equal to 1000 years.
+     * <p>
+     * When used with other calendar systems it must correspond to an integral number of days
+     * and is normally an integral number of years.
+     */
+    MILLENNIA("Millennia", Duration.ofSeconds(31556952L * 1000L)),
+    /**
+     * Unit that represents the concept of an era.
+     * The ISO calendar system doesn't have eras thus it is impossible to add
+     * an era to a date or date-time.
+     * The estimated duration of the era is artificially defined as {@code 1,000,00,000 Years}.
+     * <p>
+     * When used with other calendar systems there are no restrictions on the unit.
+     */
+    ERAS("Eras", Duration.ofSeconds(31556952L * 1000_000_000L)),
+    /**
+     * Artificial unit that represents the concept of forever.
+     * This is primarily used with {@link TemporalField} to represent unbounded fields
+     * such as the year or era.
+     * The estimated duration of the era is artificially defined as the largest duration
+     * supported by {@code Duration}.
+     */
+    FOREVER("Forever", Duration.ofSeconds(Long.MAX_VALUE, 999_999_999));
+
+    private final String name;
+    private final Duration duration;
+
+    private ChronoUnit(String name, Duration estimatedDuration) {
+        this.name = name;
+        this.duration = estimatedDuration;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the estimated duration of this unit in the ISO calendar system.
+     * <p>
+     * All of the units in this class have an estimated duration.
+     * Days vary due to daylight saving time, while months have different lengths.
+     *
+     * @return the estimated duration of this unit, not null
+     */
+    @Override
+    public Duration getDuration() {
+        return duration;
+    }
+
+    /**
+     * Checks if the duration of the unit is an estimate.
+     * <p>
+     * All time units in this class are considered to be accurate, while all date
+     * units in this class are considered to be estimated.
+     * <p>
+     * This definition ignores leap seconds, but considers that Days vary due to
+     * daylight saving time and months have different lengths.
+     *
+     * @return true if the duration is estimated, false if accurate
+     */
+    @Override
+    public boolean isDurationEstimated() {
+        return isDateUnit();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this unit is a date unit.
+     *
+     * @return true if a date unit, false if a time unit
+     */
+    public boolean isDateUnit() {
+        return this.compareTo(DAYS) >= 0;
+    }
+
+    /**
+     * Checks if this unit is a time unit.
+     *
+     * @return true if a time unit, false if a date unit
+     */
+    public boolean isTimeUnit() {
+        return this.compareTo(DAYS) < 0;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public boolean isSupported(Temporal temporal) {
+        if (this == FOREVER) {
+            return false;
+        }
+        if (temporal instanceof ChronoLocalDate) {
+            return isDateUnit();
+        }
+        if (temporal instanceof ChronoLocalDateTime || temporal instanceof ChronoZonedDateTime) {
+            return true;
+        }
+        return TemporalUnit.super.isSupported(temporal);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <R extends Temporal> R doPlus(R dateTime, long periodToAdd) {
+        return (R) dateTime.plus(periodToAdd, this);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public <R extends Temporal> SimplePeriod between(R dateTime1, R dateTime2) {
+        return new SimplePeriod(dateTime1.periodUntil(dateTime2, this), this);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public String toString() {
+        return getName();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/ChronoZonedDateTime.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,564 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import static java.time.temporal.ChronoField.INSTANT_SECONDS;
+import static java.time.temporal.ChronoField.OFFSET_SECONDS;
+import static java.time.temporal.ChronoUnit.NANOS;
+
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Comparator;
+import java.util.Objects;
+
+/**
+ * A date-time with a time-zone in an arbitrary chronology,
+ * intended for advanced globalization use cases.
+ * <p>
+ * <b>Most applications should declare method signatures, fields and variables
+ * as {@link ZonedDateTime}, not this interface.</b>
+ * <p>
+ * A {@code ChronoZonedDateTime} is the abstract representation of an offset date-time
+ * where the {@code Chrono chronology}, or calendar system, is pluggable.
+ * The date-time is defined in terms of fields expressed by {@link TemporalField},
+ * where most common implementations are defined in {@link ChronoField}.
+ * The chronology defines how the calendar system operates and the meaning of
+ * the standard fields.
+ *
+ * <h3>When to use this interface</h3>
+ * The design of the API encourages the use of {@code ZonedDateTime} rather than this
+ * interface, even in the case where the application needs to deal with multiple
+ * calendar systems. The rationale for this is explored in detail in {@link ChronoLocalDate}.
+ * <p>
+ * Ensure that the discussion in {@code ChronoLocalDate} has been read and understood
+ * before using this interface.
+ *
+ * <h3>Specification for implementors</h3>
+ * This interface must be implemented with care to ensure other classes operate correctly.
+ * All implementations that can be instantiated must be final, immutable and thread-safe.
+ * Subclasses should be Serializable wherever possible.
+ *
+ * @param <C> the chronology of this date-time
+ * @since 1.8
+ */
+public interface ChronoZonedDateTime<C extends Chrono<C>>
+        extends Temporal, Comparable<ChronoZonedDateTime<?>> {
+
+    /**
+     * Comparator for two {@code ChronoZonedDateTime} instances ignoring the chronology.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} in that it
+     * only compares the underlying date and not the chronology.
+     * This allows dates in different calendar systems to be compared based
+     * on the time-line position.
+     *
+     * @see #isAfter
+     * @see #isBefore
+     * @see #isEqual
+     */
+    Comparator<ChronoZonedDateTime<?>> INSTANT_COMPARATOR = new Comparator<ChronoZonedDateTime<?>>() {
+        @Override
+        public int compare(ChronoZonedDateTime<?> datetime1, ChronoZonedDateTime<?> datetime2) {
+            int cmp = Long.compare(datetime1.toEpochSecond(), datetime2.toEpochSecond());
+            if (cmp == 0) {
+                cmp = Long.compare(datetime1.getTime().toNanoOfDay(), datetime2.getTime().toNanoOfDay());
+            }
+            return cmp;
+        }
+    };
+
+    @Override
+    public default ValueRange range(TemporalField field) {
+        if (field instanceof ChronoField) {
+            if (field == INSTANT_SECONDS || field == OFFSET_SECONDS) {
+                return field.range();
+            }
+            return getDateTime().range(field);
+        }
+        return field.doRange(this);
+    }
+
+    @Override
+    public default int get(TemporalField field) {
+        if (field instanceof ChronoField) {
+            switch ((ChronoField) field) {
+                case INSTANT_SECONDS: throw new DateTimeException("Field too large for an int: " + field);
+                case OFFSET_SECONDS: return getOffset().getTotalSeconds();
+            }
+            return getDateTime().get(field);
+        }
+        return Temporal.super.get(field);
+    }
+
+    @Override
+    public default long getLong(TemporalField field) {
+        if (field instanceof ChronoField) {
+            switch ((ChronoField) field) {
+                case INSTANT_SECONDS: return toEpochSecond();
+                case OFFSET_SECONDS: return getOffset().getTotalSeconds();
+            }
+            return getDateTime().getLong(field);
+        }
+        return field.doGet(this);
+    }
+
+    /**
+     * Gets the local date part of this date-time.
+     * <p>
+     * This returns a local date with the same year, month and day
+     * as this date-time.
+     *
+     * @return the date part of this date-time, not null
+     */
+    public default ChronoLocalDate<C> getDate() {
+        return getDateTime().getDate();
+    }
+
+    /**
+     * Gets the local time part of this date-time.
+     * <p>
+     * This returns a local time with the same hour, minute, second and
+     * nanosecond as this date-time.
+     *
+     * @return the time part of this date-time, not null
+     */
+    public default LocalTime getTime() {
+        return getDateTime().getTime();
+    }
+
+    /**
+     * Gets the local date-time part of this date-time.
+     * <p>
+     * This returns a local date with the same year, month and day
+     * as this date-time.
+     *
+     * @return the local date-time part of this date-time, not null
+     */
+    ChronoLocalDateTime<C> getDateTime();
+
+    /**
+     * Gets the zone offset, such as '+01:00'.
+     * <p>
+     * This is the offset of the local date-time from UTC/Greenwich.
+     *
+     * @return the zone offset, not null
+     */
+    ZoneOffset getOffset();
+
+    /**
+     * Gets the zone ID, such as 'Europe/Paris'.
+     * <p>
+     * This returns the stored time-zone id used to determine the time-zone rules.
+     *
+     * @return the zone ID, not null
+     */
+    ZoneId getZone();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this date-time changing the zone offset to the
+     * earlier of the two valid offsets at a local time-line overlap.
+     * <p>
+     * This method only has any effect when the local time-line overlaps, such as
+     * at an autumn daylight savings cutover. In this scenario, there are two
+     * valid offsets for the local date-time. Calling this method will return
+     * a zoned date-time with the earlier of the two selected.
+     * <p>
+     * If this method is called when it is not an overlap, {@code this}
+     * is returned.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @return a {@code ZoneChronoDateTime} based on this date-time with the earlier offset, not null
+     * @throws DateTimeException if no rules can be found for the zone
+     * @throws DateTimeException if no rules are valid for this date-time
+     */
+    ChronoZonedDateTime<C> withEarlierOffsetAtOverlap();
+
+    /**
+     * Returns a copy of this date-time changing the zone offset to the
+     * later of the two valid offsets at a local time-line overlap.
+     * <p>
+     * This method only has any effect when the local time-line overlaps, such as
+     * at an autumn daylight savings cutover. In this scenario, there are two
+     * valid offsets for the local date-time. Calling this method will return
+     * a zoned date-time with the later of the two selected.
+     * <p>
+     * If this method is called when it is not an overlap, {@code this}
+     * is returned.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @return a {@code ChronoZonedDateTime} based on this date-time with the later offset, not null
+     * @throws DateTimeException if no rules can be found for the zone
+     * @throws DateTimeException if no rules are valid for this date-time
+     */
+    ChronoZonedDateTime<C> withLaterOffsetAtOverlap();
+
+    /**
+     * Returns a copy of this ZonedDateTime with a different time-zone,
+     * retaining the local date-time if possible.
+     * <p>
+     * This method changes the time-zone and retains the local date-time.
+     * The local date-time is only changed if it is invalid for the new zone.
+     * <p>
+     * To change the zone and adjust the local date-time,
+     * use {@link #withZoneSameInstant(ZoneId)}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param zone  the time-zone to change to, not null
+     * @return a {@code ChronoZonedDateTime} based on this date-time with the requested zone, not null
+     */
+    ChronoZonedDateTime<C> withZoneSameLocal(ZoneId zone);
+
+    /**
+     * Returns a copy of this date-time with a different time-zone,
+     * retaining the instant.
+     * <p>
+     * This method changes the time-zone and retains the instant.
+     * This normally results in a change to the local date-time.
+     * <p>
+     * This method is based on retaining the same instant, thus gaps and overlaps
+     * in the local time-line have no effect on the result.
+     * <p>
+     * To change the offset while keeping the local time,
+     * use {@link #withZoneSameLocal(ZoneId)}.
+     *
+     * @param zone  the time-zone to change to, not null
+     * @return a {@code ChronoZonedDateTime} based on this date-time with the requested zone, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    ChronoZonedDateTime<C> withZoneSameInstant(ZoneId zone);
+
+    //-----------------------------------------------------------------------
+    // override for covariant return type
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public default ChronoZonedDateTime<C> with(TemporalAdjuster adjuster) {
+        return getDate().getChrono().ensureChronoZonedDateTime(Temporal.super.with(adjuster));
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    ChronoZonedDateTime<C> with(TemporalField field, long newValue);
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public default ChronoZonedDateTime<C> plus(TemporalAdder adder) {
+        return getDate().getChrono().ensureChronoZonedDateTime(Temporal.super.plus(adder));
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    ChronoZonedDateTime<C> plus(long amountToAdd, TemporalUnit unit);
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public default ChronoZonedDateTime<C> minus(TemporalSubtractor subtractor) {
+        return getDate().getChrono().ensureChronoZonedDateTime(Temporal.super.minus(subtractor));
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public default ChronoZonedDateTime<C> minus(long amountToSubtract, TemporalUnit unit) {
+        return getDate().getChrono().ensureChronoZonedDateTime(Temporal.super.minus(amountToSubtract, unit));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this date-time using the specified query.
+     * <p>
+     * This queries this date-time using the specified query strategy object.
+     * The {@code TemporalQuery} object defines the logic to be used to
+     * obtain the result. Read the documentation of the query to understand
+     * what the result of this method will be.
+     * <p>
+     * The result of this method is obtained by invoking the
+     * {@link java.time.temporal.TemporalQuery#queryFrom(TemporalAccessor)} method on the
+     * specified query passing {@code this} as the argument.
+     *
+     * @param <R> the type of the result
+     * @param query  the query to invoke, not null
+     * @return the query result, null may be returned (defined by the query)
+     * @throws DateTimeException if unable to query (defined by the query)
+     * @throws ArithmeticException if numeric overflow occurs (defined by the query)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public default <R> R query(TemporalQuery<R> query) {
+        if (query == Queries.zone() || query == Queries.zoneId()) {
+            return (R) getZone();
+        } else if (query == Queries.chrono()) {
+            return (R) getDate().getChrono();
+        } else if (query == Queries.precision()) {
+            return (R) NANOS;
+        } else if (query == Queries.offset()) {
+            return (R) getOffset();
+        }
+        // inline TemporalAccessor.super.query(query) as an optimization
+        return query.queryFrom(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Converts this date-time to an {@code Instant}.
+     * <p>
+     * This combines the {@linkplain #getDateTime() local date-time} and
+     * {@linkplain #getOffset() offset} to form an {@code Instant}.
+     *
+     * @return an {@code Instant} representing the same instant, not null
+     */
+    public default Instant toInstant() {
+        return Instant.ofEpochSecond(toEpochSecond(), getTime().getNano());
+    }
+
+    /**
+     * Converts this date-time to the number of seconds from the epoch
+     * of 1970-01-01T00:00:00Z.
+     * <p>
+     * This uses the {@linkplain #getDateTime() local date-time} and
+     * {@linkplain #getOffset() offset} to calculate the epoch-second value,
+     * which is the number of elapsed seconds from 1970-01-01T00:00:00Z.
+     * Instants on the time-line after the epoch are positive, earlier are negative.
+     *
+     * @return the number of seconds from the epoch of 1970-01-01T00:00:00Z
+     */
+    public default long toEpochSecond() {
+        long epochDay = getDate().toEpochDay();
+        long secs = epochDay * 86400 + getTime().toSecondOfDay();
+        secs -= getOffset().getTotalSeconds();
+        return secs;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this date-time to another date-time, including the chronology.
+     * <p>
+     * The comparison is based first on the instant, then on the local date-time,
+     * then on the zone ID, then on the chronology.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     * <p>
+     * If all the date-time objects being compared are in the same chronology, then the
+     * additional chronology stage is not required.
+     * <p>
+     * This default implementation performs the comparison defined above.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     */
+    @Override
+    public default int compareTo(ChronoZonedDateTime<?> other) {
+        int cmp = Long.compare(toEpochSecond(), other.toEpochSecond());
+        if (cmp == 0) {
+            cmp = getTime().getNano() - other.getTime().getNano();
+            if (cmp == 0) {
+                cmp = getDateTime().compareTo(other.getDateTime());
+                if (cmp == 0) {
+                    cmp = getZone().getId().compareTo(other.getZone().getId());
+                    if (cmp == 0) {
+                        cmp = getDate().getChrono().compareTo(other.getDate().getChrono());
+                    }
+                }
+            }
+        }
+        return cmp;
+    }
+
+    /**
+     * Checks if the instant of this date-time is before that of the specified date-time.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} in that it
+     * only compares the instant of the date-time. This is equivalent to using
+     * {@code dateTime1.toInstant().isBefore(dateTime2.toInstant());}.
+     * <p>
+     * This default implementation performs the comparison based on the epoch-second
+     * and nano-of-second.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return true if this point is before the specified date-time
+     */
+    public default boolean isBefore(ChronoZonedDateTime<?> other) {
+        long thisEpochSec = toEpochSecond();
+        long otherEpochSec = other.toEpochSecond();
+        return thisEpochSec < otherEpochSec ||
+            (thisEpochSec == otherEpochSec && getTime().getNano() < other.getTime().getNano());
+    }
+
+    /**
+     * Checks if the instant of this date-time is after that of the specified date-time.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} in that it
+     * only compares the instant of the date-time. This is equivalent to using
+     * {@code dateTime1.toInstant().isAfter(dateTime2.toInstant());}.
+     * <p>
+     * This default implementation performs the comparison based on the epoch-second
+     * and nano-of-second.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return true if this is after the specified date-time
+     */
+    public default boolean isAfter(ChronoZonedDateTime<?> other) {
+        long thisEpochSec = toEpochSecond();
+        long otherEpochSec = other.toEpochSecond();
+        return thisEpochSec > otherEpochSec ||
+            (thisEpochSec == otherEpochSec && getTime().getNano() > other.getTime().getNano());
+    }
+
+    /**
+     * Checks if the instant of this date-time is equal to that of the specified date-time.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} and {@link #equals}
+     * in that it only compares the instant of the date-time. This is equivalent to using
+     * {@code dateTime1.toInstant().equals(dateTime2.toInstant());}.
+     * <p>
+     * This default implementation performs the comparison based on the epoch-second
+     * and nano-of-second.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return true if the instant equals the instant of the specified date-time
+     */
+    public default boolean isEqual(ChronoZonedDateTime<?> other) {
+        return toEpochSecond() == other.toEpochSecond() &&
+                getTime().getNano() == other.getTime().getNano();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this date-time is equal to another date-time.
+     * <p>
+     * The comparison is based on the offset date-time and the zone.
+     * To compare for the same instant on the time-line, use {@link #compareTo}.
+     * Only objects of type {@code ChronoZonedDateTime} are compared, other types return false.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other date-time
+     */
+    @Override
+    boolean equals(Object obj);
+
+    /**
+     * A hash code for this date-time.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    int hashCode();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this date-time as a {@code String}.
+     * <p>
+     * The output will include the full zoned date-time and the chronology ID.
+     *
+     * @return a string representation of this date-time, not null
+     */
+    @Override
+    String toString();
+
+    /**
+     * Outputs this date-time as a {@code String} using the formatter.
+     * <p>
+     * The default implementation must behave as follows:
+     * <pre>
+     *  return formatter.print(this);
+     * </pre>
+     *
+     * @param formatter  the formatter to use, not null
+     * @return the formatted date-time string, not null
+     * @throws DateTimeException if an error occurs during printing
+     */
+    public default String toString(DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.print(this);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/ChronoZonedDateTimeImpl.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import static java.time.temporal.ChronoUnit.SECONDS;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.zone.ZoneOffsetTransition;
+import java.time.zone.ZoneRules;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A date-time with a time-zone in the calendar neutral API.
+ * <p>
+ * {@code ZoneChronoDateTime} is an immutable representation of a date-time with a time-zone.
+ * This class stores all date and time fields, to a precision of nanoseconds,
+ * as well as a time-zone and zone offset.
+ * <p>
+ * The purpose of storing the time-zone is to distinguish the ambiguous case where
+ * the local time-line overlaps, typically as a result of the end of daylight time.
+ * Information about the local-time can be obtained using methods on the time-zone.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @param <C> the chronology of this date
+ * @since 1.8
+ */
+final class ChronoZonedDateTimeImpl<C extends Chrono<C>>
+        implements ChronoZonedDateTime<C>, Serializable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -5261813987200935591L;
+
+    /**
+     * The local date-time.
+     */
+    private final ChronoLocalDateTimeImpl<C> dateTime;
+    /**
+     * The zone offset.
+     */
+    private final ZoneOffset offset;
+    /**
+     * The zone ID.
+     */
+    private final ZoneId zone;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance from a local date-time using the preferred offset if possible.
+     *
+     * @param localDateTime  the local date-time, not null
+     * @param zone  the zone identifier, not null
+     * @param preferredOffset  the zone offset, null if no preference
+     * @return the zoned date-time, not null
+     */
+    static <R extends Chrono<R>> ChronoZonedDateTime<R> ofBest(
+            ChronoLocalDateTimeImpl<R> localDateTime, ZoneId zone, ZoneOffset preferredOffset) {
+        Objects.requireNonNull(localDateTime, "localDateTime");
+        Objects.requireNonNull(zone, "zone");
+        if (zone instanceof ZoneOffset) {
+            return new ChronoZonedDateTimeImpl<R>(localDateTime, (ZoneOffset) zone, zone);
+        }
+        ZoneRules rules = zone.getRules();
+        LocalDateTime isoLDT = LocalDateTime.from(localDateTime);
+        List<ZoneOffset> validOffsets = rules.getValidOffsets(isoLDT);
+        ZoneOffset offset;
+        if (validOffsets.size() == 1) {
+            offset = validOffsets.get(0);
+        } else if (validOffsets.size() == 0) {
+            ZoneOffsetTransition trans = rules.getTransition(isoLDT);
+            localDateTime = localDateTime.plusSeconds(trans.getDuration().getSeconds());
+            offset = trans.getOffsetAfter();
+        } else {
+            if (preferredOffset != null && validOffsets.contains(preferredOffset)) {
+                offset = preferredOffset;
+            } else {
+                offset = validOffsets.get(0);
+            }
+        }
+        Objects.requireNonNull(offset, "offset");  // protect against bad ZoneRules
+        return new ChronoZonedDateTimeImpl<R>(localDateTime, offset, zone);
+    }
+
+    /**
+     * Obtains an instance from an instant using the specified time-zone.
+     *
+     * @param chrono  the chronology, not null
+     * @param instant  the instant, not null
+     * @param zone  the zone identifier, not null
+     * @return the zoned date-time, not null
+     */
+    static <R extends Chrono<R>> ChronoZonedDateTimeImpl<R> ofInstant(Chrono<R> chrono, Instant instant, ZoneId zone) {
+        ZoneRules rules = zone.getRules();
+        ZoneOffset offset = rules.getOffset(instant);
+        Objects.requireNonNull(offset, "offset");  // protect against bad ZoneRules
+        LocalDateTime ldt = LocalDateTime.ofEpochSecond(instant.getEpochSecond(), instant.getNano(), offset);
+        ChronoLocalDateTimeImpl<R> cldt = (ChronoLocalDateTimeImpl<R>) chrono.localDateTime(ldt);
+        return new ChronoZonedDateTimeImpl<R>(cldt, offset, zone);
+    }
+
+    /**
+     * Obtains an instance from an {@code Instant}.
+     *
+     * @param instant  the instant to create the date-time from, not null
+     * @param zone  the time-zone to use, validated not null
+     * @return the zoned date-time, validated not null
+     */
+    private ChronoZonedDateTimeImpl<C> create(Instant instant, ZoneId zone) {
+        return ofInstant(getDate().getChrono(), instant, zone);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructor.
+     *
+     * @param dateTime  the date-time, not null
+     * @param offset  the zone offset, not null
+     * @param zone  the zone ID, not null
+     */
+    private ChronoZonedDateTimeImpl(ChronoLocalDateTimeImpl<C> dateTime, ZoneOffset offset, ZoneId zone) {
+        this.dateTime = Objects.requireNonNull(dateTime, "dateTime");
+        this.offset = Objects.requireNonNull(offset, "offset");
+        this.zone = Objects.requireNonNull(zone, "zone");
+    }
+
+    //-----------------------------------------------------------------------
+    public ZoneOffset getOffset() {
+        return offset;
+    }
+
+    @Override
+    public ChronoZonedDateTime<C> withEarlierOffsetAtOverlap() {
+        ZoneOffsetTransition trans = getZone().getRules().getTransition(LocalDateTime.from(this));
+        if (trans != null && trans.isOverlap()) {
+            ZoneOffset earlierOffset = trans.getOffsetBefore();
+            if (earlierOffset.equals(offset) == false) {
+                return new ChronoZonedDateTimeImpl<C>(dateTime, earlierOffset, zone);
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public ChronoZonedDateTime<C> withLaterOffsetAtOverlap() {
+        ZoneOffsetTransition trans = getZone().getRules().getTransition(LocalDateTime.from(this));
+        if (trans != null) {
+            ZoneOffset offset = trans.getOffsetAfter();
+            if (offset.equals(getOffset()) == false) {
+                return new ChronoZonedDateTimeImpl<C>(dateTime, offset, zone);
+            }
+        }
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ChronoLocalDateTime<C> getDateTime() {
+        return dateTime;
+    }
+
+    public ZoneId getZone() {
+        return zone;
+    }
+
+    public ChronoZonedDateTime<C> withZoneSameLocal(ZoneId zone) {
+        return ofBest(dateTime, zone, offset);
+    }
+
+    @Override
+    public ChronoZonedDateTime<C> withZoneSameInstant(ZoneId zone) {
+        Objects.requireNonNull(zone, "zone");
+        return this.zone.equals(zone) ? this : create(dateTime.toInstant(offset), zone);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public boolean isSupported(TemporalField field) {
+        return field instanceof ChronoField || (field != null && field.doIsSupported(this));
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ChronoZonedDateTime<C> with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            switch (f) {
+                case INSTANT_SECONDS: return plus(newValue - toEpochSecond(), SECONDS);
+                case OFFSET_SECONDS: {
+                    ZoneOffset offset = ZoneOffset.ofTotalSeconds(f.checkValidIntValue(newValue));
+                    return create(dateTime.toInstant(offset), zone);
+                }
+            }
+            return ofBest(dateTime.with(field, newValue), zone, offset);
+        }
+        return getDate().getChrono().ensureChronoZonedDateTime(field.doWith(this, newValue));
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ChronoZonedDateTime<C> plus(long amountToAdd, TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            return with(dateTime.plus(amountToAdd, unit));
+        }
+        return getDate().getChrono().ensureChronoZonedDateTime(unit.doPlus(this, amountToAdd));   /// TODO: Generics replacement Risk!
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public long periodUntil(Temporal endDateTime, TemporalUnit unit) {
+        if (endDateTime instanceof ChronoZonedDateTime == false) {
+            throw new DateTimeException("Unable to calculate period between objects of two different types");
+        }
+        @SuppressWarnings("unchecked")
+        ChronoZonedDateTime<C> end = (ChronoZonedDateTime<C>) endDateTime;
+        if (getDate().getChrono().equals(end.getDate().getChrono()) == false) {
+            throw new DateTimeException("Unable to calculate period between two different chronologies");
+        }
+        if (unit instanceof ChronoUnit) {
+            end = end.withZoneSameInstant(offset);
+            return dateTime.periodUntil(end.getDateTime(), unit);
+        }
+        return unit.between(this, endDateTime).getAmount();
+    }
+
+    //-----------------------------------------------------------------------
+    private Object writeReplace() {
+        return new Ser(Ser.CHRONO_ZONE_DATE_TIME_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     * @return never
+     * @throws InvalidObjectException always
+     */
+    private Object readResolve() throws ObjectStreamException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    void writeExternal(ObjectOutput out) throws IOException {
+        out.writeObject(dateTime);
+        out.writeObject(offset);
+        out.writeObject(zone);
+    }
+
+    static ChronoZonedDateTime<?> readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+        ChronoLocalDateTime<?> dateTime = (ChronoLocalDateTime<?>) in.readObject();
+        ZoneOffset offset = (ZoneOffset) in.readObject();
+        ZoneId zone = (ZoneId) in.readObject();
+        return dateTime.atZone(offset).withZoneSameLocal(zone);
+        // TODO: ZDT uses ofLenient()
+    }
+
+    //-------------------------------------------------------------------------
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof ChronoZonedDateTime) {
+            return compareTo((ChronoZonedDateTime<?>) obj) == 0;
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return getDateTime().hashCode() ^ getOffset().hashCode() ^ Integer.rotateLeft(getZone().hashCode(), 3);
+    }
+
+    @Override
+    public String toString() {
+        String str = getDateTime().toString() + getOffset().toString();
+        if (getOffset() != getZone()) {
+            str += '[' + getZone().toString() + ']';
+        }
+        return str;
+    }
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/Era.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import static java.time.temporal.ChronoField.ERA;
+import static java.time.temporal.ChronoUnit.ERAS;
+
+import java.time.DateTimeException;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.TextStyle;
+import java.util.Locale;
+
+/**
+ * An era of the time-line.
+ * <p>
+ * Most calendar systems have a single epoch dividing the time-line into two eras.
+ * However, some calendar systems, have multiple eras, such as one for the reign
+ * of each leader.
+ * In all cases, the era is conceptually the largest division of the time-line.
+ * Each chronology defines the Era's that are known Eras and a
+ * {@link Chrono#eras Chrono.eras} to get the valid eras.
+ * <p>
+ * For example, the Thai Buddhist calendar system divides time into two eras,
+ * before and after a single date. By contrast, the Japanese calendar system
+ * has one era for the reign of each Emperor.
+ * <p>
+ * Instances of {@code Era} may be compared using the {@code ==} operator.
+ *
+ * <h3>Specification for implementors</h3>
+ * This interface must be implemented with care to ensure other classes operate correctly.
+ * All implementations must be singletons - final, immutable and thread-safe.
+ * It is recommended to use an enum whenever possible.
+ *
+ * @param <C> the chronology of the era
+ * @since 1.8
+ */
+public interface Era<C extends Chrono<C>> extends TemporalAccessor, TemporalAdjuster {
+
+    /**
+     * Gets the numeric value associated with the era as defined by the chronology.
+     * Each chronology defines the predefined Eras and methods to list the Eras
+     * of the chronology.
+     * <p>
+     * All fields, including eras, have an associated numeric value.
+     * The meaning of the numeric value for era is determined by the chronology
+     * according to these principles:
+     * <p><ul>
+     * <li>The era in use at the epoch 1970-01-01 (ISO) has the value 1.
+     * <li>Later eras have sequentially higher values.
+     * <li>Earlier eras have sequentially lower values, which may be negative.
+     * </ul><p>
+     *
+     * @return the numeric era value
+     */
+    int getValue();
+
+    /**
+     * Gets the chronology of this era.
+     * <p>
+     * The {@code Chrono} represents the calendar system in use.
+     * This always returns the standard form of the chronology.
+     *
+     * @return the chronology, not null
+     */
+    C getChrono();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a date in this era given the year-of-era, month, and day.
+     * <p>
+     * This era is combined with the given date fields to form a date.
+     * The year specified must be the year-of-era.
+     * Methods to create a date from the proleptic-year are on {@code Chrono}.
+     * This always uses the standard form of the chronology.
+     * <p>
+     * This default implementation invokes the factory method on {@link Chrono}.
+     *
+     * @param yearOfEra  the calendar system year-of-era
+     * @param month  the calendar system month-of-year
+     * @param day  the calendar system day-of-month
+     * @return a local date based on this era and the specified year-of-era, month and day
+     */
+    public default ChronoLocalDate<C> date(int yearOfEra, int month, int day) {
+        return getChrono().date(this, yearOfEra, month, day);
+    }
+
+
+    /**
+     * Obtains a date in this era given year-of-era and day-of-year fields.
+     * <p>
+     * This era is combined with the given date fields to form a date.
+     * The year specified must be the year-of-era.
+     * Methods to create a date from the proleptic-year are on {@code Chrono}.
+     * This always uses the standard form of the chronology.
+     * <p>
+     * This default implementation invokes the factory method on {@link Chrono}.
+     *
+     * @param yearOfEra  the calendar system year-of-era
+     * @param dayOfYear  the calendar system day-of-year
+     * @return a local date based on this era and the specified year-of-era and day-of-year
+     */
+    public default ChronoLocalDate<C> dateYearDay(int yearOfEra, int dayOfYear) {
+        return getChrono().dateYearDay(this, yearOfEra, dayOfYear);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if this era can be queried for the specified field.
+     * If false, then calling the {@link #range(TemporalField) range} and
+     * {@link #get(TemporalField) get} methods will throw an exception.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@code ERA} field returns true.
+     * All other {@code ChronoField} instances will return false.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the field is supported is determined by the field.
+     *
+     * @param field  the field to check, null returns false
+     * @return true if the field is supported on this era, false if not
+     */
+    @Override
+    public default boolean isSupported(TemporalField field) {
+        if (field instanceof ChronoField) {
+            return field == ERA;
+        }
+        return field != null && field.doIsSupported(this);
+    }
+
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * The range object expresses the minimum and maximum valid values for a field.
+     * This era is used to enhance the accuracy of the returned range.
+     * If it is not possible to return the range, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@code ERA} field returns the range.
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the range can be obtained is determined by the field.
+     *
+     * @param field  the field to query the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     */
+    @Override  // override for Javadoc
+    public default ValueRange range(TemporalField field) {
+        return TemporalAccessor.super.range(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this era as an {@code int}.
+     * <p>
+     * This queries this era for the value for the specified field.
+     * The returned value will always be within the valid range of values for the field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@code ERA} field returns the value of the era.
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override  // override for Javadoc and performance
+    public default int get(TemporalField field) {
+        if (field == ERA) {
+            return getValue();
+        }
+        return range(field).checkValidIntValue(getLong(field), field);
+    }
+
+    /**
+     * Gets the value of the specified field from this era as a {@code long}.
+     * <p>
+     * This queries this era for the value for the specified field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@code ERA} field returns the value of the era.
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public default long getLong(TemporalField field) {
+        if (field == ERA) {
+            return getValue();
+        } else if (field instanceof ChronoField) {
+            throw new DateTimeException("Unsupported field: " + field.getName());
+        }
+        return field.doGet(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this era using the specified query.
+     * <p>
+     * This queries this era using the specified query strategy object.
+     * The {@code TemporalQuery} object defines the logic to be used to
+     * obtain the result. Read the documentation of the query to understand
+     * what the result of this method will be.
+     * <p>
+     * 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 <R> the type of the result
+     * @param query  the query to invoke, not null
+     * @return the query result, null may be returned (defined by the query)
+     * @throws DateTimeException if unable to query (defined by the query)
+     * @throws ArithmeticException if numeric overflow occurs (defined by the query)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public default <R> R query(TemporalQuery<R> query) {
+        if (query == Queries.chrono()) {
+            return (R) getChrono();
+        } else if (query == Queries.precision()) {
+            return (R) ERAS;
+        }
+        return TemporalAccessor.super.query(query);
+    }
+
+    /**
+     * Adjusts the specified temporal object to have the same era as this object.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with the era changed to be the same as this.
+     * <p>
+     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+     * passing {@link ChronoField#ERA} as the field.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisEra.adjustInto(temporal);
+     *   temporal = temporal.with(thisEra);
+     * </pre>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param temporal  the target object to be adjusted, not null
+     * @return the adjusted object, not null
+     * @throws DateTimeException if unable to make the adjustment
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public default Temporal adjustInto(Temporal temporal) {
+        return temporal.with(ERA, getValue());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the textual representation of this era.
+     * <p>
+     * This returns the textual name used to identify the era.
+     * The parameters control the style of the returned text and the locale.
+     * <p>
+     * If no textual mapping is found then the {@link #getValue() numeric value} is returned.
+     * <p>
+     * This default implementation is suitable for all implementations.
+     *
+     * @param style  the style of the text required, not null
+     * @param locale  the locale to use, not null
+     * @return the text value of the era, not null
+     */
+    public default String getText(TextStyle style, Locale locale) {
+        return new DateTimeFormatterBuilder().appendText(ERA, style).toFormatter(locale).print(this);
+    }
+
+    // NOTE: methods to convert year-of-era/proleptic-year cannot be here as they may depend on month/day (Japanese)
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/ISOChrono.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,399 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import java.io.Serializable;
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+import java.util.Objects;
+
+/**
+ * The ISO calendar system.
+ * <p>
+ * This chronology defines the rules of the ISO calendar system.
+ * This calendar system is based on the ISO-8601 standard, which is the
+ * <i>de facto</i> world calendar.
+ * <p>
+ * The fields are defined as follows:
+ * <p><ul>
+ * <li>era - There are two eras, 'Current Era' (CE) and 'Before Current Era' (BCE).
+ * <li>year-of-era - The year-of-era is the same as the proleptic-year for the current CE era.
+ *  For the BCE era before the ISO epoch the year increases from 1 upwards as time goes backwards.
+ * <li>proleptic-year - The proleptic year is the same as the year-of-era for the
+ *  current era. For the previous era, years have zero, then negative values.
+ * <li>month-of-year - There are 12 months in an ISO year, numbered from 1 to 12.
+ * <li>day-of-month - There are between 28 and 31 days in each of the ISO month, numbered from 1 to 31.
+ *  Months 4, 6, 9 and 11 have 30 days, Months 1, 3, 5, 7, 8, 10 and 12 have 31 days.
+ *  Month 2 has 28 days, or 29 in a leap year.
+ * <li>day-of-year - There are 365 days in a standard ISO year and 366 in a leap year.
+ *  The days are numbered from 1 to 365 or 1 to 366.
+ * <li>leap-year - Leap years occur every 4 years, except where the year is divisble by 100 and not divisble by 400.
+ * </ul><p>
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class ISOChrono extends Chrono<ISOChrono> implements Serializable {
+
+    /**
+     * Singleton instance of the ISO chronology.
+     */
+    public static final ISOChrono INSTANCE = new ISOChrono();
+    /**
+     * The singleton instance for the era BCE - 'Before Current Era'.
+     * The 'ISO' part of the name emphasizes that this differs from the BCE
+     * era in the Gregorian calendar system.
+     * This has the numeric value of {@code 0}.
+     */
+    public static final Era<ISOChrono> 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<ISOChrono> ERA_CE = ISOEra.CE;
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -1440403870442975015L;
+
+    /**
+     * Restricted constructor.
+     */
+    private ISOChrono() {
+    }
+
+    /**
+     * Resolve singleton.
+     *
+     * @return the singleton instance, not null
+     */
+    private Object readResolve() {
+        return INSTANCE;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the ID of the chronology - 'ISO'.
+     * <p>
+     * The ID uniquely identifies the {@code Chrono}.
+     * It can be used to lookup the {@code Chrono} using {@link #of(String)}.
+     *
+     * @return the chronology ID - 'ISO'
+     * @see #getCalendarType()
+     */
+    @Override
+    public String getId() {
+        return "ISO";
+    }
+
+    /**
+     * Gets the calendar type of the underlying calendar system - 'iso8601'.
+     * <p>
+     * The calendar type is an identifier defined by the
+     * <em>Unicode Locale Data Markup Language (LDML)</em> specification.
+     * It can be used to lookup the {@code Chrono} using {@link #of(String)}.
+     * It can also be used as part of a locale, accessible via
+     * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
+     *
+     * @return the calendar system type - 'iso8601'
+     * @see #getId()
+     */
+    @Override
+    public String getCalendarType() {
+        return "iso8601";
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an ISO local date from the era, year-of-era, month-of-year
+     * and day-of-month fields.
+     *
+     * @param era  the ISO era, not null
+     * @param yearOfEra  the ISO year-of-era
+     * @param month  the ISO month-of-year
+     * @param dayOfMonth  the ISO day-of-month
+     * @return the ISO local date, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    @Override  // override with covariant return type
+    public LocalDate date(Era<ISOChrono> era, int yearOfEra, int month, int dayOfMonth) {
+        return date(prolepticYear(era, yearOfEra), month, dayOfMonth);
+    }
+
+    /**
+     * Obtains an ISO local date from the proleptic-year, month-of-year
+     * and day-of-month fields.
+     * <p>
+     * This is equivalent to {@link LocalDate#of(int, int, int)}.
+     *
+     * @param prolepticYear  the ISO proleptic-year
+     * @param month  the ISO month-of-year
+     * @param dayOfMonth  the ISO day-of-month
+     * @return the ISO local date, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    @Override  // override with covariant return type
+    public LocalDate date(int prolepticYear, int month, int dayOfMonth) {
+        return LocalDate.of(prolepticYear, month, dayOfMonth);
+    }
+
+    /**
+     * Obtains an ISO local date from the era, year-of-era and day-of-year fields.
+     *
+     * @param era  the ISO era, not null
+     * @param yearOfEra  the ISO year-of-era
+     * @param dayOfYear  the ISO day-of-year
+     * @return the ISO local date, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    @Override  // override with covariant return type
+    public LocalDate dateYearDay(Era<ISOChrono> era, int yearOfEra, int dayOfYear) {
+        return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear);
+    }
+
+    /**
+     * Obtains an ISO local date from the proleptic-year and day-of-year fields.
+     * <p>
+     * This is equivalent to {@link LocalDate#ofYearDay(int, int)}.
+     *
+     * @param prolepticYear  the ISO proleptic-year
+     * @param dayOfYear  the ISO day-of-year
+     * @return the ISO local date, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    @Override  // override with covariant return type
+    public LocalDate dateYearDay(int prolepticYear, int dayOfYear) {
+        return LocalDate.ofYearDay(prolepticYear, dayOfYear);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an ISO local date from another date-time object.
+     * <p>
+     * This is equivalent to {@link LocalDate#from(TemporalAccessor)}.
+     *
+     * @param temporal  the date-time object to convert, not null
+     * @return the ISO local date, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    @Override  // override with covariant return type
+    public LocalDate date(TemporalAccessor temporal) {
+        return LocalDate.from(temporal);
+    }
+
+    /**
+     * Obtains an ISO local date-time from another date-time object.
+     * <p>
+     * This is equivalent to {@link LocalDateTime#from(TemporalAccessor)}.
+     *
+     * @param temporal  the date-time object to convert, not null
+     * @return the ISO local date-time, not null
+     * @throws DateTimeException if unable to create the date-time
+     */
+    @Override  // override with covariant return type
+    public LocalDateTime localDateTime(TemporalAccessor temporal) {
+        return LocalDateTime.from(temporal);
+    }
+
+    /**
+     * Obtains an ISO zoned date-time from another date-time object.
+     * <p>
+     * This is equivalent to {@link ZonedDateTime#from(TemporalAccessor)}.
+     *
+     * @param temporal  the date-time object to convert, not null
+     * @return the ISO zoned date-time, not null
+     * @throws DateTimeException if unable to create the date-time
+     */
+    @Override  // override with covariant return type
+    public ZonedDateTime zonedDateTime(TemporalAccessor temporal) {
+        return ZonedDateTime.from(temporal);
+    }
+
+    /**
+     * Obtains an ISO zoned date-time in this chronology from an {@code Instant}.
+     * <p>
+     * This is equivalent to {@link ZonedDateTime#ofInstant(Instant, ZoneId)}.
+     *
+     * @param instant  the instant to create the date-time from, not null
+     * @param zone  the time-zone, not null
+     * @return the zoned date-time, not null
+     * @throws DateTimeException if the result exceeds the supported range
+     */
+    public ZonedDateTime zonedDateTime(Instant instant, ZoneId zone) {
+        return ZonedDateTime.ofInstant(instant, zone);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains the current ISO local date from the system clock in the default time-zone.
+     * <p>
+     * This will query the {@link Clock#systemDefaultZone() system clock} in the default
+     * time-zone to obtain the current date.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @return the current ISO local date using the system clock and default time-zone, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    @Override  // override with covariant return type
+    public LocalDate dateNow() {
+        return dateNow(Clock.systemDefaultZone());
+    }
+
+    /**
+     * Obtains the current ISO local date from the system clock in the specified time-zone.
+     * <p>
+     * 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.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @return the current ISO local date using the system clock, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    @Override  // override with covariant return type
+    public LocalDate dateNow(ZoneId zone) {
+        return dateNow(Clock.system(zone));
+    }
+
+    /**
+     * Obtains the current ISO local date from the specified clock.
+     * <p>
+     * This will query the specified clock to obtain the current date - today.
+     * Using this method allows the use of an alternate clock for testing.
+     * The alternate clock may be introduced using {@link Clock dependency injection}.
+     *
+     * @param clock  the clock to use, not null
+     * @return the current ISO local date, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    @Override  // override with covariant return type
+    public LocalDate dateNow(Clock clock) {
+        Objects.requireNonNull(clock, "clock");
+        return date(LocalDate.now(clock));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the year is a leap year, according to the ISO proleptic
+     * calendar system rules.
+     * <p>
+     * This method applies the current rules for leap years across the whole time-line.
+     * In general, a year is a leap year if it is divisible by four without
+     * remainder. However, years divisible by 100, are not leap years, with
+     * the exception of years divisible by 400 which are.
+     * <p>
+     * For example, 1904 is a leap year it is divisible by 4.
+     * 1900 was not a leap year as it is divisible by 100, however 2000 was a
+     * leap year as it is divisible by 400.
+     * <p>
+     * The calculation is proleptic - applying the same rules into the far future and far past.
+     * This is historically inaccurate, but is correct for the ISO-8601 standard.
+     *
+     * @param prolepticYear  the ISO proleptic year to check
+     * @return true if the year is leap, false otherwise
+     */
+    @Override
+    public boolean isLeapYear(long prolepticYear) {
+        return ((prolepticYear & 3) == 0) && ((prolepticYear % 100) != 0 || (prolepticYear % 400) == 0);
+    }
+
+    @Override
+    public int prolepticYear(Era<ISOChrono> era, int yearOfEra) {
+        if (era instanceof ISOEra == false) {
+            throw new DateTimeException("Era must be ISOEra");
+        }
+        return (era == ISOEra.CE ? yearOfEra : 1 - yearOfEra);
+    }
+
+    @Override
+    public Era<ISOChrono> eraOf(int eraValue) {
+        return ISOEra.of(eraValue);
+    }
+
+    @Override
+    public List<Era<ISOChrono>> eras() {
+        return Arrays.<Era<ISOChrono>>asList(ISOEra.values());
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ValueRange range(ChronoField field) {
+        return field.range();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/ISOEra.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import static java.time.temporal.ChronoField.ERA;
+
+import java.time.DateTimeException;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.TextStyle;
+import java.util.Locale;
+
+/**
+ * An era in the ISO calendar system.
+ * <p>
+ * The ISO-8601 standard does not define eras.
+ * A definition has therefore been created with two eras - 'Current era' (CE) for
+ * years from 0001-01-01 (ISO) and 'Before current era' (BCE) for years before that.
+ * <p>
+ * <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code ISOEra}.
+ * Use {@code getValue()} instead.</b>
+ *
+ * <h3>Specification for implementors</h3>
+ * This is an immutable and thread-safe enum.
+ *
+ * @since 1.8
+ */
+enum ISOEra implements Era<ISOChrono> {
+
+    /**
+     * The singleton instance for the era BCE, 'Before Current Era'.
+     * The 'ISO' part of the name emphasizes that this differs from the BCE
+     * era in the Gregorian calendar system.
+     * This has the numeric value of {@code 0}.
+     */
+    BCE,
+    /**
+     * The singleton instance for the era CE, 'Current Era'.
+     * The 'ISO' part of the name emphasizes that this differs from the CE
+     * era in the Gregorian calendar system.
+     * This has the numeric value of {@code 1}.
+     */
+    CE;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ISOEra} from an {@code int} value.
+     * <p>
+     * {@code ISOEra} is an enum representing the ISO eras of BCE/CE.
+     * This factory allows the enum to be obtained from the {@code int} value.
+     *
+     * @param era  the BCE/CE value to represent, from 0 (BCE) to 1 (CE)
+     * @return the era singleton, not null
+     * @throws DateTimeException if the value is invalid
+     */
+    public static ISOEra of(int era) {
+        switch (era) {
+            case 0:
+                return BCE;
+            case 1:
+                return CE;
+            default:
+                throw new DateTimeException("Invalid era: " + era);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the numeric era {@code int} value.
+     * <p>
+     * The era BCE has the value 0, while the era CE has the value 1.
+     *
+     * @return the era value, from 0 (BCE) to 1 (CE)
+     */
+    @Override
+    public int getValue() {
+        return ordinal();
+    }
+
+    @Override
+    public ISOChrono getChrono() {
+        return ISOChrono.INSTANCE;
+    }
+
+    // JDK8 default methods:
+    //-----------------------------------------------------------------------
+    @Override
+    public ChronoLocalDate<ISOChrono> date(int year, int month, int day) {
+        return getChrono().date(this, year, month, day);
+    }
+
+    @Override
+    public ChronoLocalDate<ISOChrono> 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);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/ISOFields.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,564 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import static java.time.DayOfWeek.THURSDAY;
+import static java.time.DayOfWeek.WEDNESDAY;
+import static java.time.temporal.ChronoField.DAY_OF_WEEK;
+import static java.time.temporal.ChronoField.DAY_OF_YEAR;
+import static java.time.temporal.ChronoField.EPOCH_DAY;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.YEAR;
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.FOREVER;
+import static java.time.temporal.ChronoUnit.MONTHS;
+import static java.time.temporal.ChronoUnit.WEEKS;
+import static java.time.temporal.ChronoUnit.YEARS;
+
+import java.time.DateTimeException;
+import java.time.Duration;
+import java.time.LocalDate;
+import java.time.format.DateTimeBuilder;
+
+/**
+ * Fields and units specific to the ISO-8601 calendar system,
+ * including quarter-of-year and week-based-year.
+ * <p>
+ * This class defines fields and units that are specific to the ISO calendar system.
+ *
+ * <h3>Quarter of year</h3>
+ * The ISO-8601 standard is based on the standard civic 12 month year.
+ * This is commonly divided into four quarters, often abbreviated as Q1, Q2, Q3 and Q4.
+ * <p>
+ * January, February and March are in Q1.
+ * April, May and June are in Q2.
+ * July, August and September are in Q3.
+ * October, November and December are in Q4.
+ * <p>
+ * The complete date is expressed using three fields:
+ * <p><ul>
+ * <li>{@link #DAY_OF_QUARTER DAY_OF_QUARTER} - the day within the quarter, from 1 to 90, 91 or 92
+ * <li>{@link #QUARTER_OF_YEAR QUARTER_OF_YEAR} - the week within the week-based-year
+ * <li>{@link ChronoField#YEAR YEAR} - the standard ISO year
+ * </ul><p>
+ *
+ * <h3>Week based years</h3>
+ * The ISO-8601 standard was originally intended as a data interchange format,
+ * defining a string format for dates and times. However, it also defines an
+ * alternate way of expressing the date, based on the concept of week-based-year.
+ * <p>
+ * The date is expressed using three fields:
+ * <p><ul>
+ * <li>{@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} - the standard field defining the
+ *  day-of-week from Monday (1) to Sunday (7)
+ * <li>{@link #WEEK_OF_WEEK_BASED_YEAR} - the week within the week-based-year
+ * <li>{@link #WEEK_BASED_YEAR WEEK_BASED_YEAR} - the week-based-year
+ * </ul><p>
+ * The week-based-year itself is defined relative to the standard ISO proleptic year.
+ * It differs from the standard year in that it always starts on a Monday.
+ * <p>
+ * The first week of a week-based-year is the first Monday-based week of the standard
+ * ISO year that has at least 4 days in the new year.
+ * <p><ul>
+ * <li>If January 1st is Monday then week 1 starts on January 1st
+ * <li>If January 1st is Tuesday then week 1 starts on December 31st of the previous standard year
+ * <li>If January 1st is Wednesday then week 1 starts on December 30th of the previous standard year
+ * <li>If January 1st is Thursday then week 1 starts on December 29th of the previous standard year
+ * <li>If January 1st is Friday then week 1 starts on January 4th
+ * <li>If January 1st is Saturday then week 1 starts on January 3rd
+ * <li>If January 1st is Sunday then week 1 starts on January 2nd
+ * </ul><p>
+ * There are 52 weeks in most week-based years, however on occasion there are 53 weeks.
+ * <p>
+ * For example:
+ * <p>
+ * <table cellpadding="0" cellspacing="3" border="0" style="text-align: left; width: 50%;">
+ * <caption>Examples of Week based Years</caption>
+ * <tr><th>Date</th><th>Day-of-week</th><th>Field values</th></tr>
+ * <tr><th>2008-12-28</th><td>Sunday</td><td>Week 52 of week-based-year 2008</td></tr>
+ * <tr><th>2008-12-29</th><td>Monday</td><td>Week 1 of week-based-year 2009</td></tr>
+ * <tr><th>2008-12-31</th><td>Wednesday</td><td>Week 1 of week-based-year 2009</td></tr>
+ * <tr><th>2009-01-01</th><td>Thursday</td><td>Week 1 of week-based-year 2009</td></tr>
+ * <tr><th>2009-01-04</th><td>Sunday</td><td>Week 1 of week-based-year 2009</td></tr>
+ * <tr><th>2009-01-05</th><td>Monday</td><td>Week 2 of week-based-year 2009</td></tr>
+ * </table>
+ *
+ * <h3>Specification for implementors</h3>
+ * <p>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class ISOFields {
+
+    /**
+     * The field that represents the day-of-quarter.
+     * <p>
+     * This field allows the day-of-quarter value to be queried and set.
+     * The day-of-quarter has values from 1 to 90 in Q1 of a standard year, from 1 to 91
+     * in Q1 of a leap year, from 1 to 91 in Q2 and from 1 to 92 in Q3 and Q4.
+     * <p>
+     * The day-of-quarter can only be calculated if the day-of-year, month-of-year and year
+     * are available.
+     * <p>
+     * When setting this field, the value is allowed to be partially lenient, taking any
+     * value from 1 to 92. If the quarter has less than 92 days, then day 92, and
+     * potentially day 91, is in the following quarter.
+     * <p>
+     * This unit is an immutable and thread-safe singleton.
+     */
+    public static final TemporalField DAY_OF_QUARTER = Field.DAY_OF_QUARTER;
+    /**
+     * The field that represents the quarter-of-year.
+     * <p>
+     * This field allows the quarter-of-year value to be queried and set.
+     * The quarter-of-year has values from 1 to 4.
+     * <p>
+     * The day-of-quarter can only be calculated if the month-of-year is available.
+     * <p>
+     * This unit is an immutable and thread-safe singleton.
+     */
+    public static final TemporalField QUARTER_OF_YEAR = Field.QUARTER_OF_YEAR;
+    /**
+     * The field that represents the week-of-week-based-year.
+     * <p>
+     * This field allows the week of the week-based-year value to be queried and set.
+     * <p>
+     * This unit is an immutable and thread-safe singleton.
+     */
+    public static final TemporalField WEEK_OF_WEEK_BASED_YEAR = Field.WEEK_OF_WEEK_BASED_YEAR;
+    /**
+     * The field that represents the week-based-year.
+     * <p>
+     * This field allows the week-based-year value to be queried and set.
+     * <p>
+     * This unit is an immutable and thread-safe singleton.
+     */
+    public static final TemporalField WEEK_BASED_YEAR = Field.WEEK_BASED_YEAR;
+    /**
+     * The unit that represents week-based-years for the purpose of addition and subtraction.
+     * <p>
+     * This allows a number of week-based-years to be added to, or subtracted from, a date.
+     * The unit is equal to either 52 or 53 weeks.
+     * The estimated duration of a week-based-year is the same as that of a standard ISO
+     * year at {@code 365.2425 Days}.
+     * <p>
+     * The rules for addition add the number of week-based-years to the existing value
+     * for the week-based-year field. If the resulting week-based-year only has 52 weeks,
+     * then the date will be in week 1 of the following week-based-year.
+     * <p>
+     * This unit is an immutable and thread-safe singleton.
+     */
+    public static final TemporalUnit WEEK_BASED_YEARS = Unit.WEEK_BASED_YEARS;
+    /**
+     * Unit that represents the concept of a quarter-year.
+     * For the ISO calendar system, it is equal to 3 months.
+     * The estimated duration of a quarter-year is one quarter of {@code 365.2425 Days}.
+     * <p>
+     * This unit is an immutable and thread-safe singleton.
+     */
+    public static final TemporalUnit QUARTER_YEARS = Unit.QUARTER_YEARS;
+
+    /**
+     * Restricted constructor.
+     */
+    private ISOFields() {
+        throw new AssertionError("Not instantiable");
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Implementation of the field.
+     */
+    private static enum Field implements TemporalField {
+        DAY_OF_QUARTER {
+            @Override
+            public String getName() {
+                return "DayOfQuarter";
+            }
+            @Override
+            public TemporalUnit getBaseUnit() {
+                return DAYS;
+            }
+            @Override
+            public TemporalUnit getRangeUnit() {
+                return QUARTER_YEARS;
+            }
+            @Override
+            public ValueRange range() {
+                return ValueRange.of(1, 90, 92);
+            }
+            @Override
+            public boolean doIsSupported(TemporalAccessor temporal) {
+                return temporal.isSupported(DAY_OF_YEAR) && temporal.isSupported(MONTH_OF_YEAR) &&
+                        temporal.isSupported(YEAR) && Chrono.from(temporal).equals(ISOChrono.INSTANCE);
+            }
+            @Override
+            public ValueRange doRange(TemporalAccessor temporal) {
+                if (doIsSupported(temporal) == false) {
+                    throw new DateTimeException("Unsupported field: DayOfQuarter");
+                }
+                long qoy = temporal.getLong(QUARTER_OF_YEAR);
+                if (qoy == 1) {
+                    long year = temporal.getLong(YEAR);
+                    return (ISOChrono.INSTANCE.isLeapYear(year) ? ValueRange.of(1, 91) : ValueRange.of(1, 90));
+                } else if (qoy == 2) {
+                    return ValueRange.of(1, 91);
+                } else if (qoy == 3 || qoy == 4) {
+                    return ValueRange.of(1, 92);
+                } // else value not from 1 to 4, so drop through
+                return range();
+            }
+            @Override
+            public long doGet(TemporalAccessor temporal) {
+                if (doIsSupported(temporal) == false) {
+                    throw new DateTimeException("Unsupported field: DayOfQuarter");
+                }
+                int doy = temporal.get(DAY_OF_YEAR);
+                int moy = temporal.get(MONTH_OF_YEAR);
+                long year = temporal.getLong(YEAR);
+                return doy - QUARTER_DAYS[((moy - 1) / 3) + (ISOChrono.INSTANCE.isLeapYear(year) ? 4 : 0)];
+            }
+            @Override
+            public <R extends Temporal> R doWith(R temporal, long newValue) {
+                long curValue = doGet(temporal);
+                range().checkValidValue(newValue, this);
+                return (R) temporal.with(DAY_OF_YEAR, temporal.getLong(DAY_OF_YEAR) + (newValue - curValue));
+            }
+        },
+        QUARTER_OF_YEAR {
+            @Override
+            public String getName() {
+                return "QuarterOfYear";
+            }
+            @Override
+            public TemporalUnit getBaseUnit() {
+                return QUARTER_YEARS;
+            }
+            @Override
+            public TemporalUnit getRangeUnit() {
+                return YEARS;
+            }
+            @Override
+            public ValueRange range() {
+                return ValueRange.of(1, 4);
+            }
+            @Override
+            public boolean doIsSupported(TemporalAccessor temporal) {
+                return temporal.isSupported(MONTH_OF_YEAR) && Chrono.from(temporal).equals(ISOChrono.INSTANCE);
+            }
+            @Override
+            public long doGet(TemporalAccessor temporal) {
+                if (doIsSupported(temporal) == false) {
+                    throw new DateTimeException("Unsupported field: DayOfQuarter");
+                }
+                long moy = temporal.getLong(MONTH_OF_YEAR);
+                return ((moy + 2) / 3);
+            }
+            @Override
+            public <R extends Temporal> R doWith(R temporal, long newValue) {
+                long curValue = doGet(temporal);
+                range().checkValidValue(newValue, this);
+                return (R) temporal.with(MONTH_OF_YEAR, temporal.getLong(MONTH_OF_YEAR) + (newValue - curValue) * 3);
+            }
+            @Override
+            public boolean resolve(DateTimeBuilder builder, long value) {
+                Long[] values = builder.queryFieldValues(YEAR, QUARTER_OF_YEAR, DAY_OF_QUARTER);
+                if (values[0] != null && values[1] != null && values[2] != null) {
+                    int y = YEAR.range().checkValidIntValue(values[0], YEAR);
+                    int qoy = QUARTER_OF_YEAR.range().checkValidIntValue(values[1], QUARTER_OF_YEAR);
+                    int doq = DAY_OF_QUARTER.range().checkValidIntValue(values[2], DAY_OF_QUARTER);
+                    LocalDate date = LocalDate.of(y, ((qoy - 1) * 3) + 1, 1).plusDays(doq - 1);
+                    builder.addFieldValue(EPOCH_DAY, date.toEpochDay());
+                    builder.removeFieldValues(QUARTER_OF_YEAR, DAY_OF_QUARTER);
+                }
+                return false;
+            }
+        },
+        WEEK_OF_WEEK_BASED_YEAR {
+            @Override
+            public String getName() {
+                return "WeekOfWeekBasedYear";
+            }
+            @Override
+            public TemporalUnit getBaseUnit() {
+                return WEEKS;
+            }
+            @Override
+            public TemporalUnit getRangeUnit() {
+                return WEEK_BASED_YEARS;
+            }
+            @Override
+            public ValueRange range() {
+                return ValueRange.of(1, 52, 53);
+            }
+            @Override
+            public boolean doIsSupported(TemporalAccessor temporal) {
+                return temporal.isSupported(EPOCH_DAY);
+            }
+            @Override
+            public ValueRange doRange(TemporalAccessor temporal) {
+                return getWeekRange(LocalDate.from(temporal));
+            }
+            @Override
+            public long doGet(TemporalAccessor temporal) {
+                return getWeek(LocalDate.from(temporal));
+            }
+            @Override
+            public <R extends Temporal> R doWith(R temporal, long newValue) {
+                ValueRange.of(1, 53).checkValidValue(newValue, this);
+                return (R) temporal.plus(Math.subtractExact(newValue, doGet(temporal)), WEEKS);
+            }
+        },
+        WEEK_BASED_YEAR {
+            @Override
+            public String getName() {
+                return "WeekBasedYear";
+            }
+            @Override
+            public TemporalUnit getBaseUnit() {
+                return WEEK_BASED_YEARS;
+            }
+            @Override
+            public TemporalUnit getRangeUnit() {
+                return FOREVER;
+            }
+            @Override
+            public ValueRange range() {
+                return YEAR.range();
+            }
+            @Override
+            public boolean doIsSupported(TemporalAccessor temporal) {
+                return temporal.isSupported(EPOCH_DAY);
+            }
+            @Override
+            public long doGet(TemporalAccessor temporal) {
+                return getWeekBasedYear(LocalDate.from(temporal));
+            }
+            @Override
+            public <R extends Temporal> R doWith(R temporal, long newValue) {
+                int newVal = range().checkValidIntValue(newValue, WEEK_BASED_YEAR);
+                LocalDate date = LocalDate.from(temporal);
+                int week = getWeek(date);
+                date = date.withDayOfYear(180).withYear(newVal).with(WEEK_OF_WEEK_BASED_YEAR, week);
+                return (R) date.with(date);
+            }
+            @Override
+            public boolean resolve(DateTimeBuilder builder, long value) {
+                Long[] values = builder.queryFieldValues(WEEK_BASED_YEAR, WEEK_OF_WEEK_BASED_YEAR, DAY_OF_WEEK);
+                if (values[0] != null && values[1] != null && values[2] != null) {
+                    int wby = WEEK_BASED_YEAR.range().checkValidIntValue(values[0], WEEK_BASED_YEAR);
+                    int week = WEEK_OF_WEEK_BASED_YEAR.range().checkValidIntValue(values[1], WEEK_OF_WEEK_BASED_YEAR);
+                    int dow = DAY_OF_WEEK.range().checkValidIntValue(values[2], DAY_OF_WEEK);
+                    LocalDate date = LocalDate.of(wby, 2, 1).with(WEEK_OF_WEEK_BASED_YEAR, week).with(DAY_OF_WEEK, dow);
+                    builder.addFieldValue(EPOCH_DAY, date.toEpochDay());
+                    builder.removeFieldValues(WEEK_BASED_YEAR, WEEK_OF_WEEK_BASED_YEAR, DAY_OF_WEEK);
+                }
+                return false;
+            }
+        };
+
+        @Override
+        public ValueRange doRange(TemporalAccessor temporal) {
+            return range();
+        }
+
+        @Override
+        public boolean resolve(DateTimeBuilder builder, long value) {
+            return false;
+        }
+
+        @Override
+        public String toString() {
+            return getName();
+        }
+
+        //-------------------------------------------------------------------------
+        private static final int[] QUARTER_DAYS = {0, 90, 181, 273, 0, 91, 182, 274};
+
+        private static ValueRange getWeekRange(LocalDate date) {
+            int wby = getWeekBasedYear(date);
+            date = date.withDayOfYear(1).withYear(wby);
+            // 53 weeks if standard year starts on Thursday, or Wed in a leap year
+            if (date.getDayOfWeek() == THURSDAY || (date.getDayOfWeek() == WEDNESDAY && date.isLeapYear())) {
+                return ValueRange.of(1, 53);
+            }
+            return ValueRange.of(1, 52);
+        }
+
+        private static int getWeek(LocalDate date) {
+            int dow0 = date.getDayOfWeek().ordinal();
+            int doy0 = date.getDayOfYear() - 1;
+            int doyThu0 = doy0 + (3 - dow0);  // adjust to mid-week Thursday (which is 3 indexed from zero)
+            int alignedWeek = doyThu0 / 7;
+            int firstThuDoy0 = doyThu0 - (alignedWeek * 7);
+            int firstMonDoy0 = firstThuDoy0 - 3;
+            if (firstMonDoy0 < -3) {
+                firstMonDoy0 += 7;
+            }
+            if (doy0 < firstMonDoy0) {
+                return (int) getWeekRange(date.withDayOfYear(180).minusYears(1)).getMaximum();
+            }
+            int week = ((doy0 - firstMonDoy0) / 7) + 1;
+            if (week == 53) {
+                if ((firstMonDoy0 == -3 || (firstMonDoy0 == -2 && date.isLeapYear())) == false) {
+                    week = 1;
+                }
+            }
+            return week;
+        }
+
+        private static int getWeekBasedYear(LocalDate date) {
+            int year = date.getYear();
+            int doy = date.getDayOfYear();
+            if (doy <= 3) {
+                int dow = date.getDayOfWeek().ordinal();
+                if (doy - dow < -2) {
+                    year--;
+                }
+            } else if (doy >= 363) {
+                int dow = date.getDayOfWeek().ordinal();
+                doy = doy - 363 - (date.isLeapYear() ? 1 : 0);
+                if (doy - dow >= 0) {
+                    year++;
+                }
+            }
+            return year;
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Implementation of the period unit.
+     */
+    private static enum Unit implements TemporalUnit {
+
+        /**
+         * Unit that represents the concept of a week-based-year.
+         */
+        WEEK_BASED_YEARS("WeekBasedYears", Duration.ofSeconds(31556952L)),
+        /**
+         * Unit that represents the concept of a quarter-year.
+         */
+        QUARTER_YEARS("QuarterYears", Duration.ofSeconds(31556952L / 4));
+
+        private final String name;
+        private final Duration duration;
+
+        private Unit(String name, Duration estimatedDuration) {
+            this.name = name;
+            this.duration = estimatedDuration;
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public Duration getDuration() {
+            return duration;
+        }
+
+        @Override
+        public boolean isDurationEstimated() {
+            return true;
+        }
+
+        @Override
+        public boolean isSupported(Temporal temporal) {
+            return temporal.isSupported(EPOCH_DAY);
+        }
+
+        @Override
+        public <R extends Temporal> R doPlus(R dateTime, long periodToAdd) {
+            switch(this) {
+                case WEEK_BASED_YEARS:
+                    return (R) dateTime.with(WEEK_BASED_YEAR,
+                            Math.addExact(dateTime.get(WEEK_BASED_YEAR), periodToAdd));
+                case QUARTER_YEARS:
+                    // no overflow (256 is multiple of 4)
+                    return (R) dateTime.plus(periodToAdd / 256, YEARS)
+                            .plus((periodToAdd % 256) * 3, MONTHS);
+                default:
+                    throw new IllegalStateException("Unreachable");
+            }
+        }
+
+        @Override
+        public <R extends Temporal> SimplePeriod between(R dateTime1, R dateTime2) {
+            switch(this) {
+                case WEEK_BASED_YEARS:
+                    long period = Math.subtractExact(dateTime2.getLong(WEEK_BASED_YEAR),
+                            dateTime1.getLong(WEEK_BASED_YEAR));
+                    return new SimplePeriod(period, WEEK_BASED_YEARS);
+                case QUARTER_YEARS:
+                    long period2 = Math.subtractExact(dateTime2.getLong(QUARTER_OF_YEAR),
+                            dateTime1.getLong(QUARTER_OF_YEAR));
+                    return new SimplePeriod(period2, QUARTER_YEARS);
+                default:
+                    throw new IllegalStateException("Unreachable");
+            }
+        }
+
+        @Override
+        public String toString() {
+            return getName();
+
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/JulianFields.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import static java.time.temporal.ChronoField.EPOCH_DAY;
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.FOREVER;
+
+import java.io.InvalidObjectException;
+import java.io.Serializable;
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.format.DateTimeBuilder;
+
+/**
+ * A set of date fields that provide access to Julian Days.
+ * <p>
+ * 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.
+ *
+ * <h3>Specification for implementors</h3>
+ * This is an immutable and thread-safe class.
+ *
+ * @since 1.8
+ */
+public final class JulianFields {
+
+    /**
+     * The offset from Julian to EPOCH DAY.
+     */
+    private static final long JULIAN_DAY_OFFSET = 2440588L;
+
+    /**
+     * Julian Day field.
+     * <p>
+     * This is an integer-based version of the Julian Day Number.
+     * Julian Day is a well-known system that represents the count of whole days since day 0,
+     * which is defined to be January 1, 4713 BCE in the Julian calendar, and -4713-11-24 Gregorian.
+     * The field  has "JulianDay" as 'name', and 'DAYS' as 'baseUnit'.
+     * The field always refers to the local date-time, ignoring the offset or zone.
+     * <p>
+     * For date-times, 'JULIAN_DAY.doGet()' assumes the same value from
+     * midnight until just before the next midnight.
+     * When 'JULIAN_DAY.doWith()' is applied to a date-time, the time of day portion remains unaltered.
+     * 'JULIAN_DAY.doWith()' and 'JULIAN_DAY.doGet()' only apply to {@code Temporal} objects that
+     * can be converted into {@link ChronoField#EPOCH_DAY}.
+     * A {@link DateTimeException} is thrown for any other type of object.
+     * <p>
+     * <h3>Astronomical and Scientific Notes</h3>
+     * The standard astronomical definition uses a fraction to indicate the time-of-day,
+     * thus 3.25 would represent the time 18:00, since days start at midday.
+     * This implementation uses an integer and days starting at midnight.
+     * The integer value for the Julian Day Number is the astronomical Julian Day value at midday
+     * of the date in question.
+     * This amounts to the astronomical Julian Day, rounded to an integer {@code JDN = floor(JD + 0.5)}.
+     * <p>
+     * <pre>
+     *  | ISO date          |  Julian Day Number | Astronomical Julian Day |
+     *  | 1970-01-01T00:00  |         2,440,588  |         2,440,587.5     |
+     *  | 1970-01-01T06:00  |         2,440,588  |         2,440,587.75    |
+     *  | 1970-01-01T12:00  |         2,440,588  |         2,440,588.0     |
+     *  | 1970-01-01T18:00  |         2,440,588  |         2,440,588.25    |
+     *  | 1970-01-02T00:00  |         2,440,589  |         2,440,588.5     |
+     *  | 1970-01-02T06:00  |         2,440,589  |         2,440,588.75    |
+     *  | 1970-01-02T12:00  |         2,440,589  |         2,440,589.0     |
+     * </pre>
+     * <p>
+     * Julian Days are sometimes taken to imply Universal Time or UTC, but this
+     * implementation always uses the Julian Day number for the local date,
+     * regardless of the offset or time-zone.
+     */
+    public static final TemporalField JULIAN_DAY = new Field("JulianDay", DAYS, FOREVER, JULIAN_DAY_OFFSET);
+
+    /**
+     * Modified Julian Day field.
+     * <p>
+     * This is an integer-based version of the Modified Julian Day Number.
+     * Modified Julian Day (MJD) is a well-known system that counts days continuously.
+     * It is defined relative to astronomical Julian Day as  {@code MJD = JD - 2400000.5}.
+     * Each Modified Julian Day runs from midnight to midnight.
+     * The field always refers to the local date-time, ignoring the offset or zone.
+     * <p>
+     * For date-times, 'MODIFIED_JULIAN_DAY.doGet()' assumes the same value from
+     * midnight until just before the next midnight.
+     * When 'MODIFIED_JULIAN_DAY.doWith()' is applied to a date-time, the time of day portion remains unaltered.
+     * 'MODIFIED_JULIAN_DAY.doWith()' and 'MODIFIED_JULIAN_DAY.doGet()' only apply to {@code Temporal} objects
+     * that can be converted into {@link ChronoField#EPOCH_DAY}.
+     * A {@link DateTimeException} is thrown for any other type of object.
+     * <p>
+     * This implementation is an integer version of MJD with the decimal part rounded to floor.
+     * <p>
+     * <h3>Astronomical and Scientific Notes</h3>
+     * <pre>
+     *  | ISO date          | Modified Julian Day |      Decimal MJD |
+     *  | 1970-01-01T00:00  |             40,587  |       40,587.0   |
+     *  | 1970-01-01T06:00  |             40,587  |       40,587.25  |
+     *  | 1970-01-01T12:00  |             40,587  |       40,587.5   |
+     *  | 1970-01-01T18:00  |             40,587  |       40,587.75  |
+     *  | 1970-01-02T00:00  |             40,588  |       40,588.0   |
+     *  | 1970-01-02T06:00  |             40,588  |       40,588.25  |
+     *  | 1970-01-02T12:00  |             40,588  |       40,588.5   |
+     * </pre>
+     * <p>
+     * Modified Julian Days are sometimes taken to imply Universal Time or UTC, but this
+     * implementation always uses the Modified Julian Day for the local date,
+     * regardless of the offset or time-zone.
+     */
+    public static final TemporalField MODIFIED_JULIAN_DAY = new Field("ModifiedJulianDay", DAYS, FOREVER, 40587L);
+
+    /**
+     * Rata Die field.
+     * <p>
+     * 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.
+     * <p>
+     * For date-times, 'RATA_DIE.doGet()' assumes the same value from
+     * midnight until just before the next midnight.
+     * When 'RATA_DIE.doWith()' is applied to a date-time, the time of day portion remains unaltered.
+     * 'MODIFIED_JULIAN_DAY.doWith()' and 'RATA_DIE.doGet()' only apply to {@code Temporal} objects
+     * that can be converted into {@link ChronoField#EPOCH_DAY}.
+     * A {@link DateTimeException} is thrown for any other type of object.
+     */
+    public static final TemporalField RATA_DIE = new Field("RataDie", DAYS, FOREVER, 719163L);
+
+    /**
+     * Restricted constructor.
+     */
+    private JulianFields() {
+        throw new AssertionError("Not instantiable");
+    }
+
+    /**
+     * implementation of JulianFields.  Each instance is a singleton.
+     */
+    private static class Field implements TemporalField, Serializable {
+
+        private static final long serialVersionUID = -7501623920830201812L;
+
+        private final String name;
+        private final transient TemporalUnit baseUnit;
+        private final transient TemporalUnit rangeUnit;
+        private final transient ValueRange range;
+        private final transient long offset;
+
+        private Field(String name, TemporalUnit baseUnit, TemporalUnit rangeUnit, long offset) {
+            this.name = name;
+            this.baseUnit = baseUnit;
+            this.rangeUnit = rangeUnit;
+            this.range = ValueRange.of(-365243219162L + offset, 365241780471L + offset);
+            this.offset = offset;
+        }
+
+
+        /**
+         * Resolve the object from the stream to the appropriate singleton.
+         * @return one of the singleton objects {@link #JULIAN_DAY},
+         *     {@link #MODIFIED_JULIAN_DAY}, or {@link #RATA_DIE}.
+         * @throws InvalidObjectException if the object in the stream is not one of the singletons.
+         */
+        private Object readResolve() throws InvalidObjectException {
+            if (JULIAN_DAY.getName().equals(name)) {
+                return JULIAN_DAY;
+            } else if (MODIFIED_JULIAN_DAY.getName().equals(name)) {
+                return MODIFIED_JULIAN_DAY;
+            } else if (RATA_DIE.getName().equals(name)) {
+                return RATA_DIE;
+            } else {
+                throw new InvalidObjectException("Not one of the singletons");
+            }
+        }
+
+        //-----------------------------------------------------------------------
+        @Override
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public TemporalUnit getBaseUnit() {
+            return baseUnit;
+        }
+
+        @Override
+        public TemporalUnit getRangeUnit() {
+            return rangeUnit;
+        }
+
+        @Override
+        public ValueRange range() {
+            return range;
+        }
+
+        //-----------------------------------------------------------------------
+        @Override
+        public boolean doIsSupported(TemporalAccessor temporal) {
+            return temporal.isSupported(EPOCH_DAY);
+        }
+
+        @Override
+        public ValueRange doRange(TemporalAccessor temporal) {
+            if (doIsSupported(temporal) == false) {
+                throw new DateTimeException("Unsupported field: " + this);
+            }
+            return range();
+        }
+
+        @Override
+        public long doGet(TemporalAccessor temporal) {
+            return temporal.getLong(EPOCH_DAY) + offset;
+        }
+
+        @Override
+        public <R extends Temporal> R doWith(R temporal, long newValue) {
+            if (range().isValidValue(newValue) == false) {
+                throw new DateTimeException("Invalid value: " + name + " " + newValue);
+            }
+            return (R) temporal.with(EPOCH_DAY, Math.subtractExact(newValue, offset));
+        }
+
+        //-----------------------------------------------------------------------
+        @Override
+        public boolean resolve(DateTimeBuilder builder, long value) {
+            boolean changed = false;
+            changed = resolve0(JULIAN_DAY, builder, changed);
+            changed = resolve0(MODIFIED_JULIAN_DAY, builder, changed);
+            changed = resolve0(RATA_DIE, builder, changed);
+            return changed;
+        }
+
+        private boolean resolve0(TemporalField field, DateTimeBuilder builder, boolean changed) {
+            if (builder.containsFieldValue(field)) {
+                builder.addCalendrical(LocalDate.ofEpochDay(Math.subtractExact(builder.getFieldValue(JULIAN_DAY), JULIAN_DAY_OFFSET)));
+                builder.removeFieldValue(JULIAN_DAY);
+                changed = true;
+            }
+            return changed;
+        }
+
+        //-----------------------------------------------------------------------
+        @Override
+        public String toString() {
+            return getName();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/MonthDay.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,755 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.Month;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.DateTimeParseException;
+import java.util.Objects;
+
+/**
+ * A month-day in the ISO-8601 calendar system, such as {@code --12-03}.
+ * <p>
+ * {@code MonthDay} is an immutable date-time object that represents the combination
+ * of a year and month. Any field that can be derived from a month and day, such as
+ * quarter-of-year, can be obtained.
+ * <p>
+ * This class does not store or represent a year, time or time-zone.
+ * For example, the value "December 3rd" can be stored in a {@code MonthDay}.
+ * <p>
+ * Since a {@code MonthDay} does not possess a year, the leap day of
+ * February 29th is considered valid.
+ * <p>
+ * This class implements {@link TemporalAccessor} rather than {@link Temporal}.
+ * This is because it is not possible to define whether February 29th is valid or not
+ * without external information, preventing the implementation of plus/minus.
+ * Related to this, {@code MonthDay} only provides access to query and set the fields
+ * {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH}.
+ * <p>
+ * The ISO-8601 calendar system is the modern civil calendar system used today
+ * in most of the world. It is equivalent to the proleptic Gregorian calendar
+ * system, in which today's rules for leap years are applied for all time.
+ * For most applications written today, the ISO-8601 rules are entirely suitable.
+ * However, any application that makes use of historical dates, and requires them
+ * to be accurate will find the ISO-8601 approach unsuitable.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class MonthDay
+        implements TemporalAccessor, TemporalAdjuster, Comparable<MonthDay>, Serializable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -939150713474957432L;
+    /**
+     * Parser.
+     */
+    private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder()
+        .appendLiteral("--")
+        .appendValue(MONTH_OF_YEAR, 2)
+        .appendLiteral('-')
+        .appendValue(DAY_OF_MONTH, 2)
+        .toFormatter();
+
+    /**
+     * The month-of-year, not null.
+     */
+    private final int month;
+    /**
+     * The day-of-month.
+     */
+    private final int day;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains the current month-day from the system clock in the default time-zone.
+     * <p>
+     * This will query the {@link java.time.Clock#systemDefaultZone() system clock} in the default
+     * time-zone to obtain the current month-day.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @return the current month-day using the system clock and default time-zone, not null
+     */
+    public static MonthDay now() {
+        return now(Clock.systemDefaultZone());
+    }
+
+    /**
+     * Obtains the current month-day from the system clock in the specified time-zone.
+     * <p>
+     * This will query the {@link Clock#system(java.time.ZoneId) system clock} to obtain the current month-day.
+     * Specifying the time-zone avoids dependence on the default time-zone.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @param zone  the zone ID to use, not null
+     * @return the current month-day using the system clock, not null
+     */
+    public static MonthDay now(ZoneId zone) {
+        return now(Clock.system(zone));
+    }
+
+    /**
+     * Obtains the current month-day from the specified clock.
+     * <p>
+     * This will query the specified clock to obtain the current month-day.
+     * Using this method allows the use of an alternate clock for testing.
+     * The alternate clock may be introduced using {@link Clock dependency injection}.
+     *
+     * @param clock  the clock to use, not null
+     * @return the current month-day, not null
+     */
+    public static MonthDay now(Clock clock) {
+        final LocalDate now = LocalDate.now(clock);  // called once
+        return MonthDay.of(now.getMonth(), now.getDayOfMonth());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code MonthDay}.
+     * <p>
+     * The day-of-month must be valid for the month within a leap year.
+     * Hence, for February, day 29 is valid.
+     * <p>
+     * For example, passing in April and day 31 will throw an exception, as
+     * there can never be April 31st in any year. By contrast, passing in
+     * February 29th is permitted, as that month-day can sometimes be valid.
+     *
+     * @param month  the month-of-year to represent, not null
+     * @param dayOfMonth  the day-of-month to represent, from 1 to 31
+     * @return the month-day, not null
+     * @throws DateTimeException if the value of any field is out of range
+     * @throws DateTimeException if the day-of-month is invalid for the month
+     */
+    public static MonthDay of(Month month, int dayOfMonth) {
+        Objects.requireNonNull(month, "month");
+        DAY_OF_MONTH.checkValidValue(dayOfMonth);
+        if (dayOfMonth > month.maxLength()) {
+            throw new DateTimeException("Illegal value for DayOfMonth field, value " + dayOfMonth +
+                    " is not valid for month " + month.name());
+        }
+        return new MonthDay(month.getValue(), dayOfMonth);
+    }
+
+    /**
+     * Obtains an instance of {@code MonthDay}.
+     * <p>
+     * The day-of-month must be valid for the month within a leap year.
+     * Hence, for month 2 (February), day 29 is valid.
+     * <p>
+     * For example, passing in month 4 (April) and day 31 will throw an exception, as
+     * there can never be April 31st in any year. By contrast, passing in
+     * February 29th is permitted, as that month-day can sometimes be valid.
+     *
+     * @param month  the month-of-year to represent, from 1 (January) to 12 (December)
+     * @param dayOfMonth  the day-of-month to represent, from 1 to 31
+     * @return the month-day, not null
+     * @throws DateTimeException if the value of any field is out of range
+     * @throws DateTimeException if the day-of-month is invalid for the month
+     */
+    public static MonthDay of(int month, int dayOfMonth) {
+        return of(Month.of(month), dayOfMonth);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code MonthDay} from a temporal object.
+     * <p>
+     * A {@code TemporalAccessor} represents some form of date and time information.
+     * This factory converts the arbitrary temporal object to an instance of {@code MonthDay}.
+     * <p>
+     * The conversion extracts the {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} and
+     * {@link ChronoField#DAY_OF_MONTH DAY_OF_MONTH} fields.
+     * The extraction is only permitted if the date-time has an ISO chronology.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used in queries via method reference, {@code MonthDay::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the month-day, not null
+     * @throws DateTimeException if unable to convert to a {@code MonthDay}
+     */
+    public static MonthDay from(TemporalAccessor temporal) {
+        if (temporal instanceof MonthDay) {
+            return (MonthDay) temporal;
+        }
+        try {
+            if (ISOChrono.INSTANCE.equals(Chrono.from(temporal)) == false) {
+                temporal = LocalDate.from(temporal);
+            }
+            return of(temporal.get(MONTH_OF_YEAR), temporal.get(DAY_OF_MONTH));
+        } catch (DateTimeException ex) {
+            throw new DateTimeException("Unable to obtain MonthDay from TemporalAccessor: " + temporal.getClass(), ex);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code MonthDay} from a text string such as {@code --12-03}.
+     * <p>
+     * The string must represent a valid month-day.
+     * The format is {@code --MM-dd}.
+     *
+     * @param text  the text to parse such as "--12-03", not null
+     * @return the parsed month-day, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static MonthDay parse(CharSequence text) {
+        return parse(text, PARSER);
+    }
+
+    /**
+     * Obtains an instance of {@code MonthDay} from a text string using a specific formatter.
+     * <p>
+     * The text is parsed using the formatter, returning a month-day.
+     *
+     * @param text  the text to parse, not null
+     * @param formatter  the formatter to use, not null
+     * @return the parsed month-day, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static MonthDay parse(CharSequence text, DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.parse(text, MonthDay::from);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructor, previously validated.
+     *
+     * @param month  the month-of-year to represent, validated from 1 to 12
+     * @param dayOfMonth  the day-of-month to represent, validated from 1 to 29-31
+     */
+    private MonthDay(int month, int dayOfMonth) {
+        this.month = month;
+        this.day = dayOfMonth;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if this month-day can be queried for the specified field.
+     * If false, then calling the {@link #range(TemporalField) range} and
+     * {@link #get(TemporalField) get} methods will throw an exception.
+     * <p>
+     * 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:
+     * <ul>
+     * <li>{@code MONTH_OF_YEAR}
+     * <li>{@code YEAR}
+     * </ul>
+     * All other {@code ChronoField} instances will return false.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the field is supported is determined by the field.
+     *
+     * @param field  the field to check, null returns false
+     * @return true if the field is supported on this month-day, false if not
+     */
+    @Override
+    public boolean isSupported(TemporalField field) {
+        if (field instanceof ChronoField) {
+            return field == MONTH_OF_YEAR || field == DAY_OF_MONTH;
+        }
+        return field != null && field.doIsSupported(this);
+    }
+
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * The range object expresses the minimum and maximum valid values for a field.
+     * This month-day is used to enhance the accuracy of the returned range.
+     * If it is not possible to return the range, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * 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}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the range can be obtained is determined by the field.
+     *
+     * @param field  the field to query the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     */
+    @Override
+    public ValueRange range(TemporalField field) {
+        if (field == MONTH_OF_YEAR) {
+            return field.range();
+        } else if (field == DAY_OF_MONTH) {
+            return ValueRange.of(1, getMonth().minLength(), getMonth().maxLength());
+        }
+        return TemporalAccessor.super.range(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this month-day as an {@code int}.
+     * <p>
+     * This queries this month-day for the value for the specified field.
+     * The returned value will always be within the valid range of values for the field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this month-day.
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override  // override for Javadoc
+    public int get(TemporalField field) {
+        return range(field).checkValidIntValue(getLong(field), field);
+    }
+
+    /**
+     * Gets the value of the specified field from this month-day as a {@code long}.
+     * <p>
+     * This queries this month-day for the value for the specified field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this month-day.
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long getLong(TemporalField field) {
+        if (field instanceof ChronoField) {
+            switch ((ChronoField) field) {
+                // alignedDOW and alignedWOM not supported because they cannot be set in with()
+                case DAY_OF_MONTH: return day;
+                case MONTH_OF_YEAR: return month;
+            }
+            throw new DateTimeException("Unsupported field: " + field.getName());
+        }
+        return field.doGet(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the month-of-year field using the {@code Month} enum.
+     * <p>
+     * This method returns the enum {@link Month} for the month.
+     * This avoids confusion as to what {@code int} values mean.
+     * If you need access to the primitive {@code int} value then the enum
+     * provides the {@link Month#getValue() int value}.
+     *
+     * @return the month-of-year, not null
+     */
+    public Month getMonth() {
+        return Month.of(month);
+    }
+
+    /**
+     * Gets the day-of-month field.
+     * <p>
+     * This method returns the primitive {@code int} value for the day-of-month.
+     *
+     * @return the day-of-month, from 1 to 31
+     */
+    public int getDayOfMonth() {
+        return day;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the year is valid for this month-day.
+     * <p>
+     * This method checks whether this month and day and the input year form
+     * a valid date. This can only return false for February 29th.
+     *
+     * @param year  the year to validate, an out of range value returns false
+     * @return true if the year is valid for this month-day
+     * @see Year#isValidMonthDay(MonthDay)
+     */
+    public boolean isValidYear(int year) {
+        return (day == 29 && month == 2 && Year.isLeap(year) == false) == false;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code MonthDay} with the month-of-year altered.
+     * <p>
+     * This returns a month-day with the specified month.
+     * If the day-of-month is invalid for the specified month, the day will
+     * be adjusted to the last valid day-of-month.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param month  the month-of-year to set in the returned month-day, from 1 (January) to 12 (December)
+     * @return a {@code MonthDay} based on this month-day with the requested month, not null
+     * @throws DateTimeException if the month-of-year value is invalid
+     */
+    public MonthDay withMonth(int month) {
+        return with(Month.of(month));
+    }
+
+    /**
+     * Returns a copy of this {@code MonthDay} with the month-of-year altered.
+     * <p>
+     * This returns a month-day with the specified month.
+     * If the day-of-month is invalid for the specified month, the day will
+     * be adjusted to the last valid day-of-month.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param month  the month-of-year to set in the returned month-day, not null
+     * @return a {@code MonthDay} based on this month-day with the requested month, not null
+     */
+    public MonthDay with(Month month) {
+        Objects.requireNonNull(month, "month");
+        if (month.getValue() == this.month) {
+            return this;
+        }
+        int day = Math.min(this.day, month.maxLength());
+        return new MonthDay(month.getValue(), day);
+    }
+
+    /**
+     * Returns a copy of this {@code MonthDay} with the day-of-month altered.
+     * <p>
+     * This returns a month-day with the specified day-of-month.
+     * If the day-of-month is invalid for the month, an exception is thrown.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param dayOfMonth  the day-of-month to set in the return month-day, from 1 to 31
+     * @return a {@code MonthDay} based on this month-day with the requested day, not null
+     * @throws DateTimeException if the day-of-month value is invalid
+     * @throws DateTimeException if the day-of-month is invalid for the month
+     */
+    public MonthDay withDayOfMonth(int dayOfMonth) {
+        if (dayOfMonth == this.day) {
+            return this;
+        }
+        return of(month, dayOfMonth);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this month-day using the specified query.
+     * <p>
+     * This queries this month-day using the specified query strategy object.
+     * The {@code TemporalQuery} object defines the logic to be used to
+     * obtain the result. Read the documentation of the query to understand
+     * what the result of this method will be.
+     * <p>
+     * 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 <R> 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> R query(TemporalQuery<R> query) {
+        if (query == Queries.chrono()) {
+            return (R) ISOChrono.INSTANCE;
+        }
+        return TemporalAccessor.super.query(query);
+    }
+
+    /**
+     * Adjusts the specified temporal object to have this month-day.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with the month and day-of-month changed to be the same as this.
+     * <p>
+     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+     * twice, passing {@link ChronoField#MONTH_OF_YEAR} and
+     * {@link ChronoField#DAY_OF_MONTH} as the fields.
+     * If the specified temporal object does not use the ISO calendar system then
+     * a {@code DateTimeException} is thrown.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisMonthDay.adjustInto(temporal);
+     *   temporal = temporal.with(thisMonthDay);
+     * </pre>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param temporal  the target object to be adjusted, not null
+     * @return the adjusted object, not null
+     * @throws DateTimeException if unable to make the adjustment
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Temporal adjustInto(Temporal temporal) {
+        if (Chrono.from(temporal).equals(ISOChrono.INSTANCE) == false) {
+            throw new DateTimeException("Adjustment only supported on ISO date-time");
+        }
+        temporal = temporal.with(MONTH_OF_YEAR, month);
+        return temporal.with(DAY_OF_MONTH, Math.min(temporal.range(DAY_OF_MONTH).getMaximum(), day));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a date formed from this month-day at the specified year.
+     * <p>
+     * This combines this month-day and the specified year to form a {@code LocalDate}.
+     * A month-day of February 29th will be adjusted to February 28th in the resulting
+     * date if the year is not a leap year.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param year  the year to use, from MIN_YEAR to MAX_YEAR
+     * @return the local date formed from this month-day and the specified year, not null
+     * @see Year#atMonthDay(MonthDay)
+     */
+    public LocalDate atYear(int year) {
+        return LocalDate.of(year, month, isValidYear(year) ? day : 28);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this month-day to another month-day.
+     * <p>
+     * The comparison is based first on value of the month, then on the value of the day.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     *
+     * @param other  the other month-day to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     */
+    public int compareTo(MonthDay other) {
+        int cmp = (month - other.month);
+        if (cmp == 0) {
+            cmp = (day - other.day);
+        }
+        return cmp;
+    }
+
+    /**
+     * Is this month-day after the specified month-day.
+     *
+     * @param other  the other month-day to compare to, not null
+     * @return true if this is after the specified month-day
+     */
+    public boolean isAfter(MonthDay other) {
+        return compareTo(other) > 0;
+    }
+
+    /**
+     * Is this month-day before the specified month-day.
+     *
+     * @param other  the other month-day to compare to, not null
+     * @return true if this point is before the specified month-day
+     */
+    public boolean isBefore(MonthDay other) {
+        return compareTo(other) < 0;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this month-day is equal to another month-day.
+     * <p>
+     * The comparison is based on the time-line position of the month-day within a year.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other month-day
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof MonthDay) {
+            MonthDay other = (MonthDay) obj;
+            return month == other.month && day == other.day;
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this month-day.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return (month << 6) + day;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this month-day as a {@code String}, such as {@code --12-03}.
+     * <p>
+     * The output will be in the format {@code --MM-dd}:
+     *
+     * @return a string representation of this month-day, not null
+     */
+    @Override
+    public String toString() {
+        return new StringBuilder(10).append("--")
+            .append(month < 10 ? "0" : "").append(month)
+            .append(day < 10 ? "-0" : "-").append(day)
+            .toString();
+    }
+
+    /**
+     * Outputs this month-day as a {@code String} using the formatter.
+     * <p>
+     * This month-day will be passed to the formatter
+     * {@link DateTimeFormatter#print(TemporalAccessor) print method}.
+     *
+     * @param formatter  the formatter to use, not null
+     * @return the formatted month-day string, not null
+     * @throws DateTimeException if an error occurs during printing
+     */
+    public String toString(DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.print(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>.
+     * <pre>
+     *  out.writeByte(6);  // identifies this as a Year
+     *  out.writeByte(month);
+     *  out.writeByte(day);
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.MONTH_DAY_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     * @return never
+     * @throws InvalidObjectException always
+     */
+    private Object readResolve() throws ObjectStreamException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        out.writeByte(month);
+        out.writeByte(day);
+    }
+
+    static MonthDay readExternal(DataInput in) throws IOException {
+        byte month = in.readByte();
+        byte day = in.readByte();
+        return MonthDay.of(month, day);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/OffsetDate.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,1351 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import static java.time.temporal.ChronoField.EPOCH_DAY;
+import static java.time.temporal.ChronoField.OFFSET_SECONDS;
+import static java.time.temporal.ChronoLocalDateTimeImpl.SECONDS_PER_DAY;
+import static java.time.temporal.ChronoUnit.DAYS;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.DayOfWeek;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.Month;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatters;
+import java.time.format.DateTimeParseException;
+import java.time.zone.ZoneRules;
+import java.util.Objects;
+
+/**
+ * A date with an offset from UTC/Greenwich in the ISO-8601 calendar system,
+ * such as {@code 2007-12-03+01:00}.
+ * <p>
+ * {@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.
+ * <p>
+ * 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}.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class OffsetDate
+        implements Temporal, TemporalAdjuster, Comparable<OffsetDate>, 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * This will query the specified clock to obtain the current date - today.
+     * The offset will be calculated from the time-zone in the clock.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * A {@code TemporalAccessor} represents some form of date and time information.
+     * This factory converts the arbitrary temporal object to an instance of {@code OffsetDate}.
+     * <p>
+     * The conversion extracts and combines {@code LocalDate} and {@code ZoneOffset}.
+     * <p>
+     * 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}.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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:
+     * <ul>
+     * <li>{@code DAY_OF_WEEK}
+     * <li>{@code ALIGNED_DAY_OF_WEEK_IN_MONTH}
+     * <li>{@code ALIGNED_DAY_OF_WEEK_IN_YEAR}
+     * <li>{@code DAY_OF_MONTH}
+     * <li>{@code DAY_OF_YEAR}
+     * <li>{@code EPOCH_DAY}
+     * <li>{@code ALIGNED_WEEK_OF_MONTH}
+     * <li>{@code ALIGNED_WEEK_OF_YEAR}
+     * <li>{@code MONTH_OF_YEAR}
+     * <li>{@code EPOCH_MONTH}
+     * <li>{@code YEAR_OF_ERA}
+     * <li>{@code YEAR}
+     * <li>{@code ERA}
+     * <li>{@code OFFSET_SECONDS}
+     * </ul>
+     * All other {@code ChronoField} instances will return false.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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}.
+     * <p>
+     * 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}.
+     * <p>
+     * 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.
+     * <p>
+     * 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}.
+     * <p>
+     * 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}.
+     * <p>
+     * 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.
+     * <p>
+     * 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}.
+     * <p>
+     * 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'.
+     * <p>
+     * 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.
+     * <p>
+     * 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}.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * This method returns the primitive {@code int} value for the year.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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}.
+     * <p>
+     * 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}.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * For example this code returns a date on the last day of July:
+     * <pre>
+     *  import static java.time.Month.*;
+     *  import static java.time.temporal.Adjusters.*;
+     *
+     *  result = offsetDate.with(JULY).with(lastDayOfMonth());
+     * </pre>
+     * <p>
+     * The classes {@link LocalDate} and {@link ZoneOffset} implement {@code TemporalAdjuster},
+     * thus this method can be used to change the date or offset:
+     * <pre>
+     *  result = offsetDate.with(date);
+     *  result = offsetDate.with(offset);
+     * </pre>
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * If the field is a {@link ChronoField} then the adjustment is implemented here.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * This method adds the specified amount to the years field in three steps:
+     * <ol>
+     * <li>Add the input years to the year field</li>
+     * <li>Check if the resulting date would be invalid</li>
+     * <li>Adjust the day-of-month to the last valid day if necessary</li>
+     * </ol>
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * This method adds the specified amount to the months field in three steps:
+     * <ol>
+     * <li>Add the input months to the month-of-year field</li>
+     * <li>Check if the resulting date would be invalid</li>
+     * <li>Adjust the day-of-month to the last valid day if necessary</li>
+     * </ol>
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * For example, 2008-12-31 plus one week would result in 2009-01-07.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * For example, 2008-12-31 plus one day would result in 2009-01-01.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * This method subtracts the specified amount from the years field in three steps:
+     * <ol>
+     * <li>Subtract the input years to the year field</li>
+     * <li>Check if the resulting date would be invalid</li>
+     * <li>Adjust the day-of-month to the last valid day if necessary</li>
+     * </ol>
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * This method subtracts the specified amount from the months field in three steps:
+     * <ol>
+     * <li>Subtract the input months to the month-of-year field</li>
+     * <li>Check if the resulting date would be invalid</li>
+     * <li>Adjust the day-of-month to the last valid day if necessary</li>
+     * </ol>
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * For example, 2009-01-07 minus one week would result in 2008-12-31.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * For example, 2009-01-01 minus one day would result in 2008-12-31.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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 <R> 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> R query(TemporalQuery<R> 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisOffsetDate.adjustInto(temporal);
+     *   temporal = temporal.with(thisOffsetDate);
+     * </pre>
+     * <p>
+     * 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.
+     * <p>
+     * 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)}.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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:
+     * <pre>
+     *   long period = start.periodUntil(end, MONTHS);   // this method
+     *   dateTime.plus(MONTHS.between(start, end));      // use in plus/minus
+     * </pre>
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * This combines this date with the specified time to form an {@code OffsetDateTime}.
+     * All possible combinations of date and time are valid.
+     * <p>
+     * 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.
+     * <p>
+     * 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}.
+     * <p>
+     * For example, the following is the comparator order:
+     * <ol>
+     * <li>2008-06-29-11:00</li>
+     * <li>2008-06-29-12:00</li>
+     * <li>2008-06-30+12:00</li>
+     * <li>2008-06-29-13:00</li>
+     * </ol>
+     * 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()}.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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)}.
+     * <p>
+     * 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}.
+     * <p>
+     * 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.
+     * <p>
+     * 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
+     * <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>.
+     * <pre>
+     *  out.writeByte(1);  // identifies this as a OffsetDateTime
+     *  out.writeObject(date);
+     *  out.writeObject(offset);
+     * </pre>
+     *
+     * @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);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/OffsetDateTime.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,1824 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import static java.time.temporal.ChronoField.EPOCH_DAY;
+import static java.time.temporal.ChronoField.INSTANT_SECONDS;
+import static java.time.temporal.ChronoField.NANO_OF_DAY;
+import static java.time.temporal.ChronoField.OFFSET_SECONDS;
+import static java.time.temporal.ChronoUnit.NANOS;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.DayOfWeek;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.Month;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatters;
+import java.time.format.DateTimeParseException;
+import java.time.zone.ZoneRules;
+import java.util.Comparator;
+import java.util.Objects;
+
+/**
+ * A date-time with an offset from UTC/Greenwich in the ISO-8601 calendar system,
+ * such as {@code 2007-12-03T10:15:30+01:00}.
+ * <p>
+ * {@code OffsetDateTime} is an immutable representation of a date-time with an offset.
+ * This class stores all date and time fields, to a precision of nanoseconds,
+ * as well as the offset from UTC/Greenwich. For example, the value
+ * "2nd October 2007 at 13:45.30.123456789 +02:00" can be stored in an {@code OffsetDateTime}.
+ * <p>
+ * {@code OffsetDateTime}, {@link java.time.ZonedDateTime} and {@link java.time.Instant} all store an instant
+ * on the time-line to nanosecond precision.
+ * {@code Instant} is the simplest, simply representing the instant.
+ * {@code OffsetDateTime} adds to the instant the offset from UTC/Greenwich, which allows
+ * the local date-time to be obtained.
+ * {@code ZonedDateTime} adds full time-zone rules.
+ * <p>
+ * It is intended that {@code ZonedDateTime} or {@code Instant} is used to model data
+ * in simpler applications. This class may be used when modeling date-time concepts in
+ * more detail, or when communicating to a database or in a network protocol.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class OffsetDateTime
+        implements Temporal, TemporalAdjuster, Comparable<OffsetDateTime>, Serializable {
+
+    /**
+     * The minimum supported {@code OffsetDateTime}, '-999999999-01-01T00:00:00+18:00'.
+     * This is the local date-time of midnight at the start of the minimum date
+     * in the maximum offset (larger offsets are earlier on the time-line).
+     * This combines {@link LocalDateTime#MIN} and {@link ZoneOffset#MAX}.
+     * This could be used by an application as a "far past" date-time.
+     */
+    public static final OffsetDateTime MIN = LocalDateTime.MIN.atOffset(ZoneOffset.MAX);
+    /**
+     * The maximum supported {@code OffsetDateTime}, '+999999999-12-31T23:59:59.999999999-18:00'.
+     * This is the local date-time just before midnight at the end of the maximum date
+     * in the minimum offset (larger negative offsets are later on the time-line).
+     * This combines {@link LocalDateTime#MAX} and {@link ZoneOffset#MIN}.
+     * This could be used by an application as a "far future" date-time.
+     */
+    public static final OffsetDateTime MAX = LocalDateTime.MAX.atOffset(ZoneOffset.MIN);
+
+    /**
+     * Comparator for two {@code OffsetDateTime} instances based solely on the instant.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} in that it
+     * only compares the underlying instant.
+     *
+     * @see #isAfter
+     * @see #isBefore
+     * @see #isEqual
+     */
+    public static final Comparator<OffsetDateTime> INSTANT_COMPARATOR = new Comparator<OffsetDateTime>() {
+        @Override
+        public int compare(OffsetDateTime datetime1, OffsetDateTime datetime2) {
+            int cmp = Long.compare(datetime1.toEpochSecond(), datetime2.toEpochSecond());
+            if (cmp == 0) {
+                cmp = Long.compare(datetime1.getTime().toNanoOfDay(), datetime2.getTime().toNanoOfDay());
+            }
+            return cmp;
+        }
+    };
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 2287754244819255394L;
+
+    /**
+     * The local date-time.
+     */
+    private final LocalDateTime dateTime;
+    /**
+     * The offset from UTC/Greenwich.
+     */
+    private final ZoneOffset offset;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains the current date-time from the system clock in the default time-zone.
+     * <p>
+     * This will query the {@link java.time.Clock#systemDefaultZone() system clock} in the default
+     * time-zone to obtain the current date-time.
+     * The offset will be calculated from the time-zone in the clock.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @return the current date-time using the system clock, not null
+     */
+    public static OffsetDateTime now() {
+        return now(Clock.systemDefaultZone());
+    }
+
+    /**
+     * Obtains the current date-time from the system clock in the specified time-zone.
+     * <p>
+     * This will query the {@link Clock#system(java.time.ZoneId) system clock} to obtain the current date-time.
+     * Specifying the time-zone avoids dependence on the default time-zone.
+     * The offset will be calculated from the specified time-zone.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @param zone  the zone ID to use, not null
+     * @return the current date-time using the system clock, not null
+     */
+    public static OffsetDateTime now(ZoneId zone) {
+        return now(Clock.system(zone));
+    }
+
+    /**
+     * Obtains the current date-time from the specified clock.
+     * <p>
+     * This will query the specified clock to obtain the current date-time.
+     * The offset will be calculated from the time-zone in the clock.
+     * <p>
+     * Using this method allows the use of an alternate clock for testing.
+     * The alternate clock may be introduced using {@link Clock dependency injection}.
+     *
+     * @param clock  the clock to use, not null
+     * @return the current date-time, not null
+     */
+    public static OffsetDateTime now(Clock clock) {
+        Objects.requireNonNull(clock, "clock");
+        final Instant now = clock.instant();  // called once
+        return ofInstant(now, clock.getZone().getRules().getOffset(now));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code OffsetDateTime} from a date, time and offset.
+     * <p>
+     * This creates an offset date-time with the specified local date, time and offset.
+     *
+     * @param date  the local date, not null
+     * @param time  the local time, not null
+     * @param offset  the zone offset, not null
+     * @return the offset date-time, not null
+     */
+    public static OffsetDateTime of(LocalDate date, LocalTime time, ZoneOffset offset) {
+        LocalDateTime dt = LocalDateTime.of(date, time);
+        return new OffsetDateTime(dt, offset);
+    }
+
+    /**
+     * Obtains an instance of {@code OffsetDateTime} from a date-time and offset.
+     * <p>
+     * This creates an offset date-time with the specified local date-time and offset.
+     *
+     * @param dateTime  the local date-time, not null
+     * @param offset  the zone offset, not null
+     * @return the offset date-time, not null
+     */
+    public static OffsetDateTime of(LocalDateTime dateTime, ZoneOffset offset) {
+        return new OffsetDateTime(dateTime, offset);
+    }
+
+    /**
+     * Obtains an instance of {@code OffsetDateTime} from a {@code ZonedDateTime}.
+     * <p>
+     * This creates an offset date-time with the same local date-time and offset as
+     * the zoned date-time. The result will have the same instant as the input.
+     *
+     * @param zonedDateTime  the zoned date-time to convert from, not null
+     * @return the offset date-time, not null
+     * @throws DateTimeException if the result exceeds the supported range
+     */
+    public static OffsetDateTime of(ZonedDateTime zonedDateTime) {
+        Objects.requireNonNull(zonedDateTime, "zonedDateTime");
+        return new OffsetDateTime(zonedDateTime.getDateTime(), zonedDateTime.getOffset());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code OffsetDateTime} from an {@code Instant} and zone ID.
+     * <p>
+     * This creates an offset date-time with the same instant as that specified.
+     * Finding the offset from UTC/Greenwich is simple as there is only one valid
+     * offset for each instant.
+     *
+     * @param instant  the instant to create the date-time from, not null
+     * @param zone  the time-zone, which may be an offset, not null
+     * @return the offset date-time, not null
+     * @throws DateTimeException if the result exceeds the supported range
+     */
+    public static OffsetDateTime ofInstant(Instant instant, ZoneId zone) {
+        Objects.requireNonNull(instant, "instant");
+        Objects.requireNonNull(zone, "zone");
+        ZoneRules rules = zone.getRules();
+        ZoneOffset offset = rules.getOffset(instant);
+        LocalDateTime ldt = LocalDateTime.ofEpochSecond(instant.getEpochSecond(), instant.getNano(), offset);
+        return new OffsetDateTime(ldt, offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code OffsetDateTime} from a temporal object.
+     * <p>
+     * A {@code TemporalAccessor} represents some form of date and time information.
+     * This factory converts the arbitrary temporal object to an instance of {@code OffsetDateTime}.
+     * <p>
+     * The conversion extracts and combines {@code LocalDateTime} and {@code ZoneOffset}.
+     * If that fails it will try to extract and combine {@code Instant} and {@code ZoneOffset}.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used in queries via method reference, {@code OffsetDateTime::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the offset date-time, not null
+     * @throws DateTimeException if unable to convert to an {@code OffsetDateTime}
+     */
+    public static OffsetDateTime from(TemporalAccessor temporal) {
+        if (temporal instanceof OffsetDateTime) {
+            return (OffsetDateTime) temporal;
+        }
+        ZoneOffset offset = ZoneOffset.from(temporal);
+        try {
+            try {
+                LocalDateTime ldt = LocalDateTime.from(temporal);
+                return OffsetDateTime.of(ldt, offset);
+            } catch (DateTimeException ignore) {
+                Instant instant = Instant.from(temporal);
+                return OffsetDateTime.ofInstant(instant, offset);
+            }
+        } catch (DateTimeException ex) {
+            throw new DateTimeException("Unable to obtain OffsetDateTime from TemporalAccessor: " + temporal.getClass(), ex);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code OffsetDateTime} from a text string
+     * such as {@code 2007-12-03T10:15:30+01:00}.
+     * <p>
+     * The string must represent a valid date-time and is parsed using
+     * {@link java.time.format.DateTimeFormatters#isoOffsetDateTime()}.
+     *
+     * @param text  the text to parse such as "2007-12-03T10:15:30+01:00", not null
+     * @return the parsed offset date-time, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static OffsetDateTime parse(CharSequence text) {
+        return parse(text, DateTimeFormatters.isoOffsetDateTime());
+    }
+
+    /**
+     * Obtains an instance of {@code OffsetDateTime} from a text string using a specific formatter.
+     * <p>
+     * The text is parsed using the formatter, returning a date-time.
+     *
+     * @param text  the text to parse, not null
+     * @param formatter  the formatter to use, not null
+     * @return the parsed offset date-time, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static OffsetDateTime parse(CharSequence text, DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.parse(text, OffsetDateTime::from);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructor.
+     *
+     * @param dateTime  the local date-time, not null
+     * @param offset  the zone offset, not null
+     */
+    private OffsetDateTime(LocalDateTime dateTime, ZoneOffset offset) {
+        this.dateTime = Objects.requireNonNull(dateTime, "dateTime");
+        this.offset = Objects.requireNonNull(offset, "offset");
+    }
+
+    /**
+     * Returns a new date-time based on this one, returning {@code this} where possible.
+     *
+     * @param dateTime  the date-time to create with, not null
+     * @param offset  the zone offset to create with, not null
+     */
+    private OffsetDateTime with(LocalDateTime dateTime, ZoneOffset offset) {
+        if (this.dateTime == dateTime && this.offset.equals(offset)) {
+            return this;
+        }
+        return new OffsetDateTime(dateTime, offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if this date-time can be queried for the specified field.
+     * If false, then calling the {@link #range(TemporalField) range} and
+     * {@link #get(TemporalField) get} methods will throw an exception.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The supported fields are:
+     * <ul>
+     * <li>{@code NANO_OF_SECOND}
+     * <li>{@code NANO_OF_DAY}
+     * <li>{@code MICRO_OF_SECOND}
+     * <li>{@code MICRO_OF_DAY}
+     * <li>{@code MILLI_OF_SECOND}
+     * <li>{@code MILLI_OF_DAY}
+     * <li>{@code SECOND_OF_MINUTE}
+     * <li>{@code SECOND_OF_DAY}
+     * <li>{@code MINUTE_OF_HOUR}
+     * <li>{@code MINUTE_OF_DAY}
+     * <li>{@code HOUR_OF_AMPM}
+     * <li>{@code CLOCK_HOUR_OF_AMPM}
+     * <li>{@code HOUR_OF_DAY}
+     * <li>{@code CLOCK_HOUR_OF_DAY}
+     * <li>{@code AMPM_OF_DAY}
+     * <li>{@code DAY_OF_WEEK}
+     * <li>{@code ALIGNED_DAY_OF_WEEK_IN_MONTH}
+     * <li>{@code ALIGNED_DAY_OF_WEEK_IN_YEAR}
+     * <li>{@code DAY_OF_MONTH}
+     * <li>{@code DAY_OF_YEAR}
+     * <li>{@code EPOCH_DAY}
+     * <li>{@code ALIGNED_WEEK_OF_MONTH}
+     * <li>{@code ALIGNED_WEEK_OF_YEAR}
+     * <li>{@code MONTH_OF_YEAR}
+     * <li>{@code EPOCH_MONTH}
+     * <li>{@code YEAR_OF_ERA}
+     * <li>{@code YEAR}
+     * <li>{@code ERA}
+     * <li>{@code INSTANT_SECONDS}
+     * <li>{@code OFFSET_SECONDS}
+     * </ul>
+     * All other {@code ChronoField} instances will return false.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the field is supported is determined by the field.
+     *
+     * @param field  the field to check, null returns false
+     * @return true if the field is supported on this date-time, false if not
+     */
+    @Override
+    public boolean isSupported(TemporalField field) {
+        return field instanceof ChronoField || (field != null && field.doIsSupported(this));
+    }
+
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * The range object expresses the minimum and maximum valid values for a field.
+     * This date-time is used to enhance the accuracy of the returned range.
+     * If it is not possible to return the range, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * 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}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the range can be obtained is determined by the field.
+     *
+     * @param field  the field to query the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     */
+    @Override
+    public ValueRange range(TemporalField field) {
+        if (field instanceof ChronoField) {
+            if (field == INSTANT_SECONDS || field == OFFSET_SECONDS) {
+                return field.range();
+            }
+            return dateTime.range(field);
+        }
+        return field.doRange(this);
+    }
+
+    /**
+     * Gets the value of the specified field from this date-time as an {@code int}.
+     * <p>
+     * This queries this date-time for the value for the specified field.
+     * The returned value will always be within the valid range of values for the field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this date-time, except {@code NANO_OF_DAY}, {@code MICRO_OF_DAY},
+     * {@code EPOCH_DAY}, {@code EPOCH_MONTH} and {@code INSTANT_SECONDS} which are too
+     * large to fit in an {@code int} and throw a {@code DateTimeException}.
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public int get(TemporalField field) {
+        if (field instanceof ChronoField) {
+            switch ((ChronoField) field) {
+                case INSTANT_SECONDS: throw new DateTimeException("Field too large for an int: " + field);
+                case OFFSET_SECONDS: return getOffset().getTotalSeconds();
+            }
+            return dateTime.get(field);
+        }
+        return Temporal.super.get(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this date-time as a {@code long}.
+     * <p>
+     * This queries this date-time for the value for the specified field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this date-time.
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long getLong(TemporalField field) {
+        if (field instanceof ChronoField) {
+            switch ((ChronoField) field) {
+                case INSTANT_SECONDS: return toEpochSecond();
+                case OFFSET_SECONDS: return getOffset().getTotalSeconds();
+            }
+            return dateTime.getLong(field);
+        }
+        return field.doGet(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the zone offset, such as '+01:00'.
+     * <p>
+     * This is the offset of the local date-time from UTC/Greenwich.
+     *
+     * @return the zone offset, not null
+     */
+    public ZoneOffset getOffset() {
+        return offset;
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified offset ensuring
+     * that the result has the same local date-time.
+     * <p>
+     * This method returns an object with the same {@code LocalDateTime} and the specified {@code ZoneOffset}.
+     * No calculation is needed or performed.
+     * For example, if this time represents {@code 2007-12-03T10:30+02:00} and the offset specified is
+     * {@code +03:00}, then this method will return {@code 2007-12-03T10:30+03:00}.
+     * <p>
+     * To take into account the difference between the offsets, and adjust the time fields,
+     * use {@link #withOffsetSameInstant}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param offset  the zone offset to change to, not null
+     * @return an {@code OffsetDateTime} based on this date-time with the requested offset, not null
+     */
+    public OffsetDateTime withOffsetSameLocal(ZoneOffset offset) {
+        return with(dateTime, offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified offset ensuring
+     * that the result is at the same instant.
+     * <p>
+     * This method returns an object with the specified {@code ZoneOffset} and a {@code LocalDateTime}
+     * adjusted by the difference between the two offsets.
+     * This will result in the old and new objects representing the same instant.
+     * This is useful for finding the local time in a different offset.
+     * For example, if this time represents {@code 2007-12-03T10:30+02:00} and the offset specified is
+     * {@code +03:00}, then this method will return {@code 2007-12-03T11:30+03:00}.
+     * <p>
+     * To change the offset without adjusting the local time use {@link #withOffsetSameLocal}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param offset  the zone offset to change to, not null
+     * @return an {@code OffsetDateTime} based on this date-time with the requested offset, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime withOffsetSameInstant(ZoneOffset offset) {
+        if (offset.equals(this.offset)) {
+            return this;
+        }
+        int difference = offset.getTotalSeconds() - this.offset.getTotalSeconds();
+        LocalDateTime adjusted = dateTime.plusSeconds(difference);
+        return new OffsetDateTime(adjusted, offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the {@code LocalDateTime} part of this offset date-time.
+     * <p>
+     * This returns a {@code LocalDateTime} with the same year, month, day and time
+     * as this date-time.
+     *
+     * @return the local date-time part of this date-time, not null
+     */
+    public LocalDateTime getDateTime() {
+        return dateTime;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the {@code LocalDate} part of this date-time.
+     * <p>
+     * This returns a {@code LocalDate} with the same year, month and day
+     * as this date-time.
+     *
+     * @return the date part of this date-time, not null
+     */
+    public LocalDate getDate() {
+        return dateTime.getDate();
+    }
+
+    /**
+     * Gets the year field.
+     * <p>
+     * This method returns the primitive {@code int} value for the year.
+     * <p>
+     * The year returned by this method is proleptic as per {@code get(YEAR)}.
+     * To obtain the year-of-era, use {@code get(YEAR_OF_ERA}.
+     *
+     * @return the year, from MIN_YEAR to MAX_YEAR
+     */
+    public int getYear() {
+        return dateTime.getYear();
+    }
+
+    /**
+     * Gets the month-of-year field from 1 to 12.
+     * <p>
+     * This method returns the month as an {@code int} from 1 to 12.
+     * Application code is frequently clearer if the enum {@link Month}
+     * is used by calling {@link #getMonth()}.
+     *
+     * @return the month-of-year, from 1 to 12
+     * @see #getMonth()
+     */
+    public int getMonthValue() {
+        return dateTime.getMonthValue();
+    }
+
+    /**
+     * Gets the month-of-year field using the {@code Month} enum.
+     * <p>
+     * This method returns the enum {@link Month} for the month.
+     * This avoids confusion as to what {@code int} values mean.
+     * If you need access to the primitive {@code int} value then the enum
+     * provides the {@link Month#getValue() int value}.
+     *
+     * @return the month-of-year, not null
+     * @see #getMonthValue()
+     */
+    public Month getMonth() {
+        return dateTime.getMonth();
+    }
+
+    /**
+     * Gets the day-of-month field.
+     * <p>
+     * This method returns the primitive {@code int} value for the day-of-month.
+     *
+     * @return the day-of-month, from 1 to 31
+     */
+    public int getDayOfMonth() {
+        return dateTime.getDayOfMonth();
+    }
+
+    /**
+     * Gets the day-of-year field.
+     * <p>
+     * This method returns the primitive {@code int} value for the day-of-year.
+     *
+     * @return the day-of-year, from 1 to 365, or 366 in a leap year
+     */
+    public int getDayOfYear() {
+        return dateTime.getDayOfYear();
+    }
+
+    /**
+     * Gets the day-of-week field, which is an enum {@code DayOfWeek}.
+     * <p>
+     * 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}.
+     * <p>
+     * Additional information can be obtained from the {@code DayOfWeek}.
+     * This includes textual names of the values.
+     *
+     * @return the day-of-week, not null
+     */
+    public DayOfWeek getDayOfWeek() {
+        return dateTime.getDayOfWeek();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the {@code LocalTime} part of this date-time.
+     * <p>
+     * This returns a {@code LocalTime} with the same hour, minute, second and
+     * nanosecond as this date-time.
+     *
+     * @return the time part of this date-time, not null
+     */
+    public LocalTime getTime() {
+        return dateTime.getTime();
+    }
+
+    /**
+     * Gets the hour-of-day field.
+     *
+     * @return the hour-of-day, from 0 to 23
+     */
+    public int getHour() {
+        return dateTime.getHour();
+    }
+
+    /**
+     * Gets the minute-of-hour field.
+     *
+     * @return the minute-of-hour, from 0 to 59
+     */
+    public int getMinute() {
+        return dateTime.getMinute();
+    }
+
+    /**
+     * Gets the second-of-minute field.
+     *
+     * @return the second-of-minute, from 0 to 59
+     */
+    public int getSecond() {
+        return dateTime.getSecond();
+    }
+
+    /**
+     * Gets the nano-of-second field.
+     *
+     * @return the nano-of-second, from 0 to 999,999,999
+     */
+    public int getNano() {
+        return dateTime.getNano();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns an adjusted copy of this date-time.
+     * <p>
+     * This returns a new {@code OffsetDateTime}, based on this one, with the date-time adjusted.
+     * The adjustment takes place using the specified adjuster strategy object.
+     * Read the documentation of the adjuster to understand what adjustment will be made.
+     * <p>
+     * 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.
+     * <p>
+     * For example this code returns a date on the last day of July:
+     * <pre>
+     *  import static java.time.Month.*;
+     *  import static java.time.temporal.Adjusters.*;
+     *
+     *  result = offsetDateTime.with(JULY).with(lastDayOfMonth());
+     * </pre>
+     * <p>
+     * The classes {@link LocalDate}, {@link LocalTime} and {@link ZoneOffset} implement
+     * {@code TemporalAdjuster}, thus this method can be used to change the date, time or offset:
+     * <pre>
+     *  result = offsetDateTime.with(date);
+     *  result = offsetDateTime.with(time);
+     *  result = offsetDateTime.with(offset);
+     * </pre>
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param adjuster the adjuster to use, not null
+     * @return an {@code OffsetDateTime} based on {@code this} with the adjustment made, not null
+     * @throws DateTimeException if the adjustment cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public OffsetDateTime with(TemporalAdjuster adjuster) {
+        // optimizations
+        if (adjuster instanceof LocalDate || adjuster instanceof LocalTime || adjuster instanceof LocalDateTime) {
+            return with(dateTime.with(adjuster), offset);
+        } else if (adjuster instanceof Instant) {
+            return ofInstant((Instant) adjuster, offset);
+        } else if (adjuster instanceof ZoneOffset) {
+            return with(dateTime, (ZoneOffset) adjuster);
+        } else if (adjuster instanceof OffsetDateTime) {
+            return (OffsetDateTime) adjuster;
+        }
+        return (OffsetDateTime) adjuster.adjustInto(this);
+    }
+
+    /**
+     * Returns a copy of this date-time with the specified field set to a new value.
+     * <p>
+     * This returns a new {@code OffsetDateTime}, based on this one, with the value
+     * for the specified field changed.
+     * This can be used to change any supported field, such as the year, month or day-of-month.
+     * If it is not possible to set the value, because the field is not supported or for
+     * some other reason, an exception is thrown.
+     * <p>
+     * In some cases, changing the specified field can cause the resulting date-time to become invalid,
+     * such as changing the month from 31st January to February would make the day-of-month invalid.
+     * In cases like this, the field is responsible for resolving the date. Typically it will choose
+     * the previous valid date, which would be the last valid day of February in this example.
+     * <p>
+     * If the field is a {@link ChronoField} then the adjustment is implemented here.
+     * <p>
+     * The {@code INSTANT_SECONDS} field will return a date-time with the specified instant.
+     * The offset and nano-of-second are unchanged.
+     * If the new instant value is outside the valid range then a {@code DateTimeException} will be thrown.
+     * <p>
+     * The {@code OFFSET_SECONDS} field will return a date-time with the specified offset.
+     * The local date-time is unaltered. If the new offset value is outside the valid range
+     * then a {@code DateTimeException} will be thrown.
+     * <p>
+     * The other {@link #isSupported(TemporalField) supported fields} will behave as per
+     * the matching method on {@link LocalDateTime#with(TemporalField, long) LocalDateTime}.
+     * In this case, the offset is not part of the calculation and will be unchanged.
+     * <p>
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param field  the field to set in the result, not null
+     * @param newValue  the new value of the field in the result
+     * @return an {@code OffsetDateTime} based on {@code this} with the specified field set, not null
+     * @throws DateTimeException if the field cannot be set
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public OffsetDateTime with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            switch (f) {
+                case INSTANT_SECONDS: return ofInstant(Instant.ofEpochSecond(newValue, getNano()), offset);
+                case OFFSET_SECONDS: {
+                    return with(dateTime, ZoneOffset.ofTotalSeconds(f.checkValidIntValue(newValue)));
+                }
+            }
+            return with(dateTime.with(field, newValue), offset);
+        }
+        return field.doWith(this, newValue);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the year altered.
+     * The offset does not affect the calculation and will be the same in the result.
+     * If the day-of-month is invalid for the year, it will be changed to the last valid day of the month.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param year  the year to set in the result, from MIN_YEAR to MAX_YEAR
+     * @return an {@code OffsetDateTime} based on this date-time with the requested year, not null
+     * @throws DateTimeException if the year value is invalid
+     */
+    public OffsetDateTime withYear(int year) {
+        return with(dateTime.withYear(year), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the month-of-year altered.
+     * The offset does not affect the calculation and will be the same in the result.
+     * If the day-of-month is invalid for the year, it will be changed to the last valid day of the month.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param month  the month-of-year to set in the result, from 1 (January) to 12 (December)
+     * @return an {@code OffsetDateTime} based on this date-time with the requested month, not null
+     * @throws DateTimeException if the month-of-year value is invalid
+     */
+    public OffsetDateTime withMonth(int month) {
+        return with(dateTime.withMonth(month), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the day-of-month altered.
+     * If the resulting {@code OffsetDateTime} is invalid, an exception is thrown.
+     * The offset does not affect the calculation and will be the same in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param dayOfMonth  the day-of-month to set in the result, from 1 to 28-31
+     * @return an {@code OffsetDateTime} based on this date-time with the requested day, not null
+     * @throws DateTimeException if the day-of-month value is invalid
+     * @throws DateTimeException if the day-of-month is invalid for the month-year
+     */
+    public OffsetDateTime withDayOfMonth(int dayOfMonth) {
+        return with(dateTime.withDayOfMonth(dayOfMonth), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the day-of-year altered.
+     * If the resulting {@code OffsetDateTime} is invalid, an exception is thrown.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param dayOfYear  the day-of-year to set in the result, from 1 to 365-366
+     * @return an {@code OffsetDateTime} based on this date with the requested day, not null
+     * @throws DateTimeException if the day-of-year value is invalid
+     * @throws DateTimeException if the day-of-year is invalid for the year
+     */
+    public OffsetDateTime withDayOfYear(int dayOfYear) {
+        return with(dateTime.withDayOfYear(dayOfYear), offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the hour-of-day value altered.
+     * <p>
+     * The offset does not affect the calculation and will be the same in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hour  the hour-of-day to set in the result, from 0 to 23
+     * @return an {@code OffsetDateTime} based on this date-time with the requested hour, not null
+     * @throws DateTimeException if the hour value is invalid
+     */
+    public OffsetDateTime withHour(int hour) {
+        return with(dateTime.withHour(hour), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the minute-of-hour value altered.
+     * <p>
+     * The offset does not affect the calculation and will be the same in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minute  the minute-of-hour to set in the result, from 0 to 59
+     * @return an {@code OffsetDateTime} based on this date-time with the requested minute, not null
+     * @throws DateTimeException if the minute value is invalid
+     */
+    public OffsetDateTime withMinute(int minute) {
+        return with(dateTime.withMinute(minute), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the second-of-minute value altered.
+     * <p>
+     * The offset does not affect the calculation and will be the same in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param second  the second-of-minute to set in the result, from 0 to 59
+     * @return an {@code OffsetDateTime} based on this date-time with the requested second, not null
+     * @throws DateTimeException if the second value is invalid
+     */
+    public OffsetDateTime withSecond(int second) {
+        return with(dateTime.withSecond(second), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the nano-of-second value altered.
+     * <p>
+     * The offset does not affect the calculation and will be the same in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanoOfSecond  the nano-of-second to set in the result, from 0 to 999,999,999
+     * @return an {@code OffsetDateTime} based on this date-time with the requested nanosecond, not null
+     * @throws DateTimeException if the nanos value is invalid
+     */
+    public OffsetDateTime withNano(int nanoOfSecond) {
+        return with(dateTime.withNano(nanoOfSecond), offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the time truncated.
+     * <p>
+     * Truncation returns a copy of the original date-time with fields
+     * smaller than the specified unit set to zero.
+     * For example, truncating with the {@link ChronoUnit#MINUTES minutes} unit
+     * will set the second-of-minute and nano-of-second field to zero.
+     * <p>
+     * Not all units are accepted. The {@link ChronoUnit#DAYS days} unit and time
+     * units with an exact duration can be used, other units throw an exception.
+     * <p>
+     * The offset does not affect the calculation and will be the same in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param unit  the unit to truncate to, not null
+     * @return an {@code OffsetDateTime} based on this date-time with the time truncated, not null
+     * @throws DateTimeException if unable to truncate
+     */
+    public OffsetDateTime truncatedTo(TemporalUnit unit) {
+        return with(dateTime.truncatedTo(unit), offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this date-time with the specified period added.
+     * <p>
+     * This method returns a new date-time based on this time with the specified period added.
+     * The adder is typically {@link java.time.Period} but may be any other type implementing
+     * the {@link TemporalAdder} interface.
+     * The calculation is delegated to the specified adjuster, which typically calls
+     * back to {@link #plus(long, TemporalUnit)}.
+     * The offset is not part of the calculation and will be unchanged in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param adder  the adder to use, not null
+     * @return an {@code OffsetDateTime} based on this date-time with the addition made, not null
+     * @throws DateTimeException if the addition cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public OffsetDateTime plus(TemporalAdder adder) {
+        return (OffsetDateTime) adder.addTo(this);
+    }
+
+    /**
+     * Returns a copy of this date-time with the specified period added.
+     * <p>
+     * This method returns a new date-time based on this date-time with the specified period added.
+     * This can be used to add any period that is defined by a unit, for example to add years, months or days.
+     * The unit is responsible for the details of the calculation, including the resolution
+     * of any edge cases in the calculation.
+     * The offset is not part of the calculation and will be unchanged in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToAdd  the amount of the unit to add to the result, may be negative
+     * @param unit  the unit of the period to add, not null
+     * @return an {@code OffsetDateTime} based on this date-time with the specified period added, not null
+     * @throws DateTimeException if the unit cannot be added to this type
+     */
+    @Override
+    public OffsetDateTime plus(long amountToAdd, TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            return with(dateTime.plus(amountToAdd, unit), offset);
+        }
+        return unit.doPlus(this, amountToAdd);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified period in years added.
+     * <p>
+     * This method adds the specified amount to the years field in three steps:
+     * <ol>
+     * <li>Add the input years to the year field</li>
+     * <li>Check if the resulting date would be invalid</li>
+     * <li>Adjust the day-of-month to the last valid day if necessary</li>
+     * </ol>
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param years  the years to add, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the years added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime plusYears(long years) {
+        return with(dateTime.plusYears(years), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified period in months added.
+     * <p>
+     * This method adds the specified amount to the months field in three steps:
+     * <ol>
+     * <li>Add the input months to the month-of-year field</li>
+     * <li>Check if the resulting date would be invalid</li>
+     * <li>Adjust the day-of-month to the last valid day if necessary</li>
+     * </ol>
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param months  the months to add, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the months added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime plusMonths(long months) {
+        return with(dateTime.plusMonths(months), offset);
+    }
+
+    /**
+     * Returns a copy of this OffsetDateTime with the specified period in weeks added.
+     * <p>
+     * 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.
+     * <p>
+     * For example, 2008-12-31 plus one week would result in the 2009-01-07.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param weeks  the weeks to add, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the weeks added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime plusWeeks(long weeks) {
+        return with(dateTime.plusWeeks(weeks), offset);
+    }
+
+    /**
+     * Returns a copy of this OffsetDateTime with the specified period in days added.
+     * <p>
+     * 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.
+     * <p>
+     * For example, 2008-12-31 plus one day would result in the 2009-01-01.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param days  the days to add, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the days added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime plusDays(long days) {
+        return with(dateTime.plusDays(days), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified period in hours added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hours  the hours to add, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the hours added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime plusHours(long hours) {
+        return with(dateTime.plusHours(hours), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified period in minutes added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minutes  the minutes to add, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the minutes added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime plusMinutes(long minutes) {
+        return with(dateTime.plusMinutes(minutes), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified period in seconds added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param seconds  the seconds to add, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the seconds added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime plusSeconds(long seconds) {
+        return with(dateTime.plusSeconds(seconds), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified period in nanoseconds added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanos  the nanos to add, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the nanoseconds added, not null
+     * @throws DateTimeException if the unit cannot be added to this type
+     */
+    public OffsetDateTime plusNanos(long nanos) {
+        return with(dateTime.plusNanos(nanos), offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this date-time with the specified period subtracted.
+     * <p>
+     * This method returns a new date-time based on this time with the specified period subtracted.
+     * The subtractor is typically {@link java.time.Period} but may be any other type implementing
+     * the {@link TemporalSubtractor} interface.
+     * The calculation is delegated to the specified adjuster, which typically calls
+     * back to {@link #minus(long, TemporalUnit)}.
+     * The offset is not part of the calculation and will be unchanged in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param subtractor  the subtractor to use, not null
+     * @return an {@code OffsetDateTime} based on this date-time with the subtraction made, not null
+     * @throws DateTimeException if the subtraction cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public OffsetDateTime minus(TemporalSubtractor subtractor) {
+        return (OffsetDateTime) subtractor.subtractFrom(this);
+    }
+
+    /**
+     * Returns a copy of this date-time with the specified period subtracted.
+     * <p>
+     * This method returns a new date-time based on this date-time with the specified period subtracted.
+     * This can be used to subtract any period that is defined by a unit, for example to subtract years, months or days.
+     * The unit is responsible for the details of the calculation, including the resolution
+     * of any edge cases in the calculation.
+     * The offset is not part of the calculation and will be unchanged in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToSubtract  the amount of the unit to subtract from the result, may be negative
+     * @param unit  the unit of the period to subtract, not null
+     * @return an {@code OffsetDateTime} based on this date-time with the specified period subtracted, not null
+     */
+    @Override
+    public OffsetDateTime minus(long amountToSubtract, TemporalUnit unit) {
+        return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified period in years subtracted.
+     * <p>
+     * This method subtracts the specified amount from the years field in three steps:
+     * <ol>
+     * <li>Subtract the input years to the year field</li>
+     * <li>Check if the resulting date would be invalid</li>
+     * <li>Adjust the day-of-month to the last valid day if necessary</li>
+     * </ol>
+     * <p>
+     * For example, 2008-02-29 (leap year) minus one year would result in the
+     * invalid date 2009-02-29 (standard year). Instead of returning an invalid
+     * result, the last valid day of the month, 2009-02-28, is selected instead.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param years  the years to subtract, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the years subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime minusYears(long years) {
+        return (years == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-years));
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified period in months subtracted.
+     * <p>
+     * This method subtracts the specified amount from the months field in three steps:
+     * <ol>
+     * <li>Subtract the input months to the month-of-year field</li>
+     * <li>Check if the resulting date would be invalid</li>
+     * <li>Adjust the day-of-month to the last valid day if necessary</li>
+     * </ol>
+     * <p>
+     * For example, 2007-03-31 minus one month would result in the invalid date
+     * 2007-04-31. Instead of returning an invalid result, the last valid day
+     * of the month, 2007-04-30, is selected instead.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param months  the months to subtract, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the months subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime minusMonths(long months) {
+        return (months == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-months));
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified period in weeks subtracted.
+     * <p>
+     * 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.
+     * <p>
+     * For example, 2008-12-31 minus one week would result in the 2009-01-07.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param weeks  the weeks to subtract, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the weeks subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime minusWeeks(long weeks) {
+        return (weeks == Long.MIN_VALUE ? plusWeeks(Long.MAX_VALUE).plusWeeks(1) : plusWeeks(-weeks));
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified period in days subtracted.
+     * <p>
+     * This method subtracts the specified amount from the days field incrementing the
+     * month and year fields as necessary to ensure the result remains valid.
+     * The result is only invalid if the maximum/minimum year is exceeded.
+     * <p>
+     * For example, 2008-12-31 minus one day would result in the 2009-01-01.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param days  the days to subtract, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the days subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime minusDays(long days) {
+        return (days == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-days));
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified period in hours subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hours  the hours to subtract, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the hours subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime minusHours(long hours) {
+        return (hours == Long.MIN_VALUE ? plusHours(Long.MAX_VALUE).plusHours(1) : plusHours(-hours));
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified period in minutes subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minutes  the minutes to subtract, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the minutes subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime minusMinutes(long minutes) {
+        return (minutes == Long.MIN_VALUE ? plusMinutes(Long.MAX_VALUE).plusMinutes(1) : plusMinutes(-minutes));
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified period in seconds subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param seconds  the seconds to subtract, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the seconds subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime minusSeconds(long seconds) {
+        return (seconds == Long.MIN_VALUE ? plusSeconds(Long.MAX_VALUE).plusSeconds(1) : plusSeconds(-seconds));
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified period in nanoseconds subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanos  the nanos to subtract, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the nanoseconds subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime minusNanos(long nanos) {
+        return (nanos == Long.MIN_VALUE ? plusNanos(Long.MAX_VALUE).plusNanos(1) : plusNanos(-nanos));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this date-time using the specified query.
+     * <p>
+     * This queries this date-time using the specified query strategy object.
+     * The {@code TemporalQuery} object defines the logic to be used to
+     * obtain the result. Read the documentation of the query to understand
+     * what the result of this method will be.
+     * <p>
+     * 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 <R> 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> R query(TemporalQuery<R> query) {
+        if (query == Queries.chrono()) {
+            return (R) getDate().getChrono();
+        } else if (query == Queries.precision()) {
+            return (R) NANOS;
+        } else if (query == Queries.offset() || query == Queries.zone()) {
+            return (R) getOffset();
+        }
+        return Temporal.super.query(query);
+    }
+
+    /**
+     * Adjusts the specified temporal object to have the same offset, date
+     * and time as this object.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with the offset, date and time changed to be the same as this.
+     * <p>
+     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+     * three times, passing {@link ChronoField#OFFSET_SECONDS},
+     * {@link ChronoField#EPOCH_DAY} and {@link ChronoField#NANO_OF_DAY} as the fields.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisOffsetDateTime.adjustInto(temporal);
+     *   temporal = temporal.with(thisOffsetDateTime);
+     * </pre>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param temporal  the target object to be adjusted, not null
+     * @return the adjusted object, not null
+     * @throws DateTimeException if unable to make the adjustment
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Temporal adjustInto(Temporal temporal) {
+        return temporal
+                .with(OFFSET_SECONDS, getOffset().getTotalSeconds())
+                .with(EPOCH_DAY, getDate().toEpochDay())
+                .with(NANO_OF_DAY, getTime().toNanoOfDay());
+    }
+
+    /**
+     * Calculates the period between this date-time and another date-time in
+     * terms of the specified unit.
+     * <p>
+     * This calculates the period between two date-times in terms of a single unit.
+     * The start and end points are {@code this} and the specified date-time.
+     * The result will be negative if the end is before the start.
+     * For example, the period in days between two date-times can be calculated
+     * using {@code startDateTime.periodUntil(endDateTime, DAYS)}.
+     * <p>
+     * The {@code Temporal} passed to this method must be an {@code OffsetDateTime}.
+     * If the offset differs between the two date-times, the specified
+     * end date-time is normalized to have the same offset as this date-time.
+     * <p>
+     * The calculation returns a whole number, representing the number of
+     * complete units between the two date-times.
+     * For example, the period in months between 2012-06-15T00:00Z and 2012-08-14T23:59Z
+     * will only be one month as it is one minute short of two months.
+     * <p>
+     * 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:
+     * <pre>
+     *   long period = start.periodUntil(end, MONTHS);   // this method
+     *   dateTime.plus(MONTHS.between(start, end));      // use in plus/minus
+     * </pre>
+     * <p>
+     * The calculation is implemented in this method for {@link ChronoUnit}.
+     * The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS},
+     * {@code MINUTES}, {@code HOURS} and {@code HALF_DAYS}, {@code DAYS},
+     * {@code WEEKS}, {@code MONTHS}, {@code YEARS}, {@code DECADES},
+     * {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS} are supported.
+     * Other {@code ChronoUnit} values will throw an exception.
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param endDateTime  the end date-time, which must be an {@code OffsetDateTime}, not null
+     * @param unit  the unit to measure the period in, not null
+     * @return the amount of the period between this date-time and the end date-time
+     * @throws DateTimeException if the period cannot be calculated
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long periodUntil(Temporal endDateTime, TemporalUnit unit) {
+        if (endDateTime instanceof OffsetDateTime == false) {
+            Objects.requireNonNull(endDateTime, "endDateTime");
+            throw new DateTimeException("Unable to calculate period between objects of two different types");
+        }
+        if (unit instanceof ChronoUnit) {
+            OffsetDateTime end = (OffsetDateTime) endDateTime;
+            end = end.withOffsetSameInstant(offset);
+            return dateTime.periodUntil(end.dateTime, unit);
+        }
+        return unit.between(this, endDateTime).getAmount();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a zoned date-time formed from the instant represented by this
+     * date-time and the specified zone ID.
+     * <p>
+     * This conversion will ignore the visible local date-time and use the underlying instant instead.
+     * This avoids any problems with local time-line gaps or overlaps.
+     * The result might have different values for fields such as hour, minute an even day.
+     * <p>
+     * To attempt to retain the values of the fields, use {@link #atZoneSimilarLocal(ZoneId)}.
+     * To use the offset as the zone ID, use {@link #toZonedDateTime()}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param zone  the time-zone to use, not null
+     * @return the zoned date-time formed from this date-time, not null
+     */
+    public ZonedDateTime atZoneSameInstant(ZoneId zone) {
+        return ZonedDateTime.ofInstant(dateTime, offset, zone);
+    }
+
+    /**
+     * Returns a zoned date-time formed from this date-time and the specified zone ID.
+     * <p>
+     * Time-zone rules, such as daylight savings, mean that not every time on the
+     * local time-line exists. If the local date-time is in a gap or overlap according to
+     * the rules then a resolver is used to determine the resultant local time and offset.
+     * This method uses {@link ZonedDateTime#ofLocal(LocalDateTime, ZoneId, ZoneOffset)}
+     * to retain the offset from this instance if possible.
+     * <p>
+     * Finer control over gaps and overlaps is available in two ways.
+     * If you simply want to use the later offset at overlaps then call
+     * {@link ZonedDateTime#withLaterOffsetAtOverlap()} immediately after this method.
+     * <p>
+     * To create a zoned date-time at the same instant irrespective of the local time-line,
+     * use {@link #atZoneSameInstant(ZoneId)}.
+     * To use the offset as the zone ID, use {@link #toZonedDateTime()}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param zone  the time-zone to use, not null
+     * @return the zoned date-time formed from this date and the earliest valid time for the zone, not null
+     */
+    public ZonedDateTime atZoneSimilarLocal(ZoneId zone) {
+        return ZonedDateTime.ofLocal(dateTime, zone, offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Converts this date-time to an {@code OffsetDate}.
+     * <p>
+     * This returns an offset date with the same local date and offset.
+     *
+     * @return an OffsetDate representing the date and offset, not null
+     */
+    public OffsetDate toOffsetDate() {
+        return OffsetDate.of(dateTime.getDate(), offset);
+    }
+
+    /**
+     * Converts this date-time to an {@code OffsetTime}.
+     * <p>
+     * This returns an offset time with the same local time and offset.
+     *
+     * @return an OffsetTime representing the time and offset, not null
+     */
+    public OffsetTime toOffsetTime() {
+        return OffsetTime.of(dateTime.getTime(), offset);
+    }
+
+    /**
+     * Converts this date-time to a {@code ZonedDateTime} using the offset as the zone ID.
+     * <p>
+     * This creates the simplest possible {@code ZonedDateTime} using the offset
+     * as the zone ID.
+     * <p>
+     * To control the time-zone used, see {@link #atZoneSameInstant(ZoneId)} and
+     * {@link #atZoneSimilarLocal(ZoneId)}.
+     *
+     * @return a zoned date-time representing the same local date-time and offset, not null
+     */
+    public ZonedDateTime toZonedDateTime() {
+        return ZonedDateTime.of(dateTime, offset);
+    }
+
+    /**
+     * Converts this date-time to an {@code Instant}.
+     *
+     * @return an {@code Instant} representing the same instant, not null
+     */
+    public Instant toInstant() {
+        return dateTime.toInstant(offset);
+    }
+
+    /**
+     * Converts this date-time to the number of seconds from the epoch of 1970-01-01T00:00:00Z.
+     * <p>
+     * This allows this date-time to be converted to a value of the
+     * {@link ChronoField#INSTANT_SECONDS epoch-seconds} field. This is primarily
+     * intended for low-level conversions rather than general application usage.
+     *
+     * @return the number of seconds from the epoch of 1970-01-01T00:00:00Z
+     */
+    public long toEpochSecond() {
+        return dateTime.toEpochSecond(offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this {@code OffsetDateTime} to another date-time.
+     * <p>
+     * The comparison is based on the instant then on the local date-time.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     * <p>
+     * For example, the following is the comparator order:
+     * <ol>
+     * <li>{@code 2008-12-03T10:30+01:00}</li>
+     * <li>{@code 2008-12-03T11:00+01:00}</li>
+     * <li>{@code 2008-12-03T12:00+02:00}</li>
+     * <li>{@code 2008-12-03T11:30+01:00}</li>
+     * <li>{@code 2008-12-03T12:00+01:00}</li>
+     * <li>{@code 2008-12-03T12:30+01:00}</li>
+     * </ol>
+     * Values #2 and #3 represent the same instant on the time-line.
+     * When two values represent the same instant, the local date-time is compared
+     * to distinguish them. This step is needed to make the ordering
+     * consistent with {@code equals()}.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     */
+    @Override
+    public int compareTo(OffsetDateTime other) {
+        if (getOffset().equals(other.getOffset())) {
+            return getDateTime().compareTo(other.getDateTime());
+        }
+        int cmp = Long.compare(toEpochSecond(), other.toEpochSecond());
+        if (cmp == 0) {
+            cmp = getTime().getNano() - other.getTime().getNano();
+            if (cmp == 0) {
+                cmp = getDateTime().compareTo(other.getDateTime());
+            }
+        }
+        return cmp;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the instant of this date-time is after that of the specified date-time.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} and {@link #equals} in that it
+     * only compares the instant of the date-time. This is equivalent to using
+     * {@code dateTime1.toInstant().isAfter(dateTime2.toInstant());}.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return true if this is after the instant of the specified date-time
+     */
+    public boolean isAfter(OffsetDateTime other) {
+        long thisEpochSec = toEpochSecond();
+        long otherEpochSec = other.toEpochSecond();
+        return thisEpochSec > otherEpochSec ||
+            (thisEpochSec == otherEpochSec && getTime().getNano() > other.getTime().getNano());
+    }
+
+    /**
+     * Checks if the instant of this date-time is before that of the specified date-time.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} in that it
+     * only compares the instant of the date-time. This is equivalent to using
+     * {@code dateTime1.toInstant().isBefore(dateTime2.toInstant());}.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return true if this is before the instant of the specified date-time
+     */
+    public boolean isBefore(OffsetDateTime other) {
+        long thisEpochSec = toEpochSecond();
+        long otherEpochSec = other.toEpochSecond();
+        return thisEpochSec < otherEpochSec ||
+            (thisEpochSec == otherEpochSec && getTime().getNano() < other.getTime().getNano());
+    }
+
+    /**
+     * Checks if the instant of this date-time is equal to that of the specified date-time.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} and {@link #equals}
+     * in that it only compares the instant of the date-time. This is equivalent to using
+     * {@code dateTime1.toInstant().equals(dateTime2.toInstant());}.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return true if the instant equals the instant of the specified date-time
+     */
+    public boolean isEqual(OffsetDateTime other) {
+        return toEpochSecond() == other.toEpochSecond() &&
+                getTime().getNano() == other.getTime().getNano();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this date-time is equal to another date-time.
+     * <p>
+     * The comparison is based on the local date-time and the offset.
+     * To compare for the same instant on the time-line, use {@link #isEqual}.
+     * Only objects of type {@code OffsetDateTime} are compared, other types return false.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other date-time
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof OffsetDateTime) {
+            OffsetDateTime other = (OffsetDateTime) obj;
+            return dateTime.equals(other.dateTime) && offset.equals(other.offset);
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this date-time.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return dateTime.hashCode() ^ offset.hashCode();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this date-time as a {@code String}, such as {@code 2007-12-03T10:15:30+01:00}.
+     * <p>
+     * The output will be one of the following ISO-8601 formats:
+     * <p><ul>
+     * <li>{@code yyyy-MM-dd'T'HH:mmXXXXX}</li>
+     * <li>{@code yyyy-MM-dd'T'HH:mm:ssXXXXX}</li>
+     * <li>{@code yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX}</li>
+     * <li>{@code yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXXXX}</li>
+     * <li>{@code yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSXXXXX}</li>
+     * </ul><p>
+     * The format used will be the shortest that outputs the full value of
+     * the time where the omitted parts are implied to be zero.
+     *
+     * @return a string representation of this date-time, not null
+     */
+    @Override
+    public String toString() {
+        return dateTime.toString() + offset.toString();
+    }
+
+    /**
+     * Outputs this date-time as a {@code String} using the formatter.
+     * <p>
+     * This date-time will be passed to the formatter
+     * {@link DateTimeFormatter#print(TemporalAccessor) print method}.
+     *
+     * @param formatter  the formatter to use, not null
+     * @return the formatted date-time string, not null
+     * @throws DateTimeException if an error occurs during printing
+     */
+    public String toString(DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.print(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>.
+     * <pre>
+     *  out.writeByte(3);  // identifies this as a OffsetDateTime
+     *  out.writeObject(dateTime);
+     *  out.writeObject(offset);
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.OFFSET_DATE_TIME_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     * @return never
+     * @throws InvalidObjectException always
+     */
+    private Object readResolve() throws ObjectStreamException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    void writeExternal(ObjectOutput out) throws IOException {
+        out.writeObject(dateTime);
+        out.writeObject(offset);
+    }
+
+    static OffsetDateTime readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+        LocalDateTime dateTime = (LocalDateTime) in.readObject();
+        ZoneOffset offset = (ZoneOffset) in.readObject();
+        return OffsetDateTime.of(dateTime, offset);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/OffsetTime.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,1311 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import static java.time.temporal.ChronoField.NANO_OF_DAY;
+import static java.time.temporal.ChronoField.OFFSET_SECONDS;
+import static java.time.temporal.ChronoLocalDateTimeImpl.NANOS_PER_HOUR;
+import static java.time.temporal.ChronoLocalDateTimeImpl.NANOS_PER_MINUTE;
+import static java.time.temporal.ChronoLocalDateTimeImpl.NANOS_PER_SECOND;
+import static java.time.temporal.ChronoLocalDateTimeImpl.SECONDS_PER_DAY;
+import static java.time.temporal.ChronoUnit.NANOS;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatters;
+import java.time.format.DateTimeParseException;
+import java.time.zone.ZoneRules;
+import java.util.Objects;
+
+/**
+ * A time with an offset from UTC/Greenwich in the ISO-8601 calendar system,
+ * such as {@code 10:15:30+01:00}.
+ * <p>
+ * {@code OffsetTime} is an immutable date-time object that represents a time, often
+ * viewed as hour-minute-second-offset.
+ * This class stores all time fields, to a precision of nanoseconds,
+ * as well as a zone offset.
+ * For example, the value "13:45.30.123456789+02:00" can be stored
+ * in an {@code OffsetTime}.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class OffsetTime
+        implements Temporal, TemporalAdjuster, Comparable<OffsetTime>, Serializable {
+
+    /**
+     * The minimum supported {@code OffsetTime}, '00:00:00+18:00'.
+     * This is the time of midnight at the start of the day in the maximum offset
+     * (larger offsets are earlier on the time-line).
+     * This combines {@link LocalTime#MIN} and {@link ZoneOffset#MAX}.
+     * This could be used by an application as a "far past" date.
+     */
+    public static final OffsetTime MIN = LocalTime.MIN.atOffset(ZoneOffset.MAX);
+    /**
+     * The maximum supported {@code OffsetTime}, '23:59:59.999999999-18:00'.
+     * This is the time just before midnight at the end of the day in the minimum offset
+     * (larger negative offsets are later on the time-line).
+     * This combines {@link LocalTime#MAX} and {@link ZoneOffset#MIN}.
+     * This could be used by an application as a "far future" date.
+     */
+    public static final OffsetTime MAX = LocalTime.MAX.atOffset(ZoneOffset.MIN);
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 7264499704384272492L;
+
+    /**
+     * The local date-time.
+     */
+    private final LocalTime time;
+    /**
+     * The offset from UTC/Greenwich.
+     */
+    private final ZoneOffset offset;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains the current time from the system clock in the default time-zone.
+     * <p>
+     * This will query the {@link java.time.Clock#systemDefaultZone() system clock} in the default
+     * time-zone to obtain the current time.
+     * The offset will be calculated from the time-zone in the clock.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @return the current time using the system clock, not null
+     */
+    public static OffsetTime now() {
+        return now(Clock.systemDefaultZone());
+    }
+
+    /**
+     * Obtains the current time from the system clock in the specified time-zone.
+     * <p>
+     * This will query the {@link Clock#system(java.time.ZoneId) system clock} to obtain the current time.
+     * Specifying the time-zone avoids dependence on the default time-zone.
+     * The offset will be calculated from the specified time-zone.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @param zone  the zone ID to use, not null
+     * @return the current time using the system clock, not null
+     */
+    public static OffsetTime now(ZoneId zone) {
+        return now(Clock.system(zone));
+    }
+
+    /**
+     * Obtains the current time from the specified clock.
+     * <p>
+     * This will query the specified clock to obtain the current time.
+     * The offset will be calculated from the time-zone in the clock.
+     * <p>
+     * Using this method allows the use of an alternate clock for testing.
+     * The alternate clock may be introduced using {@link Clock dependency injection}.
+     *
+     * @param clock  the clock to use, not null
+     * @return the current time, not null
+     */
+    public static OffsetTime now(Clock clock) {
+        Objects.requireNonNull(clock, "clock");
+        final Instant now = clock.instant();  // called once
+        return ofInstant(now, clock.getZone().getRules().getOffset(now));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code OffsetTime} from a local time and an offset.
+     *
+     * @param time  the local time, not null
+     * @param offset  the zone offset, not null
+     * @return the offset time, not null
+     */
+    public static OffsetTime of(LocalTime time, ZoneOffset offset) {
+        return new OffsetTime(time, offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code OffsetTime} from an {@code Instant} and zone ID.
+     * <p>
+     * This creates an offset time with the same instant as that specified.
+     * Finding the offset from UTC/Greenwich is simple as there is only one valid
+     * offset for each instant.
+     * <p>
+     * The date component of the instant is dropped during the conversion.
+     * This means that the conversion can never fail due to the instant being
+     * out of the valid range of dates.
+     *
+     * @param instant  the instant to create the time from, not null
+     * @param zone  the time-zone, which may be an offset, not null
+     * @return the offset time, not null
+     */
+    public static OffsetTime ofInstant(Instant instant, ZoneId zone) {
+        Objects.requireNonNull(instant, "instant");
+        Objects.requireNonNull(zone, "zone");
+        ZoneRules rules = zone.getRules();
+        ZoneOffset offset = rules.getOffset(instant);
+        long secsOfDay = instant.getEpochSecond() % SECONDS_PER_DAY;
+        secsOfDay = (secsOfDay + offset.getTotalSeconds()) % SECONDS_PER_DAY;
+        if (secsOfDay < 0) {
+            secsOfDay += SECONDS_PER_DAY;
+        }
+        LocalTime time = LocalTime.ofSecondOfDay(secsOfDay, instant.getNano());
+        return new OffsetTime(time, offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code OffsetTime} from a temporal object.
+     * <p>
+     * A {@code TemporalAccessor} represents some form of date and time information.
+     * This factory converts the arbitrary temporal object to an instance of {@code OffsetTime}.
+     * <p>
+     * The conversion extracts and combines {@code LocalTime} and {@code ZoneOffset}.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used in queries via method reference, {@code OffsetTime::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the offset time, not null
+     * @throws DateTimeException if unable to convert to an {@code OffsetTime}
+     */
+    public static OffsetTime from(TemporalAccessor temporal) {
+        if (temporal instanceof OffsetTime) {
+            return (OffsetTime) temporal;
+        }
+        try {
+            LocalTime time = LocalTime.from(temporal);
+            ZoneOffset offset = ZoneOffset.from(temporal);
+            return new OffsetTime(time, offset);
+        } catch (DateTimeException ex) {
+            throw new DateTimeException("Unable to obtain OffsetTime from TemporalAccessor: " + temporal.getClass(), ex);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code OffsetTime} from a text string such as {@code 10:15:30+01:00}.
+     * <p>
+     * The string must represent a valid time and is parsed using
+     * {@link java.time.format.DateTimeFormatters#isoOffsetTime()}.
+     *
+     * @param text  the text to parse such as "10:15:30+01:00", not null
+     * @return the parsed local time, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static OffsetTime parse(CharSequence text) {
+        return parse(text, DateTimeFormatters.isoOffsetTime());
+    }
+
+    /**
+     * Obtains an instance of {@code OffsetTime} from a text string using a specific formatter.
+     * <p>
+     * The text is parsed using the formatter, returning a time.
+     *
+     * @param text  the text to parse, not null
+     * @param formatter  the formatter to use, not null
+     * @return the parsed offset time, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static OffsetTime parse(CharSequence text, DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.parse(text, OffsetTime::from);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructor.
+     *
+     * @param time  the local time, not null
+     * @param offset  the zone offset, not null
+     */
+    private OffsetTime(LocalTime time, ZoneOffset offset) {
+        this.time = Objects.requireNonNull(time, "time");
+        this.offset = Objects.requireNonNull(offset, "offset");
+    }
+
+    /**
+     * Returns a new time based on this one, returning {@code this} where possible.
+     *
+     * @param time  the time to create with, not null
+     * @param offset  the zone offset to create with, not null
+     */
+    private OffsetTime with(LocalTime time, ZoneOffset offset) {
+        if (this.time == time && this.offset.equals(offset)) {
+            return this;
+        }
+        return new OffsetTime(time, offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if this time can be queried for the specified field.
+     * If false, then calling the {@link #range(TemporalField) range} and
+     * {@link #get(TemporalField) get} methods will throw an exception.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The supported fields are:
+     * <ul>
+     * <li>{@code NANO_OF_SECOND}
+     * <li>{@code NANO_OF_DAY}
+     * <li>{@code MICRO_OF_SECOND}
+     * <li>{@code MICRO_OF_DAY}
+     * <li>{@code MILLI_OF_SECOND}
+     * <li>{@code MILLI_OF_DAY}
+     * <li>{@code SECOND_OF_MINUTE}
+     * <li>{@code SECOND_OF_DAY}
+     * <li>{@code MINUTE_OF_HOUR}
+     * <li>{@code MINUTE_OF_DAY}
+     * <li>{@code HOUR_OF_AMPM}
+     * <li>{@code CLOCK_HOUR_OF_AMPM}
+     * <li>{@code HOUR_OF_DAY}
+     * <li>{@code CLOCK_HOUR_OF_DAY}
+     * <li>{@code AMPM_OF_DAY}
+     * <li>{@code OFFSET_SECONDS}
+     * </ul>
+     * All other {@code ChronoField} instances will return false.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the field is supported is determined by the field.
+     *
+     * @param field  the field to check, null returns false
+     * @return true if the field is supported on this time, false if not
+     */
+    @Override
+    public boolean isSupported(TemporalField field) {
+        if (field instanceof ChronoField) {
+            return ((ChronoField) field).isTimeField() || field == OFFSET_SECONDS;
+        }
+        return field != null && field.doIsSupported(this);
+    }
+
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * The range object expresses the minimum and maximum valid values for a field.
+     * This time is used to enhance the accuracy of the returned range.
+     * If it is not possible to return the range, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * 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}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the range can be obtained is determined by the field.
+     *
+     * @param field  the field to query the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     */
+    @Override
+    public ValueRange range(TemporalField field) {
+        if (field instanceof ChronoField) {
+            if (field == OFFSET_SECONDS) {
+                return field.range();
+            }
+            return time.range(field);
+        }
+        return field.doRange(this);
+    }
+
+    /**
+     * Gets the value of the specified field from this time as an {@code int}.
+     * <p>
+     * This queries this time for the value for the specified field.
+     * The returned value will always be within the valid range of values for the field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this time, except {@code NANO_OF_DAY} and {@code MICRO_OF_DAY}
+     * which are too large to fit in an {@code int} and throw a {@code DateTimeException}.
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override  // override for Javadoc
+    public int get(TemporalField field) {
+        return Temporal.super.get(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this time as a {@code long}.
+     * <p>
+     * This queries this time for the value for the specified field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this time.
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long getLong(TemporalField field) {
+        if (field instanceof ChronoField) {
+            if (field == OFFSET_SECONDS) {
+                return getOffset().getTotalSeconds();
+            }
+            return time.getLong(field);
+        }
+        return field.doGet(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the zone offset, such as '+01:00'.
+     * <p>
+     * This is the offset of the local time from UTC/Greenwich.
+     *
+     * @return the zone offset, not null
+     */
+    public ZoneOffset getOffset() {
+        return offset;
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetTime} with the specified offset ensuring
+     * that the result has the same local time.
+     * <p>
+     * This method returns an object with the same {@code LocalTime} and the specified {@code ZoneOffset}.
+     * No calculation is needed or performed.
+     * For example, if this time represents {@code 10:30+02:00} and the offset specified is
+     * {@code +03:00}, then this method will return {@code 10:30+03:00}.
+     * <p>
+     * To take into account the difference between the offsets, and adjust the time fields,
+     * use {@link #withOffsetSameInstant}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param offset  the zone offset to change to, not null
+     * @return an {@code OffsetTime} based on this time with the requested offset, not null
+     */
+    public OffsetTime withOffsetSameLocal(ZoneOffset offset) {
+        return offset != null && offset.equals(this.offset) ? this : new OffsetTime(time, offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetTime} with the specified offset ensuring
+     * that the result is at the same instant on an implied day.
+     * <p>
+     * This method returns an object with the specified {@code ZoneOffset} and a {@code LocalTime}
+     * adjusted by the difference between the two offsets.
+     * This will result in the old and new objects representing the same instant an an implied day.
+     * This is useful for finding the local time in a different offset.
+     * For example, if this time represents {@code 10:30+02:00} and the offset specified is
+     * {@code +03:00}, then this method will return {@code 11:30+03:00}.
+     * <p>
+     * To change the offset without adjusting the local time use {@link #withOffsetSameLocal}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param offset  the zone offset to change to, not null
+     * @return an {@code OffsetTime} based on this time with the requested offset, not null
+     */
+    public OffsetTime withOffsetSameInstant(ZoneOffset offset) {
+        if (offset.equals(this.offset)) {
+            return this;
+        }
+        int difference = offset.getTotalSeconds() - this.offset.getTotalSeconds();
+        LocalTime adjusted = time.plusSeconds(difference);
+        return new OffsetTime(adjusted, offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the {@code LocalTime} part of this date-time.
+     * <p>
+     * This returns a {@code LocalTime} with the same hour, minute, second and
+     * nanosecond as this date-time.
+     *
+     * @return the time part of this date-time, not null
+     */
+    public LocalTime getTime() {
+        return time;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the hour-of-day field.
+     *
+     * @return the hour-of-day, from 0 to 23
+     */
+    public int getHour() {
+        return time.getHour();
+    }
+
+    /**
+     * Gets the minute-of-hour field.
+     *
+     * @return the minute-of-hour, from 0 to 59
+     */
+    public int getMinute() {
+        return time.getMinute();
+    }
+
+    /**
+     * Gets the second-of-minute field.
+     *
+     * @return the second-of-minute, from 0 to 59
+     */
+    public int getSecond() {
+        return time.getSecond();
+    }
+
+    /**
+     * Gets the nano-of-second field.
+     *
+     * @return the nano-of-second, from 0 to 999,999,999
+     */
+    public int getNano() {
+        return time.getNano();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns an adjusted copy of this time.
+     * <p>
+     * This returns a new {@code OffsetTime}, based on this one, with the time adjusted.
+     * The adjustment takes place using the specified adjuster strategy object.
+     * Read the documentation of the adjuster to understand what adjustment will be made.
+     * <p>
+     * A simple adjuster might simply set the one of the fields, such as the hour field.
+     * A more complex adjuster might set the time to the last hour of the day.
+     * <p>
+     * The classes {@link LocalTime} and {@link ZoneOffset} implement {@code TemporalAdjuster},
+     * thus this method can be used to change the time or offset:
+     * <pre>
+     *  result = offsetTime.with(time);
+     *  result = offsetTime.with(offset);
+     * </pre>
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param adjuster the adjuster to use, not null
+     * @return an {@code OffsetTime} based on {@code this} with the adjustment made, not null
+     * @throws DateTimeException if the adjustment cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public OffsetTime with(TemporalAdjuster adjuster) {
+        // optimizations
+        if (adjuster instanceof LocalTime) {
+            return with((LocalTime) adjuster, offset);
+        } else if (adjuster instanceof ZoneOffset) {
+            return with(time, (ZoneOffset) adjuster);
+        } else if (adjuster instanceof OffsetTime) {
+            return (OffsetTime) adjuster;
+        }
+        return (OffsetTime) adjuster.adjustInto(this);
+    }
+
+    /**
+     * Returns a copy of this time with the specified field set to a new value.
+     * <p>
+     * This returns a new {@code OffsetTime}, based on this one, with the value
+     * for the specified field changed.
+     * This can be used to change any supported field, such as the hour, minute or second.
+     * If it is not possible to set the value, because the field is not supported or for
+     * some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the adjustment is implemented here.
+     * <p>
+     * The {@code OFFSET_SECONDS} field will return a time with the specified offset.
+     * The local time is unaltered. If the new offset value is outside the valid range
+     * then a {@code DateTimeException} will be thrown.
+     * <p>
+     * The other {@link #isSupported(TemporalField) supported fields} will behave as per
+     * the matching method on {@link LocalTime#with(TemporalField, long)} LocalTime}.
+     * In this case, the offset is not part of the calculation and will be unchanged.
+     * <p>
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param field  the field to set in the result, not null
+     * @param newValue  the new value of the field in the result
+     * @return an {@code OffsetTime} based on {@code this} with the specified field set, not null
+     * @throws DateTimeException if the field cannot be set
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public OffsetTime with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            if (field == OFFSET_SECONDS) {
+                ChronoField f = (ChronoField) field;
+                return with(time, ZoneOffset.ofTotalSeconds(f.checkValidIntValue(newValue)));
+            }
+            return with(time.with(field, newValue), offset);
+        }
+        return field.doWith(this, newValue);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code OffsetTime} with the hour-of-day value altered.
+     * <p>
+     * The offset does not affect the calculation and will be the same in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hour  the hour-of-day to set in the result, from 0 to 23
+     * @return an {@code OffsetTime} based on this time with the requested hour, not null
+     * @throws DateTimeException if the hour value is invalid
+     */
+    public OffsetTime withHour(int hour) {
+        return with(time.withHour(hour), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetTime} with the minute-of-hour value altered.
+     * <p>
+     * The offset does not affect the calculation and will be the same in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minute  the minute-of-hour to set in the result, from 0 to 59
+     * @return an {@code OffsetTime} based on this time with the requested minute, not null
+     * @throws DateTimeException if the minute value is invalid
+     */
+    public OffsetTime withMinute(int minute) {
+        return with(time.withMinute(minute), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetTime} with the second-of-minute value altered.
+     * <p>
+     * The offset does not affect the calculation and will be the same in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param second  the second-of-minute to set in the result, from 0 to 59
+     * @return an {@code OffsetTime} based on this time with the requested second, not null
+     * @throws DateTimeException if the second value is invalid
+     */
+    public OffsetTime withSecond(int second) {
+        return with(time.withSecond(second), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetTime} with the nano-of-second value altered.
+     * <p>
+     * The offset does not affect the calculation and will be the same in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanoOfSecond  the nano-of-second to set in the result, from 0 to 999,999,999
+     * @return an {@code OffsetTime} based on this time with the requested nanosecond, not null
+     * @throws DateTimeException if the nanos value is invalid
+     */
+    public OffsetTime withNano(int nanoOfSecond) {
+        return with(time.withNano(nanoOfSecond), offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code OffsetTime} with the time truncated.
+     * <p>
+     * Truncation returns a copy of the original time with fields
+     * smaller than the specified unit set to zero.
+     * For example, truncating with the {@link ChronoUnit#MINUTES minutes} unit
+     * will set the second-of-minute and nano-of-second field to zero.
+     * <p>
+     * Not all units are accepted. The {@link ChronoUnit#DAYS days} unit and time
+     * units with an exact duration can be used, other units throw an exception.
+     * <p>
+     * The offset does not affect the calculation and will be the same in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param unit  the unit to truncate to, not null
+     * @return an {@code OffsetTime} based on this time with the time truncated, not null
+     * @throws DateTimeException if unable to truncate
+     */
+    public OffsetTime truncatedTo(TemporalUnit unit) {
+        return with(time.truncatedTo(unit), offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this date with the specified period added.
+     * <p>
+     * This method returns a new time based on this time with the specified period added.
+     * The adder is typically {@link java.time.Period} but may be any other type implementing
+     * the {@link TemporalAdder} interface.
+     * The calculation is delegated to the specified adjuster, which typically calls
+     * back to {@link #plus(long, TemporalUnit)}.
+     * The offset is not part of the calculation and will be unchanged in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param adder  the adder to use, not null
+     * @return an {@code OffsetTime} based on this time with the addition made, not null
+     * @throws DateTimeException if the addition cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public OffsetTime plus(TemporalAdder adder) {
+        return (OffsetTime) adder.addTo(this);
+    }
+
+    /**
+     * Returns a copy of this time with the specified period added.
+     * <p>
+     * This method returns a new time based on this time with the specified period added.
+     * This can be used to add any period that is defined by a unit, for example to add hours, minutes or seconds.
+     * The unit is responsible for the details of the calculation, including the resolution
+     * of any edge cases in the calculation.
+     * The offset is not part of the calculation and will be unchanged in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToAdd  the amount of the unit to add to the result, may be negative
+     * @param unit  the unit of the period to add, not null
+     * @return an {@code OffsetTime} based on this time with the specified period added, not null
+     * @throws DateTimeException if the unit cannot be added to this type
+     */
+    @Override
+    public OffsetTime plus(long amountToAdd, TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            return with(time.plus(amountToAdd, unit), offset);
+        }
+        return unit.doPlus(this, amountToAdd);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code OffsetTime} with the specified period in hours added.
+     * <p>
+     * This adds the specified number of hours to this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hours  the hours to add, may be negative
+     * @return an {@code OffsetTime} based on this time with the hours added, not null
+     */
+    public OffsetTime plusHours(long hours) {
+        return with(time.plusHours(hours), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetTime} with the specified period in minutes added.
+     * <p>
+     * This adds the specified number of minutes to this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minutes  the minutes to add, may be negative
+     * @return an {@code OffsetTime} based on this time with the minutes added, not null
+     */
+    public OffsetTime plusMinutes(long minutes) {
+        return with(time.plusMinutes(minutes), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetTime} with the specified period in seconds added.
+     * <p>
+     * This adds the specified number of seconds to this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param seconds  the seconds to add, may be negative
+     * @return an {@code OffsetTime} based on this time with the seconds added, not null
+     */
+    public OffsetTime plusSeconds(long seconds) {
+        return with(time.plusSeconds(seconds), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetTime} with the specified period in nanoseconds added.
+     * <p>
+     * This adds the specified number of nanoseconds to this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanos  the nanos to add, may be negative
+     * @return an {@code OffsetTime} based on this time with the nanoseconds added, not null
+     */
+    public OffsetTime plusNanos(long nanos) {
+        return with(time.plusNanos(nanos), offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this time with the specified period subtracted.
+     * <p>
+     * This method returns a new time based on this time with the specified period subtracted.
+     * The subtractor is typically {@link java.time.Period} but may be any other type implementing
+     * the {@link TemporalSubtractor} interface.
+     * The calculation is delegated to the specified adjuster, which typically calls
+     * back to {@link #minus(long, TemporalUnit)}.
+     * The offset is not part of the calculation and will be unchanged in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param subtractor  the subtractor to use, not null
+     * @return an {@code OffsetTime} based on this time with the subtraction made, not null
+     * @throws DateTimeException if the subtraction cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public OffsetTime minus(TemporalSubtractor subtractor) {
+        return (OffsetTime) subtractor.subtractFrom(this);
+    }
+
+    /**
+     * Returns a copy of this time with the specified period subtracted.
+     * <p>
+     * This method returns a new time based on this time with the specified period subtracted.
+     * This can be used to subtract any period that is defined by a unit, for example to subtract hours, minutes or seconds.
+     * The unit is responsible for the details of the calculation, including the resolution
+     * of any edge cases in the calculation.
+     * The offset is not part of the calculation and will be unchanged in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToSubtract  the amount of the unit to subtract from the result, may be negative
+     * @param unit  the unit of the period to subtract, not null
+     * @return an {@code OffsetTime} based on this time with the specified period subtracted, not null
+     * @throws DateTimeException if the unit cannot be added to this type
+     */
+    @Override
+    public OffsetTime minus(long amountToSubtract, TemporalUnit unit) {
+        return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code OffsetTime} with the specified period in hours subtracted.
+     * <p>
+     * This subtracts the specified number of hours from this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hours  the hours to subtract, may be negative
+     * @return an {@code OffsetTime} based on this time with the hours subtracted, not null
+     */
+    public OffsetTime minusHours(long hours) {
+        return with(time.minusHours(hours), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetTime} with the specified period in minutes subtracted.
+     * <p>
+     * This subtracts the specified number of minutes from this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minutes  the minutes to subtract, may be negative
+     * @return an {@code OffsetTime} based on this time with the minutes subtracted, not null
+     */
+    public OffsetTime minusMinutes(long minutes) {
+        return with(time.minusMinutes(minutes), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetTime} with the specified period in seconds subtracted.
+     * <p>
+     * This subtracts the specified number of seconds from this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param seconds  the seconds to subtract, may be negative
+     * @return an {@code OffsetTime} based on this time with the seconds subtracted, not null
+     */
+    public OffsetTime minusSeconds(long seconds) {
+        return with(time.minusSeconds(seconds), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetTime} with the specified period in nanoseconds subtracted.
+     * <p>
+     * This subtracts the specified number of nanoseconds from this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanos  the nanos to subtract, may be negative
+     * @return an {@code OffsetTime} based on this time with the nanoseconds subtracted, not null
+     */
+    public OffsetTime minusNanos(long nanos) {
+        return with(time.minusNanos(nanos), offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this time using the specified query.
+     * <p>
+     * This queries this time using the specified query strategy object.
+     * The {@code TemporalQuery} object defines the logic to be used to
+     * obtain the result. Read the documentation of the query to understand
+     * what the result of this method will be.
+     * <p>
+     * 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 <R> 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> R query(TemporalQuery<R> query) {
+        if (query == Queries.precision()) {
+            return (R) NANOS;
+        } else if (query == Queries.offset() || query == Queries.zone()) {
+            return (R) getOffset();
+        }
+        return Temporal.super.query(query);
+    }
+
+    /**
+     * Adjusts the specified temporal object to have the same offset and time
+     * as this object.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with the offset and time changed to be the same as this.
+     * <p>
+     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+     * twice, passing {@link ChronoField#OFFSET_SECONDS} and
+     * {@link ChronoField#NANO_OF_DAY} as the fields.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisOffsetTime.adjustInto(temporal);
+     *   temporal = temporal.with(thisOffsetTime);
+     * </pre>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param temporal  the target object to be adjusted, not null
+     * @return the adjusted object, not null
+     * @throws DateTimeException if unable to make the adjustment
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Temporal adjustInto(Temporal temporal) {
+        return temporal
+                .with(OFFSET_SECONDS, getOffset().getTotalSeconds())
+                .with(NANO_OF_DAY, time.toNanoOfDay());
+    }
+
+    /**
+     * Calculates the period between this time and another time in
+     * terms of the specified unit.
+     * <p>
+     * This calculates the period between two times in terms of a single unit.
+     * The start and end points are {@code this} and the specified time.
+     * The result will be negative if the end is before the start.
+     * For example, the period in hours between two times can be calculated
+     * using {@code startTime.periodUntil(endTime, HOURS)}.
+     * <p>
+     * The {@code Temporal} passed to this method must be an {@code OffsetTime}.
+     * If the offset differs between the two times, then the specified
+     * end time is normalized to have the same offset as this time.
+     * <p>
+     * The calculation returns a whole number, representing the number of
+     * complete units between the two times.
+     * For example, the period in hours between 11:30Z and 13:29Z will only
+     * be one hour as it is one minute short of two hours.
+     * <p>
+     * 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:
+     * <pre>
+     *   long period = start.periodUntil(end, HOURS);   // this method
+     *   dateTime.plus(HOURS.between(start, end));      // use in plus/minus
+     * </pre>
+     * <p>
+     * The calculation is implemented in this method for {@link ChronoUnit}.
+     * The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS},
+     * {@code MINUTES}, {@code HOURS} and {@code HALF_DAYS} are supported.
+     * Other {@code ChronoUnit} values will throw an exception.
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param endTime  the end time, which must be an {@code OffsetTime}, not null
+     * @param unit  the unit to measure the period in, not null
+     * @return the amount of the period between this time and the end time
+     * @throws DateTimeException if the period cannot be calculated
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long periodUntil(Temporal endTime, TemporalUnit unit) {
+        if (endTime instanceof OffsetTime == false) {
+            Objects.requireNonNull(endTime, "endTime");
+            throw new DateTimeException("Unable to calculate period between objects of two different types");
+        }
+        if (unit instanceof ChronoUnit) {
+            OffsetTime end = (OffsetTime) endTime;
+            long nanosUntil = end.toEpochNano() - toEpochNano();  // no overflow
+            switch ((ChronoUnit) unit) {
+                case NANOS: return nanosUntil;
+                case MICROS: return nanosUntil / 1000;
+                case MILLIS: return nanosUntil / 1000_000;
+                case SECONDS: return nanosUntil / NANOS_PER_SECOND;
+                case MINUTES: return nanosUntil / NANOS_PER_MINUTE;
+                case HOURS: return nanosUntil / NANOS_PER_HOUR;
+                case HALF_DAYS: return nanosUntil / (12 * NANOS_PER_HOUR);
+            }
+            throw new DateTimeException("Unsupported unit: " + unit.getName());
+        }
+        return unit.between(this, endTime).getAmount();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns an offset date-time formed from this time at the specified date.
+     * <p>
+     * This combines this time with the specified date to form an {@code OffsetDateTime}.
+     * All possible combinations of date and time are valid.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param date  the date to combine with, not null
+     * @return the offset date-time formed from this time and the specified date, not null
+     */
+    public OffsetDateTime atDate(LocalDate date) {
+        return OffsetDateTime.of(date, time, offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Converts this time to epoch nanos based on 1970-01-01Z.
+     *
+     * @return the epoch nanos value
+     */
+    private long toEpochNano() {
+        long nod = time.toNanoOfDay();
+        long offsetNanos = offset.getTotalSeconds() * NANOS_PER_SECOND;
+        return nod - offsetNanos;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this {@code OffsetTime} to another time.
+     * <p>
+     * The comparison is based first on the UTC equivalent instant, then on the local time.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     * <p>
+     * For example, the following is the comparator order:
+     * <ol>
+     * <li>{@code 10:30+01:00}</li>
+     * <li>{@code 11:00+01:00}</li>
+     * <li>{@code 12:00+02:00}</li>
+     * <li>{@code 11:30+01:00}</li>
+     * <li>{@code 12:00+01:00}</li>
+     * <li>{@code 12:30+01:00}</li>
+     * </ol>
+     * Values #2 and #3 represent the same instant on the time-line.
+     * When two values represent the same instant, the local time is compared
+     * to distinguish them. This step is needed to make the ordering
+     * consistent with {@code equals()}.
+     * <p>
+     * To compare the underlying local time of two {@code TemporalAccessor} instances,
+     * use {@link ChronoField#NANO_OF_DAY} as a comparator.
+     *
+     * @param other  the other time to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     * @throws NullPointerException if {@code other} is null
+     */
+    @Override
+    public int compareTo(OffsetTime other) {
+        if (offset.equals(other.offset)) {
+            return time.compareTo(other.time);
+        }
+        int compare = Long.compare(toEpochNano(), other.toEpochNano());
+        if (compare == 0) {
+            compare = time.compareTo(other.time);
+        }
+        return compare;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the instant of this {@code OffsetTime} is after that of the
+     * specified time applying both times to a common date.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} in that it
+     * only compares the instant of the time. This is equivalent to converting both
+     * times to an instant using the same date and comparing the instants.
+     *
+     * @param other  the other time to compare to, not null
+     * @return true if this is after the instant of the specified time
+     */
+    public boolean isAfter(OffsetTime other) {
+        return toEpochNano() > other.toEpochNano();
+    }
+
+    /**
+     * Checks if the instant of this {@code OffsetTime} is before that of the
+     * specified time applying both times to a common date.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} in that it
+     * only compares the instant of the time. This is equivalent to converting both
+     * times to an instant using the same date and comparing the instants.
+     *
+     * @param other  the other time to compare to, not null
+     * @return true if this is before the instant of the specified time
+     */
+    public boolean isBefore(OffsetTime other) {
+        return toEpochNano() < other.toEpochNano();
+    }
+
+    /**
+     * Checks if the instant of this {@code OffsetTime} is equal to that of the
+     * specified time applying both times to a common date.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} and {@link #equals}
+     * in that it only compares the instant of the time. This is equivalent to converting both
+     * times to an instant using the same date and comparing the instants.
+     *
+     * @param other  the other time to compare to, not null
+     * @return true if this is equal to the instant of the specified time
+     */
+    public boolean isEqual(OffsetTime other) {
+        return toEpochNano() == other.toEpochNano();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this time is equal to another time.
+     * <p>
+     * The comparison is based on the local-time and the offset.
+     * To compare for the same instant on the time-line, use {@link #isEqual(OffsetTime)}.
+     * <p>
+     * Only objects of type {@code OffsetTime} are compared, other types return false.
+     * To compare the underlying local time of two {@code TemporalAccessor} instances,
+     * use {@link ChronoField#NANO_OF_DAY} as a comparator.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other time
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof OffsetTime) {
+            OffsetTime other = (OffsetTime) obj;
+            return time.equals(other.time) && offset.equals(other.offset);
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this time.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return time.hashCode() ^ offset.hashCode();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this time as a {@code String}, such as {@code 10:15:30+01:00}.
+     * <p>
+     * The output will be one of the following ISO-8601 formats:
+     * <p><ul>
+     * <li>{@code HH:mmXXXXX}</li>
+     * <li>{@code HH:mm:ssXXXXX}</li>
+     * <li>{@code HH:mm:ss.SSSXXXXX}</li>
+     * <li>{@code HH:mm:ss.SSSSSSXXXXX}</li>
+     * <li>{@code HH:mm:ss.SSSSSSSSSXXXXX}</li>
+     * </ul><p>
+     * The format used will be the shortest that outputs the full value of
+     * the time where the omitted parts are implied to be zero.
+     *
+     * @return a string representation of this time, not null
+     */
+    @Override
+    public String toString() {
+        return time.toString() + offset.toString();
+    }
+
+    /**
+     * Outputs this time as a {@code String} using the formatter.
+     * <p>
+     * This time will be passed to the formatter
+     * {@link DateTimeFormatter#print(TemporalAccessor) print method}.
+     *
+     * @param formatter  the formatter to use, not null
+     * @return the formatted time string, not null
+     * @throws DateTimeException if an error occurs during printing
+     */
+    public String toString(DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.print(this);
+    }
+
+    // -----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>.
+     * <pre>
+     *  out.writeByte(2);  // identifies this as a OffsetDateTime
+     *  out.writeObject(time);
+     *  out.writeObject(offset);
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.OFFSET_TIME_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     * @return never
+     * @throws InvalidObjectException always
+     */
+    private Object readResolve() throws ObjectStreamException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    void writeExternal(ObjectOutput out) throws IOException {
+        out.writeObject(time);
+        out.writeObject(offset);
+    }
+
+    static OffsetTime readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+        LocalTime time = (LocalTime) in.readObject();
+        ZoneOffset offset = (ZoneOffset) in.readObject();
+        return OffsetTime.of(time, offset);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/Queries.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import static java.time.temporal.ChronoField.OFFSET_SECONDS;
+
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+
+/**
+ * Common implementations of {@code TemporalQuery}.
+ * <p>
+ * This class provides common implementations of {@link TemporalQuery}.
+ * These queries are primarily used as optimizations, allowing the internals
+ * of other objects to be extracted effectively. Note that application code
+ * can also use the {@code from(TemporalAccessor)} method on most temporal
+ * objects as a method reference matching the query interface, such as
+ * {@code LocalDate::from} and {@code ZoneId::from}.
+ * <p>
+ * There are two equivalent ways of using a {@code TemporalQuery}.
+ * The first is to invoke the method on the interface directly.
+ * The second is to use {@link TemporalAccessor#query(TemporalQuery)}:
+ * <pre>
+ *   // these two lines are equivalent, but the second approach is recommended
+ *   dateTime = query.queryFrom(dateTime);
+ *   dateTime = dateTime.query(query);
+ * </pre>
+ * It is recommended to use the second approach, {@code query(TemporalQuery)},
+ * as it is a lot clearer to read in code.
+ *
+ * <h3>Specification for implementors</h3>
+ * This is a thread-safe utility class.
+ * All returned adjusters are immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class Queries {
+    // note that it is vital that each method supplies a constant, not a
+    // calculated value, as they will be checked for using ==
+    // it is also vital that each constant is different (due to the == checking)
+    // as such, alterations to use lambdas must be done with extreme care
+
+    /**
+     * Private constructor since this is a utility class.
+     */
+    private Queries() {
+    }
+
+    //-----------------------------------------------------------------------
+    // special constants should be used to extract information from a TemporalAccessor
+    // that cannot be derived in other ways
+    // Javadoc added here, so as to pretend they are more normal than they really are
+
+    /**
+     * A strict query for the {@code ZoneId}.
+     * <p>
+     * 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.
+     * <p>
+     * In most cases, applications should use {@link #ZONE} as this query is too strict.
+     * <p>
+     * The result from JDK classes implementing {@code TemporalAccessor} is as follows:<br>
+     * {@code LocalDate} returns null<br>
+     * {@code LocalTime} returns null<br>
+     * {@code LocalDateTime} returns null<br>
+     * {@code ZonedDateTime} returns the associated zone<br>
+     * {@code OffsetDate} returns null<br>
+     * {@code OffsetTime} returns null<br>
+     * {@code OffsetDateTime} returns null<br>
+     * {@code ChronoLocalDate} returns null<br>
+     * {@code ChronoLocalDateTime} returns null<br>
+     * {@code ChronoZonedDateTime} returns the associated zone<br>
+     * {@code Era} returns null<br>
+     * {@code DayOfWeek} returns null<br>
+     * {@code Month} returns null<br>
+     * {@code Year} returns null<br>
+     * {@code YearMonth} returns null<br>
+     * {@code MonthDay} returns null<br>
+     * {@code ZoneOffset} returns null<br>
+     * {@code Instant} returns null<br>
+     * @return a ZoneId, may be null
+     */
+    public static final TemporalQuery<ZoneId> zoneId() {
+        return ZONE_ID;
+    }
+    static final TemporalQuery<ZoneId> ZONE_ID = new TemporalQuery<ZoneId>() {
+        @Override
+        public ZoneId queryFrom(TemporalAccessor temporal) {
+            return temporal.query(this);
+        }
+    };
+
+    /**
+     * A query for the {@code Chrono}.
+     * <p>
+     * This queries a {@code TemporalAccessor} for the chronology.
+     * If the target {@code TemporalAccessor} represents a date, or part of a date,
+     * then it should return the chronology that the date is expressed in.
+     * As a result of this definition, objects only representing time, such as
+     * {@code LocalTime}, will return null.
+     * <p>
+     * The result from JDK classes implementing {@code TemporalAccessor} is as follows:<br>
+     * {@code LocalDate} returns {@code ISOChrono.INSTANCE}<br>
+     * {@code LocalTime} returns null (does not represent a date)<br>
+     * {@code LocalDateTime} returns {@code ISOChrono.INSTANCE}<br>
+     * {@code ZonedDateTime} returns {@code ISOChrono.INSTANCE}<br>
+     * {@code OffsetDate} returns {@code ISOChrono.INSTANCE}<br>
+     * {@code OffsetTime} returns null (does not represent a date)<br>
+     * {@code OffsetDateTime} returns {@code ISOChrono.INSTANCE}<br>
+     * {@code ChronoLocalDate} returns the associated chronology<br>
+     * {@code ChronoLocalDateTime} returns the associated chronology<br>
+     * {@code ChronoZonedDateTime} returns the associated chronology<br>
+     * {@code Era} returns the associated chronology<br>
+     * {@code DayOfWeek} returns null (shared across chronologies)<br>
+     * {@code Month} returns {@code ISOChrono.INSTANCE}<br>
+     * {@code Year} returns {@code ISOChrono.INSTANCE}<br>
+     * {@code YearMonth} returns {@code ISOChrono.INSTANCE}<br>
+     * {@code MonthDay} returns null {@code ISOChrono.INSTANCE}<br>
+     * {@code ZoneOffset} returns null (does not represent a date)<br>
+     * {@code Instant} returns null (does not represent a date)<br>
+     * <p>
+     * The method {@link Chrono#from(TemporalAccessor)} can be used as a
+     * {@code TemporalQuery} via a method reference, {@code Chrono::from}.
+     * That method is equivalent to this query, except that it throws an
+     * exception if a chronology cannot be obtained.
+     * @return a Chrono, may be null
+     */
+    public static final TemporalQuery<Chrono<?>> chrono() {
+        return CHRONO;
+    }
+    static final TemporalQuery<Chrono<?>> CHRONO = new TemporalQuery<Chrono<?>>() {
+        @Override
+        public Chrono<?> queryFrom(TemporalAccessor temporal) {
+            return temporal.query(this);
+        }
+    };
+
+    /**
+     * A query for the smallest supported unit.
+     * <p>
+     * This queries a {@code TemporalAccessor} for the time precision.
+     * If the target {@code TemporalAccessor} represents a consistent or complete date-time,
+     * date or time then this must return the smallest precision actually supported.
+     * Note that fields such as {@code NANO_OF_DAY} and {@code NANO_OF_SECOND}
+     * are defined to always return ignoring the precision, thus this is the only
+     * way to find the actual smallest supported unit.
+     * For example, were {@code GregorianCalendar} to implement {@code TemporalAccessor}
+     * it would return a precision of {@code MILLIS}.
+     * <p>
+     * The result from JDK classes implementing {@code TemporalAccessor} is as follows:<br>
+     * {@code LocalDate} returns {@code DAYS}<br>
+     * {@code LocalTime} returns {@code NANOS}<br>
+     * {@code LocalDateTime} returns {@code NANOS}<br>
+     * {@code ZonedDateTime} returns {@code NANOS}<br>
+     * {@code OffsetDate} returns {@code DAYS}<br>
+     * {@code OffsetTime} returns {@code NANOS}<br>
+     * {@code OffsetDateTime} returns {@code NANOS}<br>
+     * {@code ChronoLocalDate} returns {@code DAYS}<br>
+     * {@code ChronoLocalDateTime} returns {@code NANOS}<br>
+     * {@code ChronoZonedDateTime} returns {@code NANOS}<br>
+     * {@code Era} returns {@code ERAS}<br>
+     * {@code DayOfWeek} returns {@code DAYS}<br>
+     * {@code Month} returns {@code MONTHS}<br>
+     * {@code Year} returns {@code YEARS}<br>
+     * {@code YearMonth} returns {@code MONTHS}<br>
+     * {@code MonthDay} returns null (does not represent a complete date or time)<br>
+     * {@code ZoneOffset} returns null (does not represent a date or time)<br>
+     * {@code Instant} returns {@code NANOS}<br>
+     * @return a ChronoUnit, may be null
+     */
+    public static final TemporalQuery<ChronoUnit> precision() {
+        return PRECISION;
+    }
+    static final TemporalQuery<ChronoUnit> PRECISION = new TemporalQuery<ChronoUnit>() {
+        @Override
+        public ChronoUnit queryFrom(TemporalAccessor temporal) {
+            return temporal.query(this);
+        }
+    };
+
+    //-----------------------------------------------------------------------
+    // non-special constants are standard queries that derive information from other information
+    /**
+     * A lenient query for the {@code ZoneId}, falling back to the {@code ZoneOffset}.
+     * <p>
+     * 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()}.
+     * <p>
+     * In most cases, applications should use this query rather than {@code #zoneId()}.
+     * <p>
+     * This query examines the {@link java.time.temporal.ChronoField#OFFSET_SECONDS offset-seconds}
+     * field and uses it to create a {@code ZoneOffset}.
+     * <p>
+     * The method {@link ZoneId#from(TemporalAccessor)} can be used as a
+     * {@code TemporalQuery} via a method reference, {@code ZoneId::from}.
+     * That method is equivalent to this query, except that it throws an
+     * exception if a zone cannot be obtained.
+     * @return a ZoneId, may be null
+     */
+    public static final TemporalQuery<ZoneId> zone() {
+        return ZONE;
+    }
+    static final TemporalQuery<ZoneId> ZONE = new TemporalQuery<ZoneId>() {
+        @Override
+        public ZoneId queryFrom(TemporalAccessor temporal) {
+            ZoneId zone = temporal.query(ZONE_ID);
+            return (zone != null ? zone : temporal.query(OFFSET));
+        }
+    };
+
+    /**
+     * A query for the {@code ZoneOffset}.
+     * <p>
+     * This queries a {@code TemporalAccessor} for the offset.
+     * <p>
+     * This query examines the {@link java.time.temporal.ChronoField#OFFSET_SECONDS offset-seconds}
+     * field and uses it to create a {@code ZoneOffset}.
+     * <p>
+     * The method {@link ZoneOffset#from(TemporalAccessor)} can be used as a
+     * {@code TemporalQuery} via a method reference, {@code ZoneOffset::from}.
+     * That method is equivalent to this query, except that it throws an
+     * exception if an offset cannot be obtained.
+     * @return a ZoneOffset, may be null
+     */
+    public static final TemporalQuery<ZoneOffset> offset() {
+        return OFFSET;
+    }
+    static final TemporalQuery<ZoneOffset> OFFSET = new TemporalQuery<ZoneOffset>() {
+        @Override
+        public ZoneOffset queryFrom(TemporalAccessor temporal) {
+            if (temporal.isSupported(OFFSET_SECONDS)) {
+                return ZoneOffset.ofTotalSeconds(temporal.get(OFFSET_SECONDS));
+            }
+            return null;
+        }
+    };
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/Ser.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.InvalidClassException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.StreamCorruptedException;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+/**
+ * The shared serialization delegate for this package.
+ *
+ * <h3>Implementation notes</h3>
+ * 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}
+ * <p>
+ * 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.
+ * <p>
+ * 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.
+ * <p>
+ * 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;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/SimplePeriod.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.time.DateTimeException;
+import java.util.Objects;
+
+/**
+ * A period of time, measured as an amount of a single unit, such as '3 Months'.
+ * <p>
+ * 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.
+ * <p>
+ * This class is the return type from {@link TemporalUnit#between}.
+ * It can be used more generally, but is designed to enable the following code:
+ * <pre>
+ *  date = date.minus(MONTHS.between(start, end));
+ * </pre>
+ * The unit determines which calendar systems it can be added to.
+ * <p>
+ * 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.
+ *
+ * <h3>Specification for implementors</h3>
+ * 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<SimplePeriod>, 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.
+     * <p>
+     * The parameters represent the two parts of a phrase like '6 Days'. For example:
+     * <pre>
+     *  SimplePeriod.of(3, SECONDS);
+     *  SimplePeriod.of(5, YEARS);
+     * </pre>
+     *
+     * @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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with this period added.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#plus(TemporalAdder)}.
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   dateTime = thisPeriod.addTo(dateTime);
+     *   dateTime = dateTime.plus(thisPeriod);
+     * </pre>
+     * <p>
+     * The calculation is equivalent to invoking {@link Temporal#plus(long, TemporalUnit)}.
+     * <p>
+     * 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.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with this period subtracted.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#plus(TemporalAdder)}.
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   dateTime = thisPeriod.subtractFrom(dateTime);
+     *   dateTime = dateTime.minus(thisPeriod);
+     * </pre>
+     * <p>
+     * The calculation is equivalent to invoking {@link Temporal#minus(long, TemporalUnit)}.
+     * <p>
+     * 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.
+     * <p>
+     * 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
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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}.
+     * <p>
+     * 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
+     * <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>.
+     * <pre>
+     *  out.writeByte(10);  // identifies this as a SimplePeriod
+     *  out.writeLong(amount);
+     *  out.writeObject(unit);
+     * </pre>
+     *
+     * @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);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/Temporal.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,410 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import java.time.DateTimeException;
+import java.time.ZoneId;
+
+/**
+ * Framework-level interface defining read-write access to a temporal object,
+ * such as a date, time, offset or some combination of these.
+ * <p>
+ * This is the base interface type for date, time and offset objects that
+ * are complete enough to be manipulated using plus and minus.
+ * It is implemented by those classes that can provide and manipulate information
+ * as {@linkplain TemporalField fields} or {@linkplain TemporalQuery queries}.
+ * See {@link TemporalAccessor} for the read-only version of this interface.
+ * <p>
+ * Most date and time information can be represented as a number.
+ * These are modeled using {@code TemporalField} with the number held using
+ * a {@code long} to handle large values. Year, month and day-of-month are
+ * simple examples of fields, but they also include instant and offsets.
+ * See {@link ChronoField} for the standard set of fields.
+ * <p>
+ * Two pieces of date/time information cannot be represented by numbers,
+ * the {@linkplain Chrono chronology} and the {@linkplain ZoneId time-zone}.
+ * These can be accessed via {@link #query(TemporalQuery) queries} using
+ * the static methods defined on {@link Queries}.
+ * <p>
+ * This interface is a framework-level interface that should not be widely
+ * used in application code. Instead, applications should create and pass
+ * around instances of concrete types, such as {@code LocalDate}.
+ * There are many reasons for this, part of which is that implementations
+ * of this interface may be in calendar systems other than ISO.
+ * See {@link ChronoLocalDate} for a fuller discussion of the issues.
+ *
+ * <h3>When to implement</h3>
+ * <p>
+ * A class should implement this interface if it meets three criteria:
+ * <p><ul>
+ * <li>it provides access to date/time/offset information, as per {@code TemporalAccessor}
+ * <li>the set of fields are contiguous from the largest to the smallest
+ * <li>the set of fields are complete, such that no other field is needed to define the
+ *  valid range of values for the fields that are represented
+ * </ul><p>
+ * <p>
+ * Four examples make this clear:
+ * <p><ul>
+ * <li>{@code LocalDate} implements this interface as it represents a set of fields
+ *  that are contiguous from days to forever and require no external information to determine
+ *  the validity of each date. It is therefore able to implement plus/minus correctly.
+ * <li>{@code LocalTime} implements this interface as it represents a set of fields
+ *  that are contiguous from nanos to within days and require no external information to determine
+ *  validity. It is able to implement plus/minus correctly, by wrapping around the day.
+ * <li>{@code MonthDay}, the combination of month-of-year and day-of-month, does not implement
+ *  this interface.  While the combination is contiguous, from days to months within years,
+ *  the combination does not have sufficient information to define the valid range of values
+ *  for day-of-month.  As such, it is unable to implement plus/minus correctly.
+ * <li>The combination day-of-week and day-of-month ("Friday the 13th") should not implement
+ *  this interface. It does not represent a contiguous set of fields, as days to weeks overlaps
+ *  days to months.
+ * </ul><p>
+ *
+ * <h3>Specification for implementors</h3>
+ * This interface places no restrictions on the mutability of implementations,
+ * however immutability is strongly recommended.
+ * All implementations must be {@link Comparable}.
+ *
+ * @since 1.8
+ */
+public interface Temporal extends TemporalAccessor {
+
+    /**
+     * Returns an adjusted object of the same type as this object with the adjustment made.
+     * <p>
+     * This adjusts this date-time according to the rules of the specified adjuster.
+     * A simple adjuster might simply set the one of the fields, such as the year field.
+     * A more complex adjuster might set the date to the last day of the month.
+     * A selection of common adjustments is provided in {@link Adjusters}.
+     * These include finding the "last day of the month" and "next Wednesday".
+     * The adjuster is responsible for handling special cases, such as the varying
+     * lengths of month and leap years.
+     * <p>
+     * Some example code indicating how and why this method is used:
+     * <pre>
+     *  date = date.with(Month.JULY);        // most key classes implement TemporalAdjuster
+     *  date = date.with(lastDayOfMonth());  // static import from Adjusters
+     *  date = date.with(next(WEDNESDAY));   // static import from Adjusters and DayOfWeek
+     * </pre>
+     *
+     * <h3>Specification for implementors</h3>
+     * Implementations must not alter either this object.
+     * Instead, an adjusted copy of the original must be returned.
+     * This provides equivalent, safe behavior for immutable and mutable implementations.
+     * <p>
+     * The default implementation must behave equivalent to this code:
+     * <pre>
+     *  return adjuster.adjustInto(this);
+     * </pre>
+     *
+     * @param adjuster  the adjuster to use, not null
+     * @return an object of the same type with the specified adjustment made, not null
+     * @throws DateTimeException if unable to make the adjustment
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public default Temporal with(TemporalAdjuster adjuster) {
+        return adjuster.adjustInto(this);
+    }
+
+    /**
+     * Returns an object of the same type as this object with the specified field altered.
+     * <p>
+     * This returns a new object based on this one with the value for the specified field changed.
+     * For example, on a {@code LocalDate}, this could be used to set the year, month or day-of-month.
+     * The returned object will have the same observable type as this object.
+     * <p>
+     * In some cases, changing a field is not fully defined. For example, if the target object is
+     * a date representing the 31st January, then changing the month to February would be unclear.
+     * In cases like this, the field is responsible for resolving the result. Typically it will choose
+     * the previous valid date, which would be the last valid day of February in this example.
+     *
+     * <h3>Specification for implementors</h3>
+     * Implementations must check and handle all fields defined in {@link ChronoField}.
+     * If the field is supported, then the adjustment must be performed.
+     * If unsupported, then a {@code DateTimeException} must be thrown.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doWith(Temporal, long)}
+     * passing {@code this} as the first argument.
+     * <p>
+     * Implementations must not alter either this object or the specified temporal object.
+     * Instead, an adjusted copy of the original must be returned.
+     * This provides equivalent, safe behavior for immutable and mutable implementations.
+     *
+     * @param field  the field to set in the result, not null
+     * @param newValue  the new value of the field in the result
+     * @return an object of the same type with the specified field set, not null
+     * @throws DateTimeException if the field cannot be set
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    Temporal with(TemporalField field, long newValue);
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns an object of the same type as this object with an amount added.
+     * <p>
+     * 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}.
+     * <p>
+     * Some example code indicating how and why this method is used:
+     * <pre>
+     *  date = date.plus(period);                      // add a Period instance
+     *  date = date.plus(duration);                    // add a Duration instance
+     *  date = date.plus(MONTHS.between(start, end));  // static import of MONTHS field
+     *  date = date.plus(workingDays(6));              // example user-written workingDays method
+     * </pre>
+     * <p>
+     * Note that calling {@code plus} followed by {@code minus} is not guaranteed to
+     * return the same date-time.
+     *
+     * <h3>Specification for implementors</h3>
+     * Implementations must not alter either this object.
+     * Instead, an adjusted copy of the original must be returned.
+     * This provides equivalent, safe behavior for immutable and mutable implementations.
+     * <p>
+     * The default implementation must behave equivalent to this code:
+     * <pre>
+     *  return adder.addTo(this);
+     * </pre>
+     *
+     * @param adder  the adder to use, not null
+     * @return an object of the same type with the specified adjustment made, not null
+     * @throws DateTimeException if the addition cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public default Temporal plus(TemporalAdder adder) {
+        return adder.addTo(this);
+    }
+
+    /**
+     * Returns an object of the same type as this object with the specified period added.
+     * <p>
+     * This method returns a new object based on this one with the specified period added.
+     * For example, on a {@code LocalDate}, this could be used to add a number of years, months or days.
+     * The returned object will have the same observable type as this object.
+     * <p>
+     * In some cases, changing a field is not fully defined. For example, if the target object is
+     * a date representing the 31st January, then adding one month would be unclear.
+     * In cases like this, the field is responsible for resolving the result. Typically it will choose
+     * the previous valid date, which would be the last valid day of February in this example.
+     * <p>
+     * If the implementation represents a date-time that has boundaries, such as {@code LocalTime},
+     * then the permitted units must include the boundary unit, but no multiples of the boundary unit.
+     * For example, {@code LocalTime} must accept {@code DAYS} but not {@code WEEKS} or {@code MONTHS}.
+     *
+     * <h3>Specification for implementors</h3>
+     * Implementations must check and handle all units defined in {@link ChronoUnit}.
+     * If the unit is supported, then the addition must be performed.
+     * If unsupported, then a {@code DateTimeException} must be thrown.
+     * <p>
+     * If the unit is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.doPlus(Temporal, long)}
+     * passing {@code this} as the first argument.
+     * <p>
+     * Implementations must not alter either this object or the specified temporal object.
+     * Instead, an adjusted copy of the original must be returned.
+     * This provides equivalent, safe behavior for immutable and mutable implementations.
+     *
+     * @param amountToAdd  the amount of the specified unit to add, may be negative
+     * @param unit  the unit of the period to add, not null
+     * @return an object of the same type with the specified period added, not null
+     * @throws DateTimeException if the unit cannot be added
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    Temporal plus(long amountToAdd, TemporalUnit unit);
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns an object of the same type as this object with an amount subtracted.
+     * <p>
+     * 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}.
+     * <p>
+     * Some example code indicating how and why this method is used:
+     * <pre>
+     *  date = date.minus(period);                      // subtract a Period instance
+     *  date = date.minus(duration);                    // subtract a Duration instance
+     *  date = date.minus(MONTHS.between(start, end));  // static import of MONTHS field
+     *  date = date.minus(workingDays(6));              // example user-written workingDays method
+     * </pre>
+     * <p>
+     * Note that calling {@code plus} followed by {@code minus} is not guaranteed to
+     * return the same date-time.
+     *
+     * <h3>Specification for implementors</h3>
+     * Implementations must not alter either this object.
+     * Instead, an adjusted copy of the original must be returned.
+     * This provides equivalent, safe behavior for immutable and mutable implementations.
+     * <p>
+     * The default implementation must behave equivalent to this code:
+     * <pre>
+     *  return subtractor.subtractFrom(this);
+     * </pre>
+     *
+     * @param subtractor  the subtractor to use, not null
+     * @return an object of the same type with the specified adjustment made, not null
+     * @throws DateTimeException if the subtraction cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public default Temporal minus(TemporalSubtractor subtractor) {
+        return subtractor.subtractFrom(this);
+    }
+
+    /**
+     * Returns an object of the same type as this object with the specified period subtracted.
+     * <p>
+     * This method returns a new object based on this one with the specified period subtracted.
+     * For example, on a {@code LocalDate}, this could be used to subtract a number of years, months or days.
+     * The returned object will have the same observable type as this object.
+     * <p>
+     * In some cases, changing a field is not fully defined. For example, if the target object is
+     * a date representing the 31st March, then subtracting one month would be unclear.
+     * In cases like this, the field is responsible for resolving the result. Typically it will choose
+     * the previous valid date, which would be the last valid day of February in this example.
+     * <p>
+     * If the implementation represents a date-time that has boundaries, such as {@code LocalTime},
+     * then the permitted units must include the boundary unit, but no multiples of the boundary unit.
+     * For example, {@code LocalTime} must accept {@code DAYS} but not {@code WEEKS} or {@code MONTHS}.
+     *
+     * <h3>Specification for implementors</h3>
+     * Implementations must behave in a manor equivalent to the default method behavior.
+     * <p>
+     * Implementations must not alter either this object or the specified temporal object.
+     * Instead, an adjusted copy of the original must be returned.
+     * This provides equivalent, safe behavior for immutable and mutable implementations.
+     * <p>
+     * The default implementation must behave equivalent to this code:
+     * <pre>
+     *  return (amountToSubtract == Long.MIN_VALUE ?
+     *      plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
+     * </pre>
+     *
+     * @param amountToSubtract  the amount of the specified unit to subtract, may be negative
+     * @param unit  the unit of the period to subtract, not null
+     * @return an object of the same type with the specified period subtracted, not null
+     * @throws DateTimeException if the unit cannot be subtracted
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public default Temporal minus(long amountToSubtract, TemporalUnit unit) {
+        return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Calculates the period between this temporal and another temporal in
+     * terms of the specified unit.
+     * <p>
+     * This calculates the period between two temporals in terms of a single unit.
+     * The start and end points are {@code this} and the specified temporal.
+     * The result will be negative if the end is before the start.
+     * For example, the period in hours between two temporal objects can be
+     * calculated using {@code startTime.periodUntil(endTime, HOURS)}.
+     * <p>
+     * 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.
+     * <p>
+     * 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:
+     * <pre>
+     *   long period = start.periodUntil(end, HOURS);   // this method
+     *   dateTime.plus(HOURS.between(start, end));      // use in plus/minus
+     * </pre>
+     *
+     * <h3>Specification for implementors</h3>
+     * Implementations must begin by checking to ensure that the input temporal
+     * object is of the same observable type as the implementation.
+     * They must then perform the calculation for all instances of {@link ChronoUnit}.
+     * A {@code DateTimeException} must be thrown for {@code ChronoUnit}
+     * instances that are unsupported.
+     * <p>
+     * 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.
+     * <p>
+     * In summary, implementations must behave in a manner equivalent to this code:
+     * <pre>
+     *  // check input temporal is the same type as this class
+     *  if (unit instanceof ChronoUnit) {
+     *    // if unit is supported, then calculate and return result
+     *    // else throw DateTimeException for unsupported units
+     *  }
+     *  return unit.between(this, endTime).getAmount();
+     * </pre>
+     * <p>
+     * The target object must not be altered by this method.
+     *
+     * @param endTemporal  the end temporal, of the same type as this object, not null
+     * @param unit  the unit to measure the period in, not null
+     * @return the amount of the period between this and the end
+     * @throws DateTimeException if the period cannot be calculated
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    long periodUntil(Temporal endTemporal, TemporalUnit unit);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/TemporalAccessor.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import java.time.DateTimeException;
+import java.time.ZoneId;
+
+/**
+ * Framework-level interface defining read-only access to a temporal object,
+ * such as a date, time, offset or some combination of these.
+ * <p>
+ * This is the base interface type for date, time and offset objects.
+ * It is implemented by those classes that can provide information
+ * as {@linkplain TemporalField fields} or {@linkplain TemporalQuery queries}.
+ * <p>
+ * Most date and time information can be represented as a number.
+ * These are modeled using {@code TemporalField} with the number held using
+ * a {@code long} to handle large values. Year, month and day-of-month are
+ * simple examples of fields, but they also include instant and offsets.
+ * See {@link ChronoField} for the standard set of fields.
+ * <p>
+ * Two pieces of date/time information cannot be represented by numbers,
+ * the {@linkplain Chrono chronology} and the {@linkplain ZoneId time-zone}.
+ * These can be accessed via {@link #query(TemporalQuery) queries} using
+ * the static methods defined on {@link Queries}.
+ * <p>
+ * A sub-interface, {@link Temporal}, extends this definition to one that also
+ * supports adjustment and manipulation on more complete temporal objects.
+ * <p>
+ * This interface is a framework-level interface that should not be widely
+ * used in application code. Instead, applications should create and pass
+ * around instances of concrete types, such as {@code LocalDate}.
+ * There are many reasons for this, part of which is that implementations
+ * of this interface may be in calendar systems other than ISO.
+ * See {@link ChronoLocalDate} for a fuller discussion of the issues.
+ *
+ * <h3>Specification for implementors</h3>
+ * This interface places no restrictions on the mutability of implementations,
+ * however immutability is strongly recommended.
+ *
+ * @since 1.8
+ */
+public interface TemporalAccessor {
+
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if the date-time can be queried for the specified field.
+     * If false, then calling the {@link #range(TemporalField) range} and {@link #get(TemporalField) get}
+     * methods will throw an exception.
+     *
+     * <h3>Specification for implementors</h3>
+     * Implementations must check and handle all fields defined in {@link ChronoField}.
+     * If the field is supported, then true is returned, otherwise false
+     * <p>
+     * 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.
+     * <p>
+     * Implementations must not alter either this object.
+     *
+     * @param field  the field to check, null returns false
+     * @return true if this date-time can be queried for the field, false if not
+     */
+    boolean isSupported(TemporalField field);
+
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * All fields can be expressed as a {@code long} integer.
+     * This method returns an object that describes the valid range for that value.
+     * The value of this temporal object is used to enhance the accuracy of the returned range.
+     * If the date-time cannot return the range, because the field is unsupported or for
+     * some other reason, an exception will be thrown.
+     * <p>
+     * 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.
+     *
+     * <h3>Specification for implementors</h3>
+     * Implementations must check and handle all fields defined in {@link ChronoField}.
+     * If the field is supported, then the range of the field must be returned.
+     * If unsupported, then a {@code DateTimeException} must be thrown.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doRange(TemporalAccessorl)}
+     * passing {@code this} as the argument.
+     * <p>
+     * Implementations must not alter either this object.
+     * <p>
+     * The default implementation must behave equivalent to this code:
+     * <pre>
+     *  if (field instanceof ChronoField) {
+     *    if (isSupported(field)) {
+     *      return field.range();
+     *    }
+     *    throw new DateTimeException("Unsupported field: " + field.getName());
+     *  }
+     *  return field.doRange(this);
+     * </pre>
+     *
+     * @param field  the field to query the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     */
+    public default ValueRange range(TemporalField field) {
+        if (field instanceof ChronoField) {
+            if (isSupported(field)) {
+                return field.range();
+            }
+            throw new DateTimeException("Unsupported field: " + field.getName());
+        }
+        return field.doRange(this);
+    }
+
+    /**
+     * Gets the value of the specified field as an {@code int}.
+     * <p>
+     * This queries the date-time for the value for the specified field.
+     * The returned value will always be within the valid range of values for the field.
+     * If the date-time cannot return the value, because the field is unsupported or for
+     * some other reason, an exception will be thrown.
+     *
+     * <h3>Specification for implementors</h3>
+     * Implementations must check and handle all fields defined in {@link ChronoField}.
+     * If the field is supported and has an {@code int} range, then the value of
+     * the field must be returned.
+     * If unsupported, then a {@code DateTimeException} must be thrown.
+     * <p>
+     * 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.
+     * <p>
+     * Implementations must not alter either this object.
+     * <p>
+     * The default implementation must behave equivalent to this code:
+     * <pre>
+     *  return range(field).checkValidIntValue(getLong(field), field);
+     * </pre>
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field, within the valid range of values
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws DateTimeException if the range of valid values for the field exceeds an {@code int}
+     * @throws DateTimeException if the value is outside the range of valid values for the field
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public default int get(TemporalField field) {
+        return range(field).checkValidIntValue(getLong(field), field);
+    }
+
+    /**
+     * Gets the value of the specified field as a {@code long}.
+     * <p>
+     * This queries the date-time for the value for the specified field.
+     * The returned value may be outside the valid range of values for the field.
+     * If the date-time cannot return the value, because the field is unsupported or for
+     * some other reason, an exception will be thrown.
+     *
+     * <h3>Specification for implementors</h3>
+     * Implementations must check and handle all fields defined in {@link ChronoField}.
+     * If the field is supported, then the value of the field must be returned.
+     * If unsupported, then a {@code DateTimeException} must be thrown.
+     * <p>
+     * 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.
+     * <p>
+     * Implementations must not alter either this object.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    long getLong(TemporalField field);
+
+    /**
+     * Queries this date-time.
+     * <p>
+     * This queries this date-time using the specified query strategy object.
+     * <p>
+     * Queries are a key tool for extracting information from date-times.
+     * They exists to externalize the process of querying, permitting different
+     * approaches, as per the strategy design pattern.
+     * Examples might be a query that checks if the date is the day before February 29th
+     * in a leap year, or calculates the number of days to your next birthday.
+     * <p>
+     * The most common query implementations are method references, such as
+     * {@code LocalDate::from} and {@code ZoneId::from}.
+     * Further implementations are on {@link Queries}.
+     * Queries may also be defined by applications.
+     *
+     * <h3>Specification for implementors</h3>
+     * The default implementation must behave equivalent to this code:
+     * <pre>
+     *  if (query == Queries.zoneId() || query == Queries.chrono() || query == Queries.precision()) {
+     *    return null;
+     *  }
+     *  return query.queryFrom(this);
+     * </pre>
+     * Future versions are permitted to add further queries to the if statement.
+     * <p>
+     * All classes implementing this interface and overriding this method must call
+     * {@code TemporalAccessor.super.query(query)}. JDK classes may avoid calling
+     * super if they provide behavior equivalent to the default behaviour, however
+     * non-JDK classes may not utilize this optimization and must call {@code super}.
+     * <p>
+     * If the implementation can supply a value for one of the queries listed in the
+     * if statement of the default implementation, then it must do so.
+     * For example, an application-defined {@code HourMin} class storing the hour
+     * and minute must override this method as follows:
+     * <pre>
+     *  if (query == Queries.precision()) {
+     *    return MINUTES;
+     *  }
+     *  return TemporalAccessor.super.query(query);
+     * </pre>
+     *
+     * @param <R> the type of the result
+     * @param query  the query to invoke, not null
+     * @return the query result, null may be returned (defined by the query)
+     * @throws DateTimeException if unable to query
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public default <R> R query(TemporalQuery<R> query) {
+        if (query == Queries.zoneId() || query == Queries.chrono() || query == Queries.precision()) {
+            return null;
+        }
+        return query.queryFrom(this);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/TemporalAdder.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import java.time.DateTimeException;
+import java.time.Duration;
+import java.time.Period;
+
+/**
+ * Strategy for adding to a temporal object.
+ * <p>
+ * 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.
+ * <p>
+ * 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)}:
+ * <pre>
+ *   // these two lines are equivalent, but the second approach is recommended
+ *   dateTime = adder.addTo(dateTime);
+ *   dateTime = dateTime.plus(adder);
+ * </pre>
+ * It is recommended to use the second approach, {@code plus(TemporalAdder)},
+ * as it is a lot clearer to read in code.
+ * <p>
+ * The {@link Period} and {@link Duration} classes implement this interface.
+ * Adders may also be defined by applications.
+ *
+ * <h3>Specification for implementors</h3>
+ * 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.
+     * <p>
+     * This adds to the specified temporal object using the logic
+     * encapsulated in the implementing class.
+     * <p>
+     * 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)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   dateTime = adder.addTo(dateTime);
+     *   dateTime = dateTime.plus(adder);
+     * </pre>
+     * It is recommended to use the second approach, {@code plus(TemporalAdder)},
+     * as it is a lot clearer to read in code.
+     *
+     * <h3>Specification for implementors</h3>
+     * 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
+     * <p>
+     * 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.
+     * <p>
+     * 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}.
+     * <p>
+     * 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);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/TemporalAdjuster.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import java.time.DateTimeException;
+
+/**
+ * Strategy for adjusting a temporal object.
+ * <p>
+ * Adjusters are a key tool for modifying temporal objects.
+ * They exist to externalize the process of adjustment, permitting different
+ * approaches, as per the strategy design pattern.
+ * Examples might be an adjuster that sets the date avoiding weekends, or one that
+ * sets the date to the last day of the month.
+ * <p>
+ * There are two equivalent ways of using a {@code TemporalAdjuster}.
+ * The first is to invoke the method on this interface directly.
+ * The second is to use {@link Temporal#with(TemporalAdjuster)}:
+ * <pre>
+ *   // these two lines are equivalent, but the second approach is recommended
+ *   temporal = thisAdjuster.adjustInto(temporal);
+ *   temporal = temporal.with(thisAdjuster);
+ * </pre>
+ * It is recommended to use the second approach, {@code with(TemporalAdjuster)},
+ * as it is a lot clearer to read in code.
+ * <p>
+ * See {@link Adjusters} for a standard set of adjusters, including finding the
+ * last day of the month.
+ * Adjusters may also be defined by applications.
+ *
+ * <h3>Specification for implementors</h3>
+ * This interface places no restrictions on the mutability of implementations,
+ * however immutability is strongly recommended.
+ *
+ * @since 1.8
+ */
+public interface TemporalAdjuster {
+
+    /**
+     * Adjusts the specified temporal object.
+     * <p>
+     * This adjusts the specified temporal object using the logic
+     * encapsulated in the implementing class.
+     * Examples might be an adjuster that sets the date avoiding weekends, or one that
+     * sets the date to the last day of the month.
+     * <p>
+     * There are two equivalent ways of using this method.
+     * The first is to invoke this method directly.
+     * The second is to use {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisAdjuster.adjustInto(temporal);
+     *   temporal = temporal.with(thisAdjuster);
+     * </pre>
+     * It is recommended to use the second approach, {@code with(TemporalAdjuster)},
+     * as it is a lot clearer to read in code.
+     *
+     * <h3>Specification for implementors</h3>
+     * The implementation must take the input object and adjust it.
+     * The implementation defines the logic of the adjustment and is responsible for
+     * documenting that logic. It may use any method on {@code Temporal} to
+     * query the temporal object and perform the adjustment.
+     * The returned object must have the same observable type as the input object
+     * <p>
+     * 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.
+     * <p>
+     * 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}.
+     * <p>
+     * This method may be called from multiple threads in parallel.
+     * It must be thread-safe when invoked.
+     *
+     * @param temporal  the temporal object to adjust, not null
+     * @return an object of the same observable type with the adjustment made, not null
+     * @throws DateTimeException if unable to make the adjustment
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    Temporal adjustInto(Temporal temporal);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/TemporalField.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import java.time.DateTimeException;
+import java.time.format.DateTimeBuilder;
+import java.util.Comparator;
+
+/**
+ * A field of date-time, such as month-of-year or hour-of-minute.
+ * <p>
+ * Date and time is expressed using fields which partition the time-line into something
+ * meaningful for humans. Implementations of this interface represent those fields.
+ * <p>
+ * The most commonly used units are defined in {@link ChronoField}.
+ * Further fields are supplied in {@link ISOFields}, {@link WeekFields} and {@link JulianFields}.
+ * Fields can also be written by application code by implementing this interface.
+ * <p>
+ * The field works using double dispatch. Client code calls methods on a date-time like
+ * {@code LocalDateTime} which check if the field is a {@code ChronoField}.
+ * If it is, then the date-time must handle it.
+ * Otherwise, the method call is re-dispatched to the matching method in this interface.
+ *
+ * <h3>Specification for implementors</h3>
+ * This interface must be implemented with care to ensure other classes operate correctly.
+ * All implementations that can be instantiated must be final, immutable and thread-safe.
+ * It is recommended to use an enum where possible.
+ *
+ * @since 1.8
+ */
+public interface TemporalField extends Comparator<TemporalAccessor> {
+
+    /**
+     * Gets a descriptive name for the field.
+     * <p>
+     * The should be of the format 'BaseOfRange', such as 'MonthOfYear',
+     * unless the field has a range of {@code FOREVER}, when only
+     * the base unit is mentioned, such as 'Year' or 'Era'.
+     *
+     * @return the name, not null
+     */
+    String getName();
+
+    /**
+     * Gets the unit that the field is measured in.
+     * <p>
+     * The unit of the field is the period that varies within the range.
+     * For example, in the field 'MonthOfYear', the unit is 'Months'.
+     * See also {@link #getRangeUnit()}.
+     *
+     * @return the period unit defining the base unit of the field, not null
+     */
+    TemporalUnit getBaseUnit();
+
+    /**
+     * Gets the range that the field is bound by.
+     * <p>
+     * The range of the field is the period that the field varies within.
+     * For example, in the field 'MonthOfYear', the range is 'Years'.
+     * See also {@link #getBaseUnit()}.
+     * <p>
+     * The range is never null. For example, the 'Year' field is shorthand for
+     * 'YearOfForever'. It therefore has a unit of 'Years' and a range of 'Forever'.
+     *
+     * @return the period unit defining the range of the field, not null
+     */
+    TemporalUnit getRangeUnit();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares the value of this field in two temporal objects.
+     * <p>
+     * All fields implement {@link Comparator} on {@link TemporalAccessor}.
+     * This allows a list of date-times to be compared using the value of a field.
+     * For example, you could sort a list of arbitrary temporal objects by the value of
+     * the month-of-year field - {@code Collections.sort(list, MONTH_OF_YEAR)}
+     * <p>
+     * The default implementation must behave equivalent to this code:
+     * <pre>
+     *  return Long.compare(temporal1.getLong(this), temporal2.getLong(this));
+     * </pre>
+     *
+     * @param temporal1  the first temporal object to compare, not null
+     * @param temporal2  the second temporal object to compare, not null
+     * @throws DateTimeException if unable to obtain the value for this field
+     */
+    public default int compare(TemporalAccessor temporal1, TemporalAccessor temporal2) {
+         return Long.compare(temporal1.getLong(this), temporal2.getLong(this));
+    }
+
+    /**
+     * Gets the range of valid values for the field.
+     * <p>
+     * All fields can be expressed as a {@code long} integer.
+     * This method returns an object that describes the valid range for that value.
+     * This method is generally only applicable to the ISO-8601 calendar system.
+     * <p>
+     * Note that the result only describes the minimum and maximum valid values
+     * and it is important not to read too much into them. For example, there
+     * could be values within the range that are invalid for the field.
+     *
+     * @return the range of valid values for the field, not null
+     */
+    ValueRange range();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this field is supported by the temporal object.
+     * <p>
+     * This determines whether the temporal accessor supports this field.
+     * If this returns false, the the temporal cannot be queried for this field.
+     * <p>
+     * There are two equivalent ways of using this method.
+     * The first is to invoke this method directly.
+     * The second is to use {@link TemporalAccessor#isSupported(TemporalField)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisField.doIsSupported(temporal);
+     *   temporal = temporal.isSupported(thisField);
+     * </pre>
+     * It is recommended to use the second approach, {@code isSupported(TemporalField)},
+     * as it is a lot clearer to read in code.
+     * <p>
+     * Implementations should determine whether they are supported using the fields
+     * available in {@link ChronoField}.
+     *
+     * @param temporal  the temporal object to query, not null
+     * @return true if the date-time can be queried for this field, false if not
+     */
+    boolean doIsSupported(TemporalAccessor temporal);
+
+    /**
+     * Get the range of valid values for this field using the temporal object to
+     * refine the result.
+     * <p>
+     * This uses the temporal object to find the range of valid values for the field.
+     * This is similar to {@link #range()}, however this method refines the result
+     * using the temporal. For example, if the field is {@code DAY_OF_MONTH} the
+     * {@code range} method is not accurate as there are four possible month lengths,
+     * 28, 29, 30 and 31 days. Using this method with a date allows the range to be
+     * accurate, returning just one of those four options.
+     * <p>
+     * There are two equivalent ways of using this method.
+     * The first is to invoke this method directly.
+     * The second is to use {@link TemporalAccessor#range(TemporalField)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisField.doRange(temporal);
+     *   temporal = temporal.range(thisField);
+     * </pre>
+     * It is recommended to use the second approach, {@code range(TemporalField)},
+     * as it is a lot clearer to read in code.
+     * <p>
+     * Implementations should perform any queries or calculations using the fields
+     * available in {@link ChronoField}.
+     * If the field is not supported a {@code DateTimeException} must be thrown.
+     *
+     * @param temporal  the temporal object used to refine the result, not null
+     * @return the range of valid values for this field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     */
+    ValueRange doRange(TemporalAccessor temporal);
+
+    /**
+     * Gets the value of this field from the specified temporal object.
+     * <p>
+     * This queries the temporal object for the value of this field.
+     * <p>
+     * There are two equivalent ways of using this method.
+     * The first is to invoke this method directly.
+     * The second is to use {@link TemporalAccessor#getLong(TemporalField)}
+     * (or {@link TemporalAccessor#get(TemporalField)}):
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisField.doGet(temporal);
+     *   temporal = temporal.getLong(thisField);
+     * </pre>
+     * It is recommended to use the second approach, {@code getLong(TemporalField)},
+     * as it is a lot clearer to read in code.
+     * <p>
+     * Implementations should perform any queries or calculations using the fields
+     * available in {@link ChronoField}.
+     * If the field is not supported a {@code DateTimeException} must be thrown.
+     *
+     * @param temporal  the temporal object to query, not null
+     * @return the value of this field, not null
+     * @throws DateTimeException if a value for the field cannot be obtained
+     */
+    long doGet(TemporalAccessor temporal);
+
+    /**
+     * Returns a copy of the specified temporal object with the value of this field set.
+     * <p>
+     * This returns a new temporal object based on the specified one with the value for
+     * this field changed. For example, on a {@code LocalDate}, this could be used to
+     * set the year, month or day-of-month.
+     * The returned object has the same observable type as the specified object.
+     * <p>
+     * In some cases, changing a field is not fully defined. For example, if the target object is
+     * a date representing the 31st January, then changing the month to February would be unclear.
+     * In cases like this, the implementation is responsible for resolving the result.
+     * Typically it will choose the previous valid date, which would be the last valid
+     * day of February in this example.
+     * <p>
+     * There are two equivalent ways of using this method.
+     * The first is to invoke this method directly.
+     * The second is to use {@link Temporal#with(TemporalField, long)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisField.doWith(temporal);
+     *   temporal = temporal.with(thisField);
+     * </pre>
+     * It is recommended to use the second approach, {@code with(TemporalField)},
+     * as it is a lot clearer to read in code.
+     * <p>
+     * Implementations should perform any queries or calculations using the fields
+     * available in {@link ChronoField}.
+     * If the field is not supported a {@code DateTimeException} must be thrown.
+     * <p>
+     * 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 <R>  the type of the Temporal object
+     * @param temporal the temporal object to adjust, not null
+     * @param newValue the new value of the field
+     * @return the adjusted temporal object, not null
+     * @throws DateTimeException if the field cannot be set
+     */
+    <R extends Temporal> R doWith(R temporal, long newValue);
+
+    /**
+     * Resolves the date/time information in the builder
+     * <p>
+     * This method is invoked during the resolve of the builder.
+     * Implementations should combine the associated field with others to form
+     * objects like {@code LocalDate}, {@code LocalTime} and {@code LocalDateTime}
+     *
+     * @param builder  the builder to resolve, not null
+     * @param value  the value of the associated field
+     * @return true if builder has been changed, false otherwise
+     * @throws DateTimeException if unable to resolve
+     */
+    boolean resolve(DateTimeBuilder builder, long value);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/TemporalQuery.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import java.time.DateTimeException;
+
+/**
+ * Strategy for querying a temporal object.
+ * <p>
+ * Queries are a key tool for extracting information from temporal objects.
+ * They exist to externalize the process of querying, permitting different
+ * approaches, as per the strategy design pattern.
+ * Examples might be a query that checks if the date is the day before February 29th
+ * in a leap year, or calculates the number of days to your next birthday.
+ * <p>
+ * The {@link TemporalField} interface provides another mechanism for querying
+ * temporal objects. That interface is limited to returning a {@code long}.
+ * By contrast, queries can return any type.
+ * <p>
+ * There are two equivalent ways of using a {@code TemporalQuery}.
+ * The first is to invoke the method on this interface directly.
+ * The second is to use {@link TemporalAccessor#query(TemporalQuery)}:
+ * <pre>
+ *   // these two lines are equivalent, but the second approach is recommended
+ *   temporal = thisQuery.queryFrom(temporal);
+ *   temporal = temporal.query(thisQuery);
+ * </pre>
+ * It is recommended to use the second approach, {@code query(TemporalQuery)},
+ * as it is a lot clearer to read in code.
+ * <p>
+ * The most common implementations are method references, such as
+ * {@code LocalDate::from} and {@code ZoneId::from}.
+ * Further implementations are on {@link Queries}.
+ * Queries may also be defined by applications.
+ *
+ * <h3>Specification for implementors</h3>
+ * This interface places no restrictions on the mutability of implementations,
+ * however immutability is strongly recommended.
+ *
+ * @since 1.8
+ */
+public interface TemporalQuery<R> {
+
+    /**
+     * Queries the specified temporal object.
+     * <p>
+     * This queries the specified temporal object to return an object using the logic
+     * encapsulated in the implementing class.
+     * Examples might be a query that checks if the date is the day before February 29th
+     * in a leap year, or calculates the number of days to your next birthday.
+     * <p>
+     * There are two equivalent ways of using this method.
+     * The first is to invoke this method directly.
+     * The second is to use {@link TemporalAccessor#query(TemporalQuery)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisQuery.queryFrom(temporal);
+     *   temporal = temporal.query(thisQuery);
+     * </pre>
+     * It is recommended to use the second approach, {@code query(TemporalQuery)},
+     * as it is a lot clearer to read in code.
+     *
+     * <h3>Specification for implementors</h3>
+     * The implementation must take the input object and query it.
+     * The implementation defines the logic of the query and is responsible for
+     * documenting that logic.
+     * It may use any method on {@code TemporalAccessor} to determine the result.
+     * The input object must not be altered.
+     * <p>
+     * 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}.
+     * <p>
+     * This method may be called from multiple threads in parallel.
+     * It must be thread-safe when invoked.
+     *
+     * @param temporal  the temporal object to query, not null
+     * @return the queried value, may return null to indicate not found
+     * @throws DateTimeException if unable to query
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    R queryFrom(TemporalAccessor temporal);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/TemporalSubtractor.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import java.time.DateTimeException;
+import java.time.Duration;
+import java.time.Period;
+
+/**
+ * Strategy for subtracting from a temporal object.
+ * <p>
+ * 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.
+ * <p>
+ * 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)}:
+ * <pre>
+ *   // these two lines are equivalent, but the second approach is recommended
+ *   dateTime = subtractor.subtractFrom(dateTime);
+ *   dateTime = dateTime.minus(subtractor);
+ * </pre>
+ * It is recommended to use the second approach, {@code minus(TemporalSubtractor)},
+ * as it is a lot clearer to read in code.
+ * <p>
+ * The {@link Period} and {@link Duration} classes implement this interface.
+ * Subtractors may also be defined by applications.
+ *
+ * <h3>Specification for implementors</h3>
+ * 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.
+     * <p>
+     * This adds to the specified temporal object using the logic
+     * encapsulated in the implementing class.
+     * <p>
+     * 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)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   dateTime = subtractor.subtractFrom(dateTime);
+     *   dateTime = dateTime.minus(subtractor);
+     * </pre>
+     * It is recommended to use the second approach, {@code minus(TemporalSubtractor)},
+     * as it is a lot clearer to read in code.
+     *
+     * <h3>Specification for implementors</h3>
+     * 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
+     * <p>
+     * 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.
+     * <p>
+     * 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}.
+     * <p>
+     * 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);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/TemporalUnit.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import java.time.DateTimeException;
+import java.time.Duration;
+import java.time.Period;
+
+/**
+ * A unit of date-time, such as Days or Hours.
+ * <p>
+ * Measurement of time is built on units, such as years, months, days, hours, minutes and seconds.
+ * Implementations of this interface represent those units.
+ * <p>
+ * An instance of this interface represents the unit itself, rather than an amount of the unit.
+ * See {@link Period} for a class that represents an amount in terms of the common units.
+ * <p>
+ * The most commonly used units are defined in {@link ChronoUnit}.
+ * Further units are supplied in {@link ISOFields}.
+ * Units can also be written by application code by implementing this interface.
+ * <p>
+ * The unit works using double dispatch. Client code calls methods on a date-time like
+ * {@code LocalDateTime} which check if the unit is a {@code ChronoUnit}.
+ * If it is, then the date-time must handle it.
+ * Otherwise, the method call is re-dispatched to the matching method in this interface.
+ *
+ * <h3>Specification for implementors</h3>
+ * This interface must be implemented with care to ensure other classes operate correctly.
+ * All implementations that can be instantiated must be final, immutable and thread-safe.
+ * It is recommended to use an enum where possible.
+ *
+ * @since 1.8
+ */
+public interface TemporalUnit {
+
+    /**
+     * Gets a descriptive name for the unit.
+     * <p>
+     * This should be in the plural and upper-first camel case, such as 'Days' or 'Minutes'.
+     *
+     * @return the name, not null
+     */
+    String getName();
+
+    /**
+     * Gets the duration of this unit, which may be an estimate.
+     * <p>
+     * All units return a duration measured in standard nanoseconds from this method.
+     * For example, an hour has a duration of {@code 60 * 60 * 1,000,000,000ns}.
+     * <p>
+     * Some units may return an accurate duration while others return an estimate.
+     * For example, days have an estimated duration due to the possibility of
+     * daylight saving time changes.
+     * To determine if the duration is an estimate, use {@link #isDurationEstimated()}.
+     *
+     * @return the duration of this unit, which may be an estimate, not null
+     */
+    Duration getDuration();
+
+    /**
+     * Checks if the duration of the unit is an estimate.
+     * <p>
+     * All units have a duration, however the duration is not always accurate.
+     * For example, days have an estimated duration due to the possibility of
+     * daylight saving time changes.
+     * This method returns true if the duration is an estimate and false if it is
+     * accurate. Note that accurate/estimated ignores leap seconds.
+     *
+     * @return true if the duration is estimated, false if accurate
+     */
+    boolean isDurationEstimated();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this unit is supported by the specified temporal object.
+     * <p>
+     * This checks that the implementing date-time can add/subtract this unit.
+     * This can be used to avoid throwing an exception.
+     * <p>
+     * This default implementation derives the value using
+     * {@link Temporal#plus(long, TemporalUnit)}.
+     *
+     * @param temporal  the temporal object to check, not null
+     * @return true if the unit is supported
+     */
+    public default boolean isSupported(Temporal temporal) {
+        try {
+            temporal.plus(1, this);
+            return true;
+        } catch (RuntimeException ex) {
+            try {
+                temporal.plus(-1, this);
+                return true;
+            } catch (RuntimeException ex2) {
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Returns a copy of the specified temporal object with the specified period added.
+     * <p>
+     * The period added is a multiple of this unit. For example, this method
+     * could be used to add "3 days" to a date by calling this method on the
+     * instance representing "days", passing the date and the period "3".
+     * The period to be added may be negative, which is equivalent to subtraction.
+     * <p>
+     * There are two equivalent ways of using this method.
+     * The first is to invoke this method directly.
+     * The second is to use {@link Temporal#plus(long, TemporalUnit)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisUnit.doPlus(temporal);
+     *   temporal = temporal.plus(thisUnit);
+     * </pre>
+     * It is recommended to use the second approach, {@code plus(TemporalUnit)},
+     * as it is a lot clearer to read in code.
+     * <p>
+     * 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.
+     * <p>
+     * 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 <R>  the type of the Temporal object
+     * @param dateTime  the temporal object to adjust, not null
+     * @param periodToAdd  the period of this unit to add, positive or negative
+     * @return the adjusted temporal object, not null
+     * @throws DateTimeException if the period cannot be added
+     */
+    <R extends Temporal> R doPlus(R dateTime, long periodToAdd);
+
+    //-----------------------------------------------------------------------
+    /**
+     * Calculates the period in terms of this unit between two temporal objects of the same type.
+     * <p>
+     * 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.
+     * <p>
+     * The result can be queried for the {@link SimplePeriod#getAmount() amount}, the
+     * {@link SimplePeriod#getUnit() unit} and used directly in addition/subtraction:
+     * <pre>
+     *  date = date.minus(MONTHS.between(start, end));
+     * </pre>
+     *
+     * @param <R>  the type of the Temporal object; the two date-times must be of the same type
+     * @param dateTime1  the base temporal object, not null
+     * @param dateTime2  the other temporal object, not null
+     * @return the period between datetime1 and datetime2 in terms of this unit;
+     *      positive if datetime2 is later than datetime1, not null
+     */
+    <R extends Temporal> SimplePeriod between(R dateTime1, R dateTime2);
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this unit as a {@code String} using the name.
+     *
+     * @return the name of this unit, not null
+     */
+    @Override
+    String toString();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/ValueRange.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,396 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import java.io.Serializable;
+import java.time.DateTimeException;
+
+/**
+ * The range of valid values for a date-time field.
+ * <p>
+ * All {@link TemporalField} instances have a valid range of values.
+ * For example, the ISO day-of-month runs from 1 to somewhere between 28 and 31.
+ * This class captures that valid range.
+ * <p>
+ * It is important to be aware of the limitations of this class.
+ * Only the minimum and maximum values are provided.
+ * It is possible for there to be invalid values within the outer range.
+ * For example, a weird field may have valid values of 1, 2, 4, 6, 7, thus
+ * have a range of '1 - 7', despite that fact that values 3 and 5 are invalid.
+ * <p>
+ * Instances of this class are not tied to a specific field.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class ValueRange implements Serializable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -7317881728594519368L;
+
+    /**
+     * The smallest minimum value.
+     */
+    private final long minSmallest;
+    /**
+     * The largest minimum value.
+     */
+    private final long minLargest;
+    /**
+     * The smallest maximum value.
+     */
+    private final long maxSmallest;
+    /**
+     * The largest maximum value.
+     */
+    private final long maxLargest;
+
+    /**
+     * Obtains a fixed value range.
+     * <p>
+     * This factory obtains a range where the minimum and maximum values are fixed.
+     * For example, the ISO month-of-year always runs from 1 to 12.
+     *
+     * @param min  the minimum value
+     * @param max  the maximum value
+     * @return the ValueRange for min, max, not null
+     * @throws IllegalArgumentException if the minimum is greater than the maximum
+     */
+    public static ValueRange of(long min, long max) {
+        if (min > max) {
+            throw new IllegalArgumentException("Minimum value must be less than maximum value");
+        }
+        return new ValueRange(min, min, max, max);
+    }
+
+    /**
+     * Obtains a variable value range.
+     * <p>
+     * This factory obtains a range where the minimum value is fixed and the maximum value may vary.
+     * For example, the ISO day-of-month always starts at 1, but ends between 28 and 31.
+     *
+     * @param min  the minimum value
+     * @param maxSmallest  the smallest maximum value
+     * @param maxLargest  the largest maximum value
+     * @return the ValueRange for min, smallest max, largest max, not null
+     * @throws IllegalArgumentException if
+     *     the minimum is greater than the smallest maximum,
+     *  or the smallest maximum is greater than the largest maximum
+     */
+    public static ValueRange of(long min, long maxSmallest, long maxLargest) {
+        return of(min, min, maxSmallest, maxLargest);
+    }
+
+    /**
+     * Obtains a fully variable value range.
+     * <p>
+     * This factory obtains a range where both the minimum and maximum value may vary.
+     *
+     * @param minSmallest  the smallest minimum value
+     * @param minLargest  the largest minimum value
+     * @param maxSmallest  the smallest maximum value
+     * @param maxLargest  the largest maximum value
+     * @return the ValueRange for smallest min, largest min, smallest max, largest max, not null
+     * @throws IllegalArgumentException if
+     *     the smallest minimum is greater than the smallest maximum,
+     *  or the smallest maximum is greater than the largest maximum
+     *  or the largest minimum is greater than the largest maximum
+     */
+    public static ValueRange of(long minSmallest, long minLargest, long maxSmallest, long maxLargest) {
+        if (minSmallest > minLargest) {
+            throw new IllegalArgumentException("Smallest minimum value must be less than largest minimum value");
+        }
+        if (maxSmallest > maxLargest) {
+            throw new IllegalArgumentException("Smallest maximum value must be less than largest maximum value");
+        }
+        if (minLargest > maxLargest) {
+            throw new IllegalArgumentException("Minimum value must be less than maximum value");
+        }
+        return new ValueRange(minSmallest, minLargest, maxSmallest, maxLargest);
+    }
+
+    /**
+     * Restrictive constructor.
+     *
+     * @param minSmallest  the smallest minimum value
+     * @param minLargest  the largest minimum value
+     * @param maxSmallest  the smallest minimum value
+     * @param maxLargest  the largest minimum value
+     */
+    private ValueRange(long minSmallest, long minLargest, long maxSmallest, long maxLargest) {
+        this.minSmallest = minSmallest;
+        this.minLargest = minLargest;
+        this.maxSmallest = maxSmallest;
+        this.maxLargest = maxLargest;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Is the value range fixed and fully known.
+     * <p>
+     * For example, the ISO day-of-month runs from 1 to between 28 and 31.
+     * Since there is uncertainty about the maximum value, the range is not fixed.
+     * However, for the month of January, the range is always 1 to 31, thus it is fixed.
+     *
+     * @return true if the set of values is fixed
+     */
+    public boolean isFixed() {
+        return minSmallest == minLargest && maxSmallest == maxLargest;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the minimum value that the field can take.
+     * <p>
+     * For example, the ISO day-of-month always starts at 1.
+     * The minimum is therefore 1.
+     *
+     * @return the minimum value for this field
+     */
+    public long getMinimum() {
+        return minSmallest;
+    }
+
+    /**
+     * Gets the largest possible minimum value that the field can take.
+     * <p>
+     * For example, the ISO day-of-month always starts at 1.
+     * The largest minimum is therefore 1.
+     *
+     * @return the largest possible minimum value for this field
+     */
+    public long getLargestMinimum() {
+        return minLargest;
+    }
+
+    /**
+     * Gets the smallest possible maximum value that the field can take.
+     * <p>
+     * For example, the ISO day-of-month runs to between 28 and 31 days.
+     * The smallest maximum is therefore 28.
+     *
+     * @return the smallest possible maximum value for this field
+     */
+    public long getSmallestMaximum() {
+        return maxSmallest;
+    }
+
+    /**
+     * Gets the maximum value that the field can take.
+     * <p>
+     * For example, the ISO day-of-month runs to between 28 and 31 days.
+     * The maximum is therefore 31.
+     *
+     * @return the maximum value for this field
+     */
+    public long getMaximum() {
+        return maxLargest;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if all values in the range fit in an {@code int}.
+     * <p>
+     * This checks that all valid values are within the bounds of an {@code int}.
+     * <p>
+     * For example, the ISO month-of-year has values from 1 to 12, which fits in an {@code int}.
+     * By comparison, ISO nano-of-day runs from 1 to 86,400,000,000,000 which does not fit in an {@code int}.
+     * <p>
+     * This implementation uses {@link #getMinimum()} and {@link #getMaximum()}.
+     *
+     * @return true if a valid value always fits in an {@code int}
+     */
+    public boolean isIntValue() {
+        return getMinimum() >= Integer.MIN_VALUE && getMaximum() <= Integer.MAX_VALUE;
+    }
+
+    /**
+     * Checks if the value is within the valid range.
+     * <p>
+     * This checks that the value is within the stored range of values.
+     *
+     * @param value  the value to check
+     * @return true if the value is valid
+     */
+    public boolean isValidValue(long value) {
+        return (value >= getMinimum() && value <= getMaximum());
+    }
+
+    /**
+     * Checks if the value is within the valid range and that all values
+     * in the range fit in an {@code int}.
+     * <p>
+     * This method combines {@link #isIntValue()} and {@link #isValidValue(long)}.
+     *
+     * @param value  the value to check
+     * @return true if the value is valid and fits in an {@code int}
+     */
+    public boolean isValidIntValue(long value) {
+        return isIntValue() && isValidValue(value);
+    }
+
+    /**
+     * Checks that the specified value is valid.
+     * <p>
+     * This validates that the value is within the valid range of values.
+     * The field is only used to improve the error message.
+     *
+     * @param value  the value to check
+     * @param field  the field being checked, may be null
+     * @return the value that was passed in
+     * @see #isValidValue(long)
+     */
+    public long checkValidValue(long value, TemporalField field) {
+        if (isValidValue(value) == false) {
+            if (field != null) {
+                throw new DateTimeException("Invalid value for " + field.getName() + " (valid values " + this + "): " + value);
+            } else {
+                throw new DateTimeException("Invalid value (valid values " + this + "): " + value);
+            }
+        }
+        return value;
+    }
+
+    /**
+     * Checks that the specified value is valid and fits in an {@code int}.
+     * <p>
+     * This validates that the value is within the valid range of values and that
+     * all valid values are within the bounds of an {@code int}.
+     * The field is only used to improve the error message.
+     *
+     * @param value  the value to check
+     * @param field  the field being checked, may be null
+     * @return the value that was passed in
+     * @see #isValidIntValue(long)
+     */
+    public int checkValidIntValue(long value, TemporalField field) {
+        if (isValidIntValue(value) == false) {
+            throw new DateTimeException("Invalid int value for " + field.getName() + ": " + value);
+        }
+        return (int) value;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this range is equal to another range.
+     * <p>
+     * The comparison is based on the four values, minimum, largest minimum,
+     * smallest maximum and maximum.
+     * Only objects of type {@code ValueRange} are compared, other types return false.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other range
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (obj instanceof ValueRange) {
+            ValueRange other = (ValueRange) obj;
+           return minSmallest == other.minSmallest && minLargest == other.minLargest &&
+                   maxSmallest == other.maxSmallest && maxLargest == other.maxLargest;
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this range.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        long hash = minSmallest + minLargest << 16 + minLargest >> 48 + maxSmallest << 32 +
+            maxSmallest >> 32 + maxLargest << 48 + maxLargest >> 16;
+        return (int) (hash ^ (hash >>> 32));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this range as a {@code String}.
+     * <p>
+     * The format will be '{min}/{largestMin} - {smallestMax}/{max}',
+     * where the largestMin or smallestMax sections may be omitted, together
+     * with associated slash, if they are the same as the min or max.
+     *
+     * @return a string representation of this range, not null
+     */
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder();
+        buf.append(minSmallest);
+        if (minSmallest != minLargest) {
+            buf.append('/').append(minLargest);
+        }
+        buf.append(" - ").append(maxSmallest);
+        if (maxSmallest != maxLargest) {
+            buf.append('/').append(maxLargest);
+        }
+        return buf.toString();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/WeekFields.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,663 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import java.io.InvalidObjectException;
+import java.io.Serializable;
+import java.time.DayOfWeek;
+import java.time.format.DateTimeBuilder;
+import java.util.GregorianCalendar;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * Localized definitions of the day-of-week, week-of-month and week-of-year fields.
+ * <p>
+ * A standard week is seven days long, but cultures have different definitions for some
+ * other aspects of a week. This class represents the definition of the week, for the
+ * purpose of providing {@link TemporalField} instances.
+ * <p>
+ * WeekFields provides three fields,
+ * {@link #dayOfWeek()}, {@link #weekOfMonth()}, and {@link #weekOfYear()}
+ * that provide access to the values from any {@linkplain Temporal temporal object}.
+ * <p>
+ * The computations for day-of-week, week-of-month, and week-of-year are based
+ * on the  {@linkplain ChronoField#YEAR proleptic-year},
+ * {@linkplain ChronoField#MONTH_OF_YEAR month-of-year},
+ * {@linkplain ChronoField#DAY_OF_MONTH day-of-month}, and
+ * {@linkplain ChronoField#DAY_OF_WEEK ISO day-of-week} which are based on the
+ * {@linkplain ChronoField#EPOCH_DAY epoch-day} and the chronology.
+ * The values may not be aligned with the {@linkplain ChronoField#YEAR_OF_ERA year-of-Era}
+ * depending on the Chronology.
+ * <p>A week is defined by:
+ * <ul>
+ * <li>The first day-of-week.
+ * For example, the ISO-8601 standard considers Monday to be the first day-of-week.
+ * <li>The minimal number of days in the first week.
+ * For example, the ISO-08601 standard counts the first week as needing at least 4 days.
+ * </ul><p>
+ * Together these two values allow a year or month to be divided into weeks.
+ * <p>
+ * <h3>Week of Month</h3>
+ * One field is used: week-of-month.
+ * The calculation ensures that weeks never overlap a month boundary.
+ * The month is divided into periods where each period starts on the defined first day-of-week.
+ * The earliest period is referred to as week 0 if it has less than the minimal number of days
+ * and week 1 if it has at least the minimal number of days.
+ * <p>
+ * <table cellpadding="0" cellspacing="3" border="0" style="text-align: left; width: 50%;">
+ * <caption>Examples of WeekFields</caption>
+ * <tr><th>Date</th><td>Day-of-week</td>
+ *  <td>First day: Monday<br>Minimal days: 4</td><td>First day: Monday<br>Minimal days: 5</td></tr>
+ * <tr><th>2008-12-31</th><td>Wednesday</td>
+ *  <td>Week 5 of December 2008</td><td>Week 5 of December 2008</td></tr>
+ * <tr><th>2009-01-01</th><td>Thursday</td>
+ *  <td>Week 1 of January 2009</td><td>Week 0 of January 2009</td></tr>
+ * <tr><th>2009-01-04</th><td>Sunday</td>
+ *  <td>Week 1 of January 2009</td><td>Week 0 of January 2009</td></tr>
+ * <tr><th>2009-01-05</th><td>Monday</td>
+ *  <td>Week 2 of January 2009</td><td>Week 1 of January 2009</td></tr>
+ * </table>
+ * <p>
+ * <h3>Week of Year</h3>
+ * One field is used: week-of-year.
+ * The calculation ensures that weeks never overlap a year boundary.
+ * The year is divided into periods where each period starts on the defined first day-of-week.
+ * The earliest period is referred to as week 0 if it has less than the minimal number of days
+ * and week 1 if it has at least the minimal number of days.
+ * <p>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class WeekFields implements Serializable {
+    // implementation notes
+    // querying week-of-month or week-of-year should return the week value bound within the month/year
+    // however, setting the week value should be lenient (use plus/minus weeks)
+    // allow week-of-month outer range [0 to 5]
+    // allow week-of-year outer range [0 to 53]
+    // this is because callers shouldn't be expected to know the details of validity
+
+    /**
+     * The cache of rules by firstDayOfWeek plus minimalDays.
+     * Initialized first to be available for definition of ISO, etc.
+     */
+    private static final ConcurrentMap<String, WeekFields> CACHE = new ConcurrentHashMap<>(4, 0.75f, 2);
+
+    /**
+     * The ISO-8601 definition, where a week starts on Monday and the first week
+     * has a minimum of 4 days.
+     * <p>
+     * The ISO-8601 standard defines a calendar system based on weeks.
+     * It uses the week-based-year and week-of-week-based-year concepts to split
+     * up the passage of days instead of the standard year/month/day.
+     * <p>
+     * Note that the first week may start in the previous calendar year.
+     * Note also that the first few days of a calendar year may be in the
+     * week-based-year corresponding to the previous calendar year.
+     */
+    public static final WeekFields ISO = new WeekFields(DayOfWeek.MONDAY, 4);
+
+    /**
+     * The common definition of a week that starts on Sunday.
+     * <p>
+     * Defined as starting on Sunday and with a minimum of 1 day in the month.
+     * This week definition is in use in the US and other European countries.
+     *
+     */
+    public static final WeekFields SUNDAY_START = WeekFields.of(DayOfWeek.SUNDAY, 1);
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -1177360819670808121L;
+
+    /**
+     * The first day-of-week.
+     */
+    private final DayOfWeek firstDayOfWeek;
+    /**
+     * The minimal number of days in the first week.
+     */
+    private final int minimalDays;
+
+    /**
+     * The field used to access the computed DayOfWeek.
+     */
+    private transient final TemporalField dayOfWeek = ComputedDayOfField.ofDayOfWeekField(this);
+
+    /**
+     * The field used to access the computed WeekOfMonth.
+     */
+    private transient final TemporalField weekOfMonth = ComputedDayOfField.ofWeekOfMonthField(this);
+
+    /**
+     * The field used to access the computed WeekOfYear.
+     */
+    private transient final TemporalField weekOfYear = ComputedDayOfField.ofWeekOfYearField(this);
+
+    /**
+     * Obtains an instance of {@code WeekFields} appropriate for a locale.
+     * <p>
+     * This will look up appropriate values from the provider of localization data.
+     *
+     * @param locale  the locale to use, not null
+     * @return the week-definition, not null
+     */
+    public static WeekFields of(Locale locale) {
+        Objects.requireNonNull(locale, "locale");
+        locale = new Locale(locale.getLanguage(), locale.getCountry());  // elminate variants
+
+        // obtain these from GregorianCalendar for now
+        // TODO: consider getting them directly from the spi
+        GregorianCalendar gcal = new GregorianCalendar(locale);
+        int calDow = gcal.getFirstDayOfWeek();
+        DayOfWeek dow = DayOfWeek.SUNDAY.plus(calDow - 1);
+        int minDays = gcal.getMinimalDaysInFirstWeek();
+        return WeekFields.of(dow, minDays);
+    }
+
+    /**
+     * Obtains an instance of {@code WeekFields} from the first day-of-week and minimal days.
+     * <p>
+     * The first day-of-week defines the ISO {@code DayOfWeek} that is day 1 of the week.
+     * The minimal number of days in the first week defines how many days must be present
+     * in a month or year, starting from the first day-of-week, before the week is counted
+     * as the first week. A value of 1 will count the first day of the month or year as part
+     * of the first week, whereas a value of 7 will require the whole seven days to be in
+     * the new month or year.
+     * <p>
+     * WeekFields instances are singletons; for each unique combination
+     * of {@code firstDayOfWeek} and {@code minimalDaysInFirstWeek} the
+     * the same instance will be returned.
+     *
+     * @param firstDayOfWeek  the first day of the week, not null
+     * @param minimalDaysInFirstWeek  the minimal number of days in the first week, from 1 to 7
+     * @return the week-definition, not null
+     * @throws IllegalArgumentException if the minimal days value is less than one
+     *      or greater than 7
+     */
+    public static WeekFields of(DayOfWeek firstDayOfWeek, int minimalDaysInFirstWeek) {
+        String key = firstDayOfWeek.toString() + minimalDaysInFirstWeek;
+        WeekFields rules = CACHE.get(key);
+        if (rules == null) {
+            rules = new WeekFields(firstDayOfWeek, minimalDaysInFirstWeek);
+            CACHE.putIfAbsent(key, rules);
+            rules = CACHE.get(key);
+        }
+        return rules;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Creates an instance of the definition.
+     *
+     * @param firstDayOfWeek  the first day of the week, not null
+     * @param minimalDaysInFirstWeek  the minimal number of days in the first week, from 1 to 7
+     * @throws IllegalArgumentException if the minimal days value is invalid
+     */
+    private WeekFields(DayOfWeek firstDayOfWeek, int minimalDaysInFirstWeek) {
+        Objects.requireNonNull(firstDayOfWeek, "firstDayOfWeek");
+        if (minimalDaysInFirstWeek < 1 || minimalDaysInFirstWeek > 7) {
+            throw new IllegalArgumentException("Minimal number of days is invalid");
+        }
+        this.firstDayOfWeek = firstDayOfWeek;
+        this.minimalDays = minimalDaysInFirstWeek;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Return the singleton WeekFields associated with the
+     * {@code firstDayOfWeek} and {@code minimalDays}.
+     * @return the singleton WeekFields for the firstDayOfWeek and minimalDays.
+     * @throws InvalidObjectException if the serialized object has invalid
+     *     values for firstDayOfWeek or minimalDays.
+     */
+    private Object readResolve() throws InvalidObjectException {
+        try {
+            return WeekFields.of(firstDayOfWeek, minimalDays);
+        } catch (IllegalArgumentException iae) {
+            throw new InvalidObjectException("Invalid serialized WeekFields: "
+                    + iae.getMessage());
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the first day-of-week.
+     * <p>
+     * The first day-of-week varies by culture.
+     * For example, the US uses Sunday, while France and the ISO-8601 standard use Monday.
+     * This method returns the first day using the standard {@code DayOfWeek} enum.
+     *
+     * @return the first day-of-week, not null
+     */
+    public DayOfWeek getFirstDayOfWeek() {
+        return firstDayOfWeek;
+    }
+
+    /**
+     * Gets the minimal number of days in the first week.
+     * <p>
+     * The number of days considered to define the first week of a month or year
+     * varies by culture.
+     * For example, the ISO-8601 requires 4 days (more than half a week) to
+     * be present before counting the first week.
+     *
+     * @return the minimal number of days in the first week of a month or year, from 1 to 7
+     */
+    public int getMinimalDaysInFirstWeek() {
+        return minimalDays;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a field to access the day of week,
+     * computed based on this WeekFields.
+     * <p>
+     * The days of week are numbered from 1 to 7.
+     * Day number 1 is the {@link #getFirstDayOfWeek() first day-of-week}.
+     *
+     * @return the field for day-of-week using this week definition, not null
+     */
+    public TemporalField dayOfWeek() {
+        return dayOfWeek;
+    }
+
+    /**
+     * Returns a field to access the week of month,
+     * computed based on this WeekFields.
+     * <p>
+     * This represents concept of the count of weeks within the month where weeks
+     * start on a fixed day-of-week, such as Monday.
+     * This field is typically used with {@link WeekFields#dayOfWeek()}.
+     * <p>
+     * Week one (1) is the week starting on the {@link WeekFields#getFirstDayOfWeek}
+     * where there are at least {@link WeekFields#getMinimalDaysInFirstWeek()} days in the month.
+     * Thus, week one may start up to {@code minDays} days before the start of the month.
+     * If the first week starts after the start of the month then the period before is week zero (0).
+     * <p>
+     * For example:<br>
+     * - if the 1st day of the month is a Monday, week one starts on the 1st and there is no week zero<br>
+     * - if the 2nd day of the month is a Monday, week one starts on the 2nd and the 1st is in week zero<br>
+     * - if the 4th day of the month is a Monday, week one starts on the 4th and the 1st to 3rd is in week zero<br>
+     * - if the 5th day of the month is a Monday, week two starts on the 5th and the 1st to 4th is in week one<br>
+     * <p>
+     * This field can be used with any calendar system.
+     * @return a TemporalField to access the WeekOfMonth, not null
+     */
+    public TemporalField weekOfMonth() {
+        return weekOfMonth;
+    }
+
+    /**
+     * Returns a field to access the week of year,
+     * computed based on this WeekFields.
+     * <p>
+     * This represents concept of the count of weeks within the year where weeks
+     * start on a fixed day-of-week, such as Monday.
+     * This field is typically used with {@link WeekFields#dayOfWeek()}.
+     * <p>
+     * Week one(1) is the week starting on the {@link WeekFields#getFirstDayOfWeek}
+     * where there are at least {@link WeekFields#getMinimalDaysInFirstWeek()} days in the month.
+     * Thus, week one may start up to {@code minDays} days before the start of the year.
+     * If the first week starts after the start of the year then the period before is week zero (0).
+     * <p>
+     * For example:<br>
+     * - if the 1st day of the year is a Monday, week one starts on the 1st and there is no week zero<br>
+     * - if the 2nd day of the year is a Monday, week one starts on the 2nd and the 1st is in week zero<br>
+     * - if the 4th day of the year is a Monday, week one starts on the 4th and the 1st to 3rd is in week zero<br>
+     * - if the 5th day of the year is a Monday, week two starts on the 5th and the 1st to 4th is in week one<br>
+     * <p>
+     * This field can be used with any calendar system.
+     * @return a TemporalField to access the WeekOfYear, not null
+     */
+    public TemporalField weekOfYear() {
+        return weekOfYear;
+    }
+
+    /**
+     * Checks if these rules are equal to the specified rules.
+     * <p>
+     * The comparison is based on the entire state of the rules, which is
+     * the first day-of-week and minimal days.
+     *
+     * @param object  the other rules to compare to, null returns false
+     * @return true if this is equal to the specified rules
+     */
+    @Override
+    public boolean equals(Object object) {
+        if (this == object) {
+            return true;
+        }
+        if (object instanceof WeekFields) {
+            return hashCode() == object.hashCode();
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for these rules.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return firstDayOfWeek.ordinal() * 7 + minimalDays;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * A string representation of this definition.
+     *
+     * @return the string representation, not null
+     */
+    @Override
+    public String toString() {
+        return "WeekFields[" + firstDayOfWeek + ',' + minimalDays + ']';
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Field type that computes DayOfWeek, WeekOfMonth, and WeekOfYear
+     * based on a WeekFields.
+     * A separate Field instance is required for each different WeekFields;
+     * combination of start of week and minimum number of days.
+     * Constructors are provided to create fields for DayOfWeek, WeekOfMonth,
+     * and WeekOfYear.
+     */
+    static class ComputedDayOfField implements TemporalField {
+
+        /**
+         * Returns a field to access the day of week,
+         * computed based on a WeekFields.
+         * <p>
+         * The WeekDefintion of the first day of the week is used with
+         * the ISO DAY_OF_WEEK field to compute week boundaries.
+         */
+        static ComputedDayOfField ofDayOfWeekField(WeekFields weekDef) {
+            return new ComputedDayOfField("DayOfWeek", weekDef,
+                    ChronoUnit.DAYS, ChronoUnit.WEEKS, DAY_OF_WEEK_RANGE);
+        }
+
+        /**
+         * Returns a field to access the week of month,
+         * computed based on a WeekFields.
+         * @see WeekFields#weekOfMonth()
+         */
+        static ComputedDayOfField ofWeekOfMonthField(WeekFields weekDef) {
+            return new ComputedDayOfField("WeekOfMonth", weekDef,
+                    ChronoUnit.WEEKS, ChronoUnit.MONTHS, WEEK_OF_MONTH_RANGE);
+        }
+
+        /**
+         * Returns a field to access the week of year,
+         * computed based on a WeekFields.
+         * @see WeekFields#weekOfYear()
+         */
+        static ComputedDayOfField ofWeekOfYearField(WeekFields weekDef) {
+            return new ComputedDayOfField("WeekOfYear", weekDef,
+                    ChronoUnit.WEEKS, ChronoUnit.YEARS, WEEK_OF_YEAR_RANGE);
+        }
+        private final String name;
+        private final WeekFields weekDef;
+        private final TemporalUnit baseUnit;
+        private final TemporalUnit rangeUnit;
+        private final ValueRange range;
+
+        private ComputedDayOfField(String name, WeekFields weekDef, TemporalUnit baseUnit, TemporalUnit rangeUnit, ValueRange range) {
+            this.name = name;
+            this.weekDef = weekDef;
+            this.baseUnit = baseUnit;
+            this.rangeUnit = rangeUnit;
+            this.range = range;
+        }
+
+        private static final ValueRange DAY_OF_WEEK_RANGE = ValueRange.of(1, 7);
+        private static final ValueRange WEEK_OF_MONTH_RANGE = ValueRange.of(0, 1, 4, 5);
+        private static final ValueRange WEEK_OF_YEAR_RANGE = ValueRange.of(0, 1, 52, 53);
+
+        @Override
+        public long doGet(TemporalAccessor temporal) {
+            // Offset the ISO DOW by the start of this week
+            int sow = weekDef.getFirstDayOfWeek().getValue();
+            int isoDow = temporal.get(ChronoField.DAY_OF_WEEK);
+            int dow = Math.floorMod(isoDow - sow, 7) + 1;
+
+            if (rangeUnit == ChronoUnit.WEEKS) {
+                return dow;
+            } else if (rangeUnit == ChronoUnit.MONTHS) {
+                int dom = temporal.get(ChronoField.DAY_OF_MONTH);
+                int offset = startOfWeekOffset(dom, dow);
+                return computeWeek(offset, dom);
+            } else if (rangeUnit == ChronoUnit.YEARS) {
+                int doy = temporal.get(ChronoField.DAY_OF_YEAR);
+                int offset = startOfWeekOffset(doy, dow);
+                return computeWeek(offset, doy);
+            } else {
+                throw new IllegalStateException("unreachable");
+            }
+        }
+
+        /**
+         * Returns an offset to align week start with a day of month or day of year.
+         *
+         * @param day the day; 1 through infinity
+         * @param dow the day of the week of that day; 1 through 7
+         * @return an offset in days to align a day with the start of the first 'full' week
+         */
+        private int startOfWeekOffset(int day, int dow) {
+            // offset of first day corresponding to the day of week in first 7 days (zero origin)
+            int weekStart = Math.floorMod(day - dow, 7);
+            int offset = -weekStart;
+            if (weekStart + 1 > weekDef.getMinimalDaysInFirstWeek()) {
+                // The previous week has the minimum days in the current month to be a 'week'
+                offset = 7 - weekStart;
+            }
+            return offset;
+        }
+
+        /**
+         * Returns the week number computed from the reference day and reference dayOfWeek.
+         *
+         * @param offset the offset to align a date with the start of week
+         *     from {@link #startOfWeekOffset}.
+         * @param day  the day for which to compute the week number
+         * @return the week number where zero is used for a partial week and 1 for the first full week
+         */
+        private int computeWeek(int offset, int day) {
+            return ((7 + offset + (day - 1)) / 7);
+        }
+
+        @Override
+        public <R extends Temporal> R doWith(R temporal, long newValue) {
+            // Check the new value and get the old value of the field
+            int newVal = range.checkValidIntValue(newValue, this);
+            int currentVal = temporal.get(this);
+            if (newVal == currentVal) {
+                return temporal;
+            }
+            // Compute the difference and add that using the base using of the field
+            int delta = newVal - currentVal;
+            return (R) temporal.plus(delta, baseUnit);
+        }
+
+        @Override
+        public boolean resolve(DateTimeBuilder builder, long value) {
+            int newValue = range.checkValidIntValue(value, this);
+            // DOW and YEAR are necessary for all fields; Chrono defaults to ISO if not present
+            int sow = weekDef.getFirstDayOfWeek().getValue();
+            int dow = builder.get(weekDef.dayOfWeek());
+            int year = builder.get(ChronoField.YEAR);
+            Chrono chrono = Chrono.from(builder);
+
+            // The WOM and WOY fields are the critical values
+            if (rangeUnit == ChronoUnit.MONTHS) {
+                // Process WOM value by combining with DOW and MONTH, YEAR
+                int month = builder.get(ChronoField.MONTH_OF_YEAR);
+                ChronoLocalDate cd = chrono.date(year, month, 1);
+                int offset = startOfWeekOffset(1, cd.get(weekDef.dayOfWeek()));
+                offset += dow - 1;    // offset to desired day of week
+                offset += 7 * (newValue - 1);    // offset by week number
+                ChronoLocalDate result = cd.plus(offset, ChronoUnit.DAYS);
+                builder.addFieldValue(ChronoField.DAY_OF_MONTH, result.get(ChronoField.DAY_OF_MONTH));
+                builder.removeFieldValue(this);
+                builder.removeFieldValue(weekDef.dayOfWeek());
+                return true;
+            } else if (rangeUnit == ChronoUnit.YEARS) {
+                // Process WOY
+                ChronoLocalDate cd = chrono.date(year, 1, 1);
+                int offset = startOfWeekOffset(1, cd.get(weekDef.dayOfWeek()));
+                offset += dow - 1;    // offset to desired day of week
+                offset += 7 * (newValue - 1);    // offset by week number
+                ChronoLocalDate result = cd.plus(offset, ChronoUnit.DAYS);
+                builder.addFieldValue(ChronoField.DAY_OF_MONTH, result.get(ChronoField.DAY_OF_MONTH));
+                builder.addFieldValue(ChronoField.MONTH_OF_YEAR, result.get(ChronoField.MONTH_OF_YEAR));
+                builder.removeFieldValue(this);
+                builder.removeFieldValue(weekDef.dayOfWeek());
+                return true;
+            } else {
+                // ignore DOW of WEEK field; the value will be processed by WOM or WOY
+                int isoDow = Math.floorMod((sow - 1) + (dow - 1), 7) + 1;
+                builder.addFieldValue(ChronoField.DAY_OF_WEEK, isoDow);
+                // Not removed, the week-of-xxx fields need this value
+                return true;
+            }
+        }
+
+        //-----------------------------------------------------------------------
+        @Override
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public TemporalUnit getBaseUnit() {
+            return baseUnit;
+        }
+
+        @Override
+        public TemporalUnit getRangeUnit() {
+            return rangeUnit;
+        }
+
+        @Override
+        public ValueRange range() {
+            return range;
+        }
+
+        //-------------------------------------------------------------------------
+        @Override
+        public int compare(TemporalAccessor temporal1, TemporalAccessor temporal2) {
+            return Long.compare(temporal1.getLong(this), temporal2.getLong(this));
+        }
+
+        //-----------------------------------------------------------------------
+        @Override
+        public boolean doIsSupported(TemporalAccessor temporal) {
+            if (temporal.isSupported(ChronoField.DAY_OF_WEEK)) {
+                if (rangeUnit == ChronoUnit.WEEKS) {
+                    return true;
+                } else if (rangeUnit == ChronoUnit.MONTHS) {
+                    return temporal.isSupported(ChronoField.DAY_OF_MONTH);
+                } else if (rangeUnit == ChronoUnit.YEARS) {
+                    return temporal.isSupported(ChronoField.DAY_OF_YEAR);
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public ValueRange doRange(TemporalAccessor temporal) {
+            if (rangeUnit == ChronoUnit.WEEKS) {
+                return range;
+            }
+
+            TemporalField field = null;
+            if (rangeUnit == ChronoUnit.MONTHS) {
+                field = ChronoField.DAY_OF_MONTH;
+            } else if (rangeUnit == ChronoUnit.YEARS) {
+                field = ChronoField.DAY_OF_YEAR;
+            } else {
+                throw new IllegalStateException("unreachable");
+            }
+
+            // Offset the ISO DOW by the start of this week
+            int sow = weekDef.getFirstDayOfWeek().getValue();
+            int isoDow = temporal.get(ChronoField.DAY_OF_WEEK);
+            int dow = Math.floorMod(isoDow - sow, 7) + 1;
+
+            int offset = startOfWeekOffset(temporal.get(field), dow);
+            ValueRange fieldRange = temporal.range(field);
+            return ValueRange.of(computeWeek(offset, (int) fieldRange.getMinimum()),
+                    computeWeek(offset, (int) fieldRange.getMaximum()));
+        }
+
+        //-----------------------------------------------------------------------
+        @Override
+        public String toString() {
+            return getName() + "[" + weekDef.toString() + "]";
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/Year.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,996 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import static java.time.temporal.ChronoField.ERA;
+import static java.time.temporal.ChronoField.YEAR;
+import static java.time.temporal.ChronoField.YEAR_OF_ERA;
+import static java.time.temporal.ChronoUnit.YEARS;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.Month;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.DateTimeParseException;
+import java.time.format.SignStyle;
+import java.util.Objects;
+
+/**
+ * A year in the ISO-8601 calendar system, such as {@code 2007}.
+ * <p>
+ * {@code Year} is an immutable date-time object that represents a year.
+ * Any field that can be derived from a year can be obtained.
+ * <p>
+ * <b>Note that years in the ISO chronology only align with years in the
+ * Gregorian-Julian system for modern years. Parts of Russia did not switch to the
+ * modern Gregorian/ISO rules until 1920.
+ * As such, historical years must be treated with caution.</b>
+ * <p>
+ * This class does not store or represent a month, day, time or time-zone.
+ * For example, the value "2007" can be stored in a {@code Year}.
+ * <p>
+ * Years represented by this class follow the ISO-8601 standard and use
+ * the proleptic numbering system. Year 1 is preceded by year 0, then by year -1.
+ * <p>
+ * The ISO-8601 calendar system is the modern civil calendar system used today
+ * in most of the world. It is equivalent to the proleptic Gregorian calendar
+ * system, in which today's rules for leap years are applied for all time.
+ * For most applications written today, the ISO-8601 rules are entirely suitable.
+ * However, any application that makes use of historical dates, and requires them
+ * to be accurate will find the ISO-8601 approach unsuitable.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class Year
+        implements Temporal, TemporalAdjuster, Comparable<Year>, Serializable {
+
+    /**
+     * The minimum supported year, '-999,999,999'.
+     */
+    public static final int MIN_VALUE = -999_999_999;
+    /**
+     * The maximum supported year, '+999,999,999'.
+     */
+    public static final int MAX_VALUE = 999_999_999;
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -23038383694477807L;
+    /**
+     * Parser.
+     */
+    private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder()
+        .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
+        .toFormatter();
+
+    /**
+     * The year being represented.
+     */
+    private final int year;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains the current year from the system clock in the default time-zone.
+     * <p>
+     * This will query the {@link java.time.Clock#systemDefaultZone() system clock} in the default
+     * time-zone to obtain the current year.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @return the current year using the system clock and default time-zone, not null
+     */
+    public static Year now() {
+        return now(Clock.systemDefaultZone());
+    }
+
+    /**
+     * Obtains the current year from the system clock in the specified time-zone.
+     * <p>
+     * This will query the {@link Clock#system(java.time.ZoneId) system clock} to obtain the current year.
+     * Specifying the time-zone avoids dependence on the default time-zone.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @param zone  the zone ID to use, not null
+     * @return the current year using the system clock, not null
+     */
+    public static Year now(ZoneId zone) {
+        return now(Clock.system(zone));
+    }
+
+    /**
+     * Obtains the current year from the specified clock.
+     * <p>
+     * This will query the specified clock to obtain the current year.
+     * Using this method allows the use of an alternate clock for testing.
+     * The alternate clock may be introduced using {@link Clock dependency injection}.
+     *
+     * @param clock  the clock to use, not null
+     * @return the current year, not null
+     */
+    public static Year now(Clock clock) {
+        final LocalDate now = LocalDate.now(clock);  // called once
+        return Year.of(now.getYear());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Year}.
+     * <p>
+     * This method accepts a year value from the proleptic ISO calendar system.
+     * <p>
+     * The year 2AD/CE is represented by 2.<br>
+     * The year 1AD/CE is represented by 1.<br>
+     * The year 1BC/BCE is represented by 0.<br>
+     * The year 2BC/BCE is represented by -1.<br>
+     *
+     * @param isoYear  the ISO proleptic year to represent, from {@code MIN_VALUE} to {@code MAX_VALUE}
+     * @return the year, not null
+     * @throws DateTimeException if the field is invalid
+     */
+    public static Year of(int isoYear) {
+        YEAR.checkValidValue(isoYear);
+        return new Year(isoYear);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Year} from a temporal object.
+     * <p>
+     * A {@code TemporalAccessor} represents some form of date and time information.
+     * This factory converts the arbitrary temporal object to an instance of {@code Year}.
+     * <p>
+     * The conversion extracts the {@link ChronoField#YEAR year} field.
+     * The extraction is only permitted if the temporal object has an ISO
+     * chronology, or can be converted to a {@code LocalDate}.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used in queries via method reference, {@code Year::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the year, not null
+     * @throws DateTimeException if unable to convert to a {@code Year}
+     */
+    public static Year from(TemporalAccessor temporal) {
+        if (temporal instanceof Year) {
+            return (Year) temporal;
+        }
+        try {
+            if (ISOChrono.INSTANCE.equals(Chrono.from(temporal)) == false) {
+                temporal = LocalDate.from(temporal);
+            }
+            return of(temporal.get(YEAR));
+        } catch (DateTimeException ex) {
+            throw new DateTimeException("Unable to obtain Year from TemporalAccessor: " + temporal.getClass(), ex);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Year} from a text string such as {@code 2007}.
+     * <p>
+     * The string must represent a valid year.
+     * Years outside the range 0000 to 9999 must be prefixed by the plus or minus symbol.
+     *
+     * @param text  the text to parse such as "2007", not null
+     * @return the parsed year, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static Year parse(CharSequence text) {
+        return parse(text, PARSER);
+    }
+
+    /**
+     * Obtains an instance of {@code Year} from a text string using a specific formatter.
+     * <p>
+     * The text is parsed using the formatter, returning a year.
+     *
+     * @param text  the text to parse, not null
+     * @param formatter  the formatter to use, not null
+     * @return the parsed year, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static Year parse(CharSequence text, DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.parse(text, Year::from);
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Checks if the year is a leap year, according to the ISO proleptic
+     * calendar system rules.
+     * <p>
+     * This method applies the current rules for leap years across the whole time-line.
+     * In general, a year is a leap year if it is divisible by four without
+     * remainder. However, years divisible by 100, are not leap years, with
+     * the exception of years divisible by 400 which are.
+     * <p>
+     * For example, 1904 is a leap year it is divisible by 4.
+     * 1900 was not a leap year as it is divisible by 100, however 2000 was a
+     * leap year as it is divisible by 400.
+     * <p>
+     * The calculation is proleptic - applying the same rules into the far future and far past.
+     * This is historically inaccurate, but is correct for the ISO-8601 standard.
+     *
+     * @param year  the year to check
+     * @return true if the year is leap, false otherwise
+     */
+    public static boolean isLeap(long year) {
+        return ((year & 3) == 0) && ((year % 100) != 0 || (year % 400) == 0);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructor.
+     *
+     * @param year  the year to represent
+     */
+    private Year(int year) {
+        this.year = year;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the year value.
+     * <p>
+     * The year returned by this method is proleptic as per {@code get(YEAR)}.
+     *
+     * @return the year, {@code MIN_VALUE} to {@code MAX_VALUE}
+     */
+    public int getValue() {
+        return year;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if this year can be queried for the specified field.
+     * If false, then calling the {@link #range(TemporalField) range} and
+     * {@link #get(TemporalField) get} methods will throw an exception.
+     * <p>
+     * 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:
+     * <ul>
+     * <li>{@code YEAR_OF_ERA}
+     * <li>{@code YEAR}
+     * <li>{@code ERA}
+     * </ul>
+     * All other {@code ChronoField} instances will return false.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the field is supported is determined by the field.
+     *
+     * @param field  the field to check, null returns false
+     * @return true if the field is supported on this year, false if not
+     */
+    @Override
+    public boolean isSupported(TemporalField field) {
+        if (field instanceof ChronoField) {
+            return field == YEAR || field == YEAR_OF_ERA || field == ERA;
+        }
+        return field != null && field.doIsSupported(this);
+    }
+
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * The range object expresses the minimum and maximum valid values for a field.
+     * This year is used to enhance the accuracy of the returned range.
+     * If it is not possible to return the range, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * 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}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the range can be obtained is determined by the field.
+     *
+     * @param field  the field to query the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     */
+    @Override
+    public ValueRange range(TemporalField field) {
+        if (field == YEAR_OF_ERA) {
+            return (year <= 0 ? ValueRange.of(1, MAX_VALUE + 1) : ValueRange.of(1, MAX_VALUE));
+        }
+        return Temporal.super.range(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this year as an {@code int}.
+     * <p>
+     * This queries this year for the value for the specified field.
+     * The returned value will always be within the valid range of values for the field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this year.
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override  // override for Javadoc
+    public int get(TemporalField field) {
+        return range(field).checkValidIntValue(getLong(field), field);
+    }
+
+    /**
+     * Gets the value of the specified field from this year as a {@code long}.
+     * <p>
+     * This queries this year for the value for the specified field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this year.
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long getLong(TemporalField field) {
+        if (field instanceof ChronoField) {
+            switch ((ChronoField) field) {
+                case YEAR_OF_ERA: return (year < 1 ? 1 - year : year);
+                case YEAR: return year;
+                case ERA: return (year < 1 ? 0 : 1);
+            }
+            throw new DateTimeException("Unsupported field: " + field.getName());
+        }
+        return field.doGet(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the year is a leap year, according to the ISO proleptic
+     * calendar system rules.
+     * <p>
+     * This method applies the current rules for leap years across the whole time-line.
+     * In general, a year is a leap year if it is divisible by four without
+     * remainder. However, years divisible by 100, are not leap years, with
+     * the exception of years divisible by 400 which are.
+     * <p>
+     * For example, 1904 is a leap year it is divisible by 4.
+     * 1900 was not a leap year as it is divisible by 100, however 2000 was a
+     * leap year as it is divisible by 400.
+     * <p>
+     * The calculation is proleptic - applying the same rules into the far future and far past.
+     * This is historically inaccurate, but is correct for the ISO-8601 standard.
+     *
+     * @return true if the year is leap, false otherwise
+     */
+    public boolean isLeap() {
+        return Year.isLeap(year);
+    }
+
+    /**
+     * Checks if the month-day is valid for this year.
+     * <p>
+     * This method checks whether this year and the input month and day form
+     * a valid date.
+     *
+     * @param monthDay  the month-day to validate, null returns false
+     * @return true if the month and day are valid for this year
+     */
+    public boolean isValidMonthDay(MonthDay monthDay) {
+        return monthDay != null && monthDay.isValidYear(year);
+    }
+
+    /**
+     * Gets the length of this year in days.
+     *
+     * @return the length of this year in days, 365 or 366
+     */
+    public int length() {
+        return isLeap() ? 366 : 365;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns an adjusted copy of this year.
+     * <p>
+     * This returns a new {@code Year}, based on this one, with the year adjusted.
+     * The adjustment takes place using the specified adjuster strategy object.
+     * Read the documentation of the adjuster to understand what adjustment will be made.
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param adjuster the adjuster to use, not null
+     * @return a {@code Year} based on {@code this} with the adjustment made, not null
+     * @throws DateTimeException if the adjustment cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Year with(TemporalAdjuster adjuster) {
+        return (Year) adjuster.adjustInto(this);
+    }
+
+    /**
+     * Returns a copy of this year with the specified field set to a new value.
+     * <p>
+     * This returns a new {@code Year}, based on this one, with the value
+     * for the specified field changed.
+     * If it is not possible to set the value, because the field is not supported or for
+     * some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the adjustment is implemented here.
+     * The supported fields behave as follows:
+     * <ul>
+     * <li>{@code YEAR_OF_ERA} -
+     *  Returns a {@code Year} with the specified year-of-era
+     *  The era will be unchanged.
+     * <li>{@code YEAR} -
+     *  Returns a {@code Year} with the specified year.
+     *  This completely replaces the date and is equivalent to {@link #of(int)}.
+     * <li>{@code ERA} -
+     *  Returns a {@code Year} with the specified era.
+     *  The year-of-era will be unchanged.
+     * </ul>
+     * <p>
+     * In all cases, if the new value is outside the valid range of values for the field
+     * then a {@code DateTimeException} will be thrown.
+     * <p>
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param field  the field to set in the result, not null
+     * @param newValue  the new value of the field in the result
+     * @return a {@code Year} based on {@code this} with the specified field set, not null
+     * @throws DateTimeException if the field cannot be set
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Year with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            f.checkValidValue(newValue);
+            switch (f) {
+                case YEAR_OF_ERA: return Year.of((int) (year < 1 ? 1 - newValue : newValue));
+                case YEAR: return Year.of((int) newValue);
+                case ERA: return (getLong(ERA) == newValue ? this : Year.of(1 - year));
+            }
+            throw new DateTimeException("Unsupported field: " + field.getName());
+        }
+        return field.doWith(this, newValue);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this year with the specified period added.
+     * <p>
+     * This method returns a new year based on this year with the specified period added.
+     * The adder is typically {@link java.time.Period} but may be any other type implementing
+     * the {@link TemporalAdder} interface.
+     * The calculation is delegated to the specified adjuster, which typically calls
+     * back to {@link #plus(long, TemporalUnit)}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param adder  the adder to use, not null
+     * @return a {@code Year} based on this year with the addition made, not null
+     * @throws DateTimeException if the addition cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Year plus(TemporalAdder adder) {
+        return (Year) adder.addTo(this);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public Year plus(long amountToAdd, TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            switch ((ChronoUnit) unit) {
+                case YEARS: return plusYears(amountToAdd);
+                case DECADES: return plusYears(Math.multiplyExact(amountToAdd, 10));
+                case CENTURIES: return plusYears(Math.multiplyExact(amountToAdd, 100));
+                case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000));
+                case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd));
+            }
+            throw new DateTimeException("Unsupported unit: " + unit.getName());
+        }
+        return unit.doPlus(this, amountToAdd);
+    }
+
+    /**
+     * Returns a copy of this year with the specified number of years added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param yearsToAdd  the years to add, may be negative
+     * @return a {@code Year} based on this year with the period added, not null
+     * @throws DateTimeException if the result exceeds the supported year range
+     */
+    public Year plusYears(long yearsToAdd) {
+        if (yearsToAdd == 0) {
+            return this;
+        }
+        return of(YEAR.checkValidIntValue(year + yearsToAdd));  // overflow safe
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this year with the specified period subtracted.
+     * <p>
+     * This method returns a new year based on this year with the specified period subtracted.
+     * The subtractor is typically {@link java.time.Period} but may be any other type implementing
+     * the {@link TemporalSubtractor} interface.
+     * The calculation is delegated to the specified adjuster, which typically calls
+     * back to {@link #minus(long, TemporalUnit)}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param subtractor  the subtractor to use, not null
+     * @return a {@code Year} based on this year with the subtraction made, not null
+     * @throws DateTimeException if the subtraction cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Year minus(TemporalSubtractor subtractor) {
+        return (Year) subtractor.subtractFrom(this);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public Year minus(long amountToSubtract, TemporalUnit unit) {
+        return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
+    }
+
+    /**
+     * Returns a copy of this year with the specified number of years subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param yearsToSubtract  the years to subtract, may be negative
+     * @return a {@code Year} based on this year with the period subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported year range
+     */
+    public Year minusYears(long yearsToSubtract) {
+        return (yearsToSubtract == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-yearsToSubtract));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this year using the specified query.
+     * <p>
+     * This queries this year using the specified query strategy object.
+     * The {@code TemporalQuery} object defines the logic to be used to
+     * obtain the result. Read the documentation of the query to understand
+     * what the result of this method will be.
+     * <p>
+     * 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 <R> 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> R query(TemporalQuery<R> query) {
+        if (query == Queries.chrono()) {
+            return (R) ISOChrono.INSTANCE;
+        } else if (query == Queries.precision()) {
+            return (R) YEARS;
+        }
+        return Temporal.super.query(query);
+    }
+
+    /**
+     * Adjusts the specified temporal object to have this year.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with the year changed to be the same as this.
+     * <p>
+     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+     * passing {@link ChronoField#YEAR} as the field.
+     * If the specified temporal object does not use the ISO calendar system then
+     * a {@code DateTimeException} is thrown.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisYear.adjustInto(temporal);
+     *   temporal = temporal.with(thisYear);
+     * </pre>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param temporal  the target object to be adjusted, not null
+     * @return the adjusted object, not null
+     * @throws DateTimeException if unable to make the adjustment
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Temporal adjustInto(Temporal temporal) {
+        if (Chrono.from(temporal).equals(ISOChrono.INSTANCE) == false) {
+            throw new DateTimeException("Adjustment only supported on ISO date-time");
+        }
+        return temporal.with(YEAR, year);
+    }
+
+    /**
+     * Calculates the period between this year and another year in
+     * terms of the specified unit.
+     * <p>
+     * This calculates the period between two years in terms of a single unit.
+     * The start and end points are {@code this} and the specified year.
+     * The result will be negative if the end is before the start.
+     * The {@code Temporal} passed to this method must be a {@code Year}.
+     * For example, the period in decades between two year can be calculated
+     * using {@code startYear.periodUntil(endYear, DECADES)}.
+     * <p>
+     * The calculation returns a whole number, representing the number of
+     * complete units between the two years.
+     * For example, the period in decades between 2012 and 2031
+     * will only be one decade as it is one year short of two decades.
+     * <p>
+     * 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:
+     * <pre>
+     *   long period = start.periodUntil(end, YEARS);   // this method
+     *   dateTime.plus(YEARS.between(start, end));      // use in plus/minus
+     * </pre>
+     * <p>
+     * The calculation is implemented in this method for {@link ChronoUnit}.
+     * The units {@code YEARS}, {@code DECADES}, {@code CENTURIES},
+     * {@code MILLENNIA} and {@code ERAS} are supported.
+     * Other {@code ChronoUnit} values will throw an exception.
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param endYear  the end year, which must be a {@code Year}, not null
+     * @param unit  the unit to measure the period in, not null
+     * @return the amount of the period between this year and the end year
+     * @throws DateTimeException if the period cannot be calculated
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long periodUntil(Temporal endYear, TemporalUnit unit) {
+        if (endYear instanceof Year == false) {
+            Objects.requireNonNull(endYear, "endYear");
+            throw new DateTimeException("Unable to calculate period between objects of two different types");
+        }
+        Year end = (Year) endYear;
+        if (unit instanceof ChronoUnit) {
+            long yearsUntil = ((long) end.year) - year;  // no overflow
+            switch ((ChronoUnit) unit) {
+                case YEARS: return yearsUntil;
+                case DECADES: return yearsUntil / 10;
+                case CENTURIES: return yearsUntil / 100;
+                case MILLENNIA: return yearsUntil / 1000;
+                case ERAS: return end.getLong(ERA) - getLong(ERA);
+            }
+            throw new DateTimeException("Unsupported unit: " + unit.getName());
+        }
+        return unit.between(this, endYear).getAmount();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a date formed from this year at the specified day-of-year.
+     * <p>
+     * This combines this year and the specified day-of-year to form a {@code LocalDate}.
+     * The day-of-year value 366 is only valid in a leap year.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param dayOfYear  the day-of-year to use, not null
+     * @return the local date formed from this year and the specified date of year, not null
+     * @throws DateTimeException if the day of year is 366 and this is not a leap year
+     */
+    public LocalDate atDay(int dayOfYear) {
+        return LocalDate.ofYearDay(year, dayOfYear);
+    }
+
+    /**
+     * Returns a year-month formed from this year at the specified month.
+     * <p>
+     * This combines this year and the specified month to form a {@code YearMonth}.
+     * All possible combinations of year and month are valid.
+     * <p>
+     * This method can be used as part of a chain to produce a date:
+     * <pre>
+     *  LocalDate date = year.atMonth(month).atDay(day);
+     * </pre>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param month  the month-of-year to use, not null
+     * @return the year-month formed from this year and the specified month, not null
+     */
+    public YearMonth atMonth(Month month) {
+        return YearMonth.of(year, month);
+    }
+
+    /**
+     * Returns a year-month formed from this year at the specified month.
+     * <p>
+     * This combines this year and the specified month to form a {@code YearMonth}.
+     * All possible combinations of year and month are valid.
+     * <p>
+     * This method can be used as part of a chain to produce a date:
+     * <pre>
+     *  LocalDate date = year.atMonth(month).atDay(day);
+     * </pre>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param month  the month-of-year to use, from 1 (January) to 12 (December)
+     * @return the year-month formed from this year and the specified month, not null
+     */
+    public YearMonth atMonth(int month) {
+        return YearMonth.of(year, month);
+    }
+
+    /**
+     * Returns a date formed from this year at the specified month-day.
+     * <p>
+     * This combines this year and the specified month-day to form a {@code LocalDate}.
+     * The month-day value of February 29th is only valid in a leap year.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param monthDay  the month-day to use, not null
+     * @return the local date formed from this year and the specified month-day, not null
+     * @throws DateTimeException if the month-day is February 29th and this is not a leap year
+     */
+    public LocalDate atMonthDay(MonthDay monthDay) {
+        return LocalDate.of(year, monthDay.getMonth(), monthDay.getDayOfMonth());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this year to another year.
+     * <p>
+     * The comparison is based on the value of the year.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     *
+     * @param other  the other year to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     */
+    public int compareTo(Year other) {
+        return year - other.year;
+    }
+
+    /**
+     * Is this year after the specified year.
+     *
+     * @param other  the other year to compare to, not null
+     * @return true if this is after the specified year
+     */
+    public boolean isAfter(Year other) {
+        return year > other.year;
+    }
+
+    /**
+     * Is this year before the specified year.
+     *
+     * @param other  the other year to compare to, not null
+     * @return true if this point is before the specified year
+     */
+    public boolean isBefore(Year other) {
+        return year < other.year;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this year is equal to another year.
+     * <p>
+     * The comparison is based on the time-line position of the years.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other year
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof Year) {
+            return year == ((Year) obj).year;
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this year.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return year;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this year as a {@code String}.
+     *
+     * @return a string representation of this year, not null
+     */
+    @Override
+    public String toString() {
+        return Integer.toString(year);
+    }
+
+    /**
+     * Outputs this year as a {@code String} using the formatter.
+     * <p>
+     * This year will be passed to the formatter
+     * {@link DateTimeFormatter#print(TemporalAccessor) print method}.
+     *
+     * @param formatter  the formatter to use, not null
+     * @return the formatted year string, not null
+     * @throws DateTimeException if an error occurs during printing
+     */
+    public String toString(DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.print(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>.
+     * <pre>
+     *  out.writeByte(4);  // identifies this as a Year
+     *  out.writeInt(year);
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.YEAR_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     * @return never
+     * @throws InvalidObjectException always
+     */
+    private Object readResolve() throws ObjectStreamException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        out.writeInt(year);
+    }
+
+    static Year readExternal(DataInput in) throws IOException {
+        return Year.of(in.readInt());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/YearMonth.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,1085 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import static java.time.temporal.ChronoField.EPOCH_MONTH;
+import static java.time.temporal.ChronoField.ERA;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.YEAR;
+import static java.time.temporal.ChronoField.YEAR_OF_ERA;
+import static java.time.temporal.ChronoUnit.MONTHS;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.Month;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.DateTimeParseException;
+import java.time.format.SignStyle;
+import java.util.Objects;
+
+/**
+ * A year-month in the ISO-8601 calendar system, such as {@code 2007-12}.
+ * <p>
+ * {@code YearMonth} is an immutable date-time object that represents the combination
+ * of a year and month. Any field that can be derived from a year and month, such as
+ * quarter-of-year, can be obtained.
+ * <p>
+ * This class does not store or represent a day, time or time-zone.
+ * For example, the value "October 2007" can be stored in a {@code YearMonth}.
+ * <p>
+ * The ISO-8601 calendar system is the modern civil calendar system used today
+ * in most of the world. It is equivalent to the proleptic Gregorian calendar
+ * system, in which today's rules for leap years are applied for all time.
+ * For most applications written today, the ISO-8601 rules are entirely suitable.
+ * However, any application that makes use of historical dates, and requires them
+ * to be accurate will find the ISO-8601 approach unsuitable.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class YearMonth
+        implements Temporal, TemporalAdjuster, Comparable<YearMonth>, Serializable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 4183400860270640070L;
+    /**
+     * Parser.
+     */
+    private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder()
+        .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
+        .appendLiteral('-')
+        .appendValue(MONTH_OF_YEAR, 2)
+        .toFormatter();
+
+    /**
+     * The year.
+     */
+    private final int year;
+    /**
+     * The month-of-year, not null.
+     */
+    private final int month;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains the current year-month from the system clock in the default time-zone.
+     * <p>
+     * This will query the {@link java.time.Clock#systemDefaultZone() system clock} in the default
+     * time-zone to obtain the current year-month.
+     * The zone and offset will be set based on the time-zone in the clock.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @return the current year-month using the system clock and default time-zone, not null
+     */
+    public static YearMonth now() {
+        return now(Clock.systemDefaultZone());
+    }
+
+    /**
+     * Obtains the current year-month from the system clock in the specified time-zone.
+     * <p>
+     * This will query the {@link Clock#system(java.time.ZoneId) system clock} to obtain the current year-month.
+     * Specifying the time-zone avoids dependence on the default time-zone.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @param zone  the zone ID to use, not null
+     * @return the current year-month using the system clock, not null
+     */
+    public static YearMonth now(ZoneId zone) {
+        return now(Clock.system(zone));
+    }
+
+    /**
+     * Obtains the current year-month from the specified clock.
+     * <p>
+     * This will query the specified clock to obtain the current year-month.
+     * Using this method allows the use of an alternate clock for testing.
+     * The alternate clock may be introduced using {@link Clock dependency injection}.
+     *
+     * @param clock  the clock to use, not null
+     * @return the current year-month, not null
+     */
+    public static YearMonth now(Clock clock) {
+        final LocalDate now = LocalDate.now(clock);  // called once
+        return YearMonth.of(now.getYear(), now.getMonth());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code YearMonth} from a year and month.
+     *
+     * @param year  the year to represent, from MIN_YEAR to MAX_YEAR
+     * @param month  the month-of-year to represent, not null
+     * @return the year-month, not null
+     * @throws DateTimeException if the year value is invalid
+     */
+    public static YearMonth of(int year, Month month) {
+        Objects.requireNonNull(month, "month");
+        return of(year, month.getValue());
+    }
+
+    /**
+     * Obtains an instance of {@code YearMonth} from a year and month.
+     *
+     * @param year  the year to represent, from MIN_YEAR to MAX_YEAR
+     * @param month  the month-of-year to represent, from 1 (January) to 12 (December)
+     * @return the year-month, not null
+     * @throws DateTimeException if either field value is invalid
+     */
+    public static YearMonth of(int year, int month) {
+        YEAR.checkValidValue(year);
+        MONTH_OF_YEAR.checkValidValue(month);
+        return new YearMonth(year, month);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code YearMonth} from a temporal object.
+     * <p>
+     * A {@code TemporalAccessor} represents some form of date and time information.
+     * This factory converts the arbitrary temporal object to an instance of {@code YearMonth}.
+     * <p>
+     * The conversion extracts the {@link ChronoField#YEAR YEAR} and
+     * {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} fields.
+     * The extraction is only permitted if the temporal object has an ISO
+     * chronology, or can be converted to a {@code LocalDate}.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used in queries via method reference, {@code YearMonth::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the year-month, not null
+     * @throws DateTimeException if unable to convert to a {@code YearMonth}
+     */
+    public static YearMonth from(TemporalAccessor temporal) {
+        if (temporal instanceof YearMonth) {
+            return (YearMonth) temporal;
+        }
+        try {
+            if (ISOChrono.INSTANCE.equals(Chrono.from(temporal)) == false) {
+                temporal = LocalDate.from(temporal);
+            }
+            return of(temporal.get(YEAR), temporal.get(MONTH_OF_YEAR));
+        } catch (DateTimeException ex) {
+            throw new DateTimeException("Unable to obtain YearMonth from TemporalAccessor: " + temporal.getClass(), ex);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code YearMonth} from a text string such as {@code 2007-12}.
+     * <p>
+     * The string must represent a valid year-month.
+     * The format must be {@code yyyy-MM}.
+     * Years outside the range 0000 to 9999 must be prefixed by the plus or minus symbol.
+     *
+     * @param text  the text to parse such as "2007-12", not null
+     * @return the parsed year-month, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static YearMonth parse(CharSequence text) {
+        return parse(text, PARSER);
+    }
+
+    /**
+     * Obtains an instance of {@code YearMonth} from a text string using a specific formatter.
+     * <p>
+     * The text is parsed using the formatter, returning a year-month.
+     *
+     * @param text  the text to parse, not null
+     * @param formatter  the formatter to use, not null
+     * @return the parsed year-month, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static YearMonth parse(CharSequence text, DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.parse(text, YearMonth::from);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructor.
+     *
+     * @param year  the year to represent, validated from MIN_YEAR to MAX_YEAR
+     * @param month  the month-of-year to represent, validated from 1 (January) to 12 (December)
+     */
+    private YearMonth(int year, int month) {
+        this.year = year;
+        this.month = month;
+    }
+
+    /**
+     * Returns a copy of this year-month with the new year and month, checking
+     * to see if a new object is in fact required.
+     *
+     * @param newYear  the year to represent, validated from MIN_YEAR to MAX_YEAR
+     * @param newMonth  the month-of-year to represent, validated not null
+     * @return the year-month, not null
+     */
+    private YearMonth with(int newYear, int newMonth) {
+        if (year == newYear && month == newMonth) {
+            return this;
+        }
+        return new YearMonth(newYear, newMonth);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if this year-month can be queried for the specified field.
+     * If false, then calling the {@link #range(TemporalField) range} and
+     * {@link #get(TemporalField) get} methods will throw an exception.
+     * <p>
+     * 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:
+     * <ul>
+     * <li>{@code MONTH_OF_YEAR}
+     * <li>{@code EPOCH_MONTH}
+     * <li>{@code YEAR_OF_ERA}
+     * <li>{@code YEAR}
+     * <li>{@code ERA}
+     * </ul>
+     * All other {@code ChronoField} instances will return false.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the field is supported is determined by the field.
+     *
+     * @param field  the field to check, null returns false
+     * @return true if the field is supported on this year-month, false if not
+     */
+    @Override
+    public boolean isSupported(TemporalField field) {
+        if (field instanceof ChronoField) {
+            return field == YEAR || field == MONTH_OF_YEAR ||
+                    field == EPOCH_MONTH || field == YEAR_OF_ERA || field == ERA;
+        }
+        return field != null && field.doIsSupported(this);
+    }
+
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * The range object expresses the minimum and maximum valid values for a field.
+     * This year-month is used to enhance the accuracy of the returned range.
+     * If it is not possible to return the range, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * 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}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the range can be obtained is determined by the field.
+     *
+     * @param field  the field to query the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     */
+    @Override
+    public ValueRange range(TemporalField field) {
+        if (field == YEAR_OF_ERA) {
+            return (getYear() <= 0 ? ValueRange.of(1, Year.MAX_VALUE + 1) : ValueRange.of(1, Year.MAX_VALUE));
+        }
+        return Temporal.super.range(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this year-month as an {@code int}.
+     * <p>
+     * This queries this year-month for the value for the specified field.
+     * The returned value will always be within the valid range of values for the field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this year-month, except {@code EPOCH_MONTH} which is too
+     * large to fit in an {@code int} and throw a {@code DateTimeException}.
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override  // override for Javadoc
+    public int get(TemporalField field) {
+        return range(field).checkValidIntValue(getLong(field), field);
+    }
+
+    /**
+     * Gets the value of the specified field from this year-month as a {@code long}.
+     * <p>
+     * This queries this year-month for the value for the specified field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this year-month.
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long getLong(TemporalField field) {
+        if (field instanceof ChronoField) {
+            switch ((ChronoField) field) {
+                case MONTH_OF_YEAR: return month;
+                case EPOCH_MONTH: return getEpochMonth();
+                case YEAR_OF_ERA: return (year < 1 ? 1 - year : year);
+                case YEAR: return year;
+                case ERA: return (year < 1 ? 0 : 1);
+            }
+            throw new DateTimeException("Unsupported field: " + field.getName());
+        }
+        return field.doGet(this);
+    }
+
+    private long getEpochMonth() {
+        return ((year - 1970) * 12L) + (month - 1);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the year field.
+     * <p>
+     * This method returns the primitive {@code int} value for the year.
+     * <p>
+     * The year returned by this method is proleptic as per {@code get(YEAR)}.
+     *
+     * @return the year, from MIN_YEAR to MAX_YEAR
+     */
+    public int getYear() {
+        return year;
+    }
+
+    /**
+     * Gets the month-of-year field using the {@code Month} enum.
+     * <p>
+     * This method returns the enum {@link Month} for the month.
+     * This avoids confusion as to what {@code int} values mean.
+     * If you need access to the primitive {@code int} value then the enum
+     * provides the {@link Month#getValue() int value}.
+     *
+     * @return the month-of-year, not null
+     */
+    public Month getMonth() {
+        return Month.of(month);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the year is a leap year, according to the ISO proleptic
+     * calendar system rules.
+     * <p>
+     * This method applies the current rules for leap years across the whole time-line.
+     * In general, a year is a leap year if it is divisible by four without
+     * remainder. However, years divisible by 100, are not leap years, with
+     * the exception of years divisible by 400 which are.
+     * <p>
+     * For example, 1904 is a leap year it is divisible by 4.
+     * 1900 was not a leap year as it is divisible by 100, however 2000 was a
+     * leap year as it is divisible by 400.
+     * <p>
+     * The calculation is proleptic - applying the same rules into the far future and far past.
+     * This is historically inaccurate, but is correct for the ISO-8601 standard.
+     *
+     * @return true if the year is leap, false otherwise
+     */
+    public boolean isLeapYear() {
+        return ISOChrono.INSTANCE.isLeapYear(year);
+    }
+
+    /**
+     * Checks if the day-of-month is valid for this year-month.
+     * <p>
+     * This method checks whether this year and month and the input day form
+     * a valid date.
+     *
+     * @param dayOfMonth  the day-of-month to validate, from 1 to 31, invalid value returns false
+     * @return true if the day is valid for this year-month
+     */
+    public boolean isValidDay(int dayOfMonth) {
+        return dayOfMonth >= 1 && dayOfMonth <= lengthOfMonth();
+    }
+
+    /**
+     * Returns the length of the month, taking account of the year.
+     * <p>
+     * This returns the length of the month in days.
+     * For example, a date in January would return 31.
+     *
+     * @return the length of the month in days, from 28 to 31
+     */
+    public int lengthOfMonth() {
+        return getMonth().length(isLeapYear());
+    }
+
+    /**
+     * Returns the length of the year.
+     * <p>
+     * This returns the length of the year in days, either 365 or 366.
+     *
+     * @return 366 if the year is leap, 365 otherwise
+     */
+    public int lengthOfYear() {
+        return (isLeapYear() ? 366 : 365);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns an adjusted copy of this year-month.
+     * <p>
+     * This returns a new {@code YearMonth}, based on this one, with the year-month adjusted.
+     * The adjustment takes place using the specified adjuster strategy object.
+     * Read the documentation of the adjuster to understand what adjustment will be made.
+     * <p>
+     * A simple adjuster might simply set the one of the fields, such as the year field.
+     * A more complex adjuster might set the year-month to the next month that
+     * Halley's comet will pass the Earth.
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param adjuster the adjuster to use, not null
+     * @return a {@code YearMonth} based on {@code this} with the adjustment made, not null
+     * @throws DateTimeException if the adjustment cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public YearMonth with(TemporalAdjuster adjuster) {
+        return (YearMonth) adjuster.adjustInto(this);
+    }
+
+    /**
+     * Returns a copy of this year-month with the specified field set to a new value.
+     * <p>
+     * This returns a new {@code YearMonth}, based on this one, with the value
+     * for the specified field changed.
+     * This can be used to change any supported field, such as the year or month.
+     * If it is not possible to set the value, because the field is not supported or for
+     * some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the adjustment is implemented here.
+     * The supported fields behave as follows:
+     * <ul>
+     * <li>{@code MONTH_OF_YEAR} -
+     *  Returns a {@code YearMonth} with the specified month-of-year.
+     *  The year will be unchanged.
+     * <li>{@code EPOCH_MONTH} -
+     *  Returns a {@code YearMonth} with the specified epoch-month.
+     *  This completely replaces the year and month of this object.
+     * <li>{@code YEAR_OF_ERA} -
+     *  Returns a {@code YearMonth} with the specified year-of-era
+     *  The month and era will be unchanged.
+     * <li>{@code YEAR} -
+     *  Returns a {@code YearMonth} with the specified year.
+     *  The month will be unchanged.
+     * <li>{@code ERA} -
+     *  Returns a {@code YearMonth} with the specified era.
+     *  The month and year-of-era will be unchanged.
+     * </ul>
+     * <p>
+     * In all cases, if the new value is outside the valid range of values for the field
+     * then a {@code DateTimeException} will be thrown.
+     * <p>
+     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param field  the field to set in the result, not null
+     * @param newValue  the new value of the field in the result
+     * @return a {@code YearMonth} based on {@code this} with the specified field set, not null
+     * @throws DateTimeException if the field cannot be set
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public YearMonth with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            f.checkValidValue(newValue);
+            switch (f) {
+                case MONTH_OF_YEAR: return withMonth((int) newValue);
+                case EPOCH_MONTH: return plusMonths(newValue - getLong(EPOCH_MONTH));
+                case YEAR_OF_ERA: return withYear((int) (year < 1 ? 1 - newValue : newValue));
+                case YEAR: return withYear((int) newValue);
+                case ERA: return (getLong(ERA) == newValue ? this : withYear(1 - year));
+            }
+            throw new DateTimeException("Unsupported field: " + field.getName());
+        }
+        return field.doWith(this, newValue);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code YearMonth} with the year altered.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param year  the year to set in the returned year-month, from MIN_YEAR to MAX_YEAR
+     * @return a {@code YearMonth} based on this year-month with the requested year, not null
+     * @throws DateTimeException if the year value is invalid
+     */
+    public YearMonth withYear(int year) {
+        YEAR.checkValidValue(year);
+        return with(year, month);
+    }
+
+    /**
+     * Returns a copy of this {@code YearMonth} with the month-of-year altered.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param month  the month-of-year to set in the returned year-month, from 1 (January) to 12 (December)
+     * @return a {@code YearMonth} based on this year-month with the requested month, not null
+     * @throws DateTimeException if the month-of-year value is invalid
+     */
+    public YearMonth withMonth(int month) {
+        MONTH_OF_YEAR.checkValidValue(month);
+        return with(year, month);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this year-month with the specified period added.
+     * <p>
+     * This method returns a new year-month based on this year-month with the specified period added.
+     * The adder is typically {@link java.time.Period} but may be any other type implementing
+     * the {@link TemporalAdder} interface.
+     * The calculation is delegated to the specified adjuster, which typically calls
+     * back to {@link #plus(long, TemporalUnit)}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param adder  the adder to use, not null
+     * @return a {@code YearMonth} based on this year-month with the addition made, not null
+     * @throws DateTimeException if the addition cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public YearMonth plus(TemporalAdder adder) {
+        return (YearMonth) adder.addTo(this);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public YearMonth plus(long amountToAdd, TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            switch ((ChronoUnit) unit) {
+                case MONTHS: return plusMonths(amountToAdd);
+                case YEARS: return plusYears(amountToAdd);
+                case DECADES: return plusYears(Math.multiplyExact(amountToAdd, 10));
+                case CENTURIES: return plusYears(Math.multiplyExact(amountToAdd, 100));
+                case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000));
+                case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd));
+            }
+            throw new DateTimeException("Unsupported unit: " + unit.getName());
+        }
+        return unit.doPlus(this, amountToAdd);
+    }
+
+    /**
+     * Returns a copy of this year-month with the specified period in years added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param yearsToAdd  the years to add, may be negative
+     * @return a {@code YearMonth} based on this year-month with the years added, not null
+     * @throws DateTimeException if the result exceeds the supported range
+     */
+    public YearMonth plusYears(long yearsToAdd) {
+        if (yearsToAdd == 0) {
+            return this;
+        }
+        int newYear = YEAR.checkValidIntValue(year + yearsToAdd);  // safe overflow
+        return with(newYear, month);
+    }
+
+    /**
+     * Returns a copy of this year-month with the specified period in months added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param monthsToAdd  the months to add, may be negative
+     * @return a {@code YearMonth} based on this year-month with the months added, not null
+     * @throws DateTimeException if the result exceeds the supported range
+     */
+    public YearMonth plusMonths(long monthsToAdd) {
+        if (monthsToAdd == 0) {
+            return this;
+        }
+        long monthCount = year * 12L + (month - 1);
+        long calcMonths = monthCount + monthsToAdd;  // safe overflow
+        int newYear = YEAR.checkValidIntValue(Math.floorDiv(calcMonths, 12));
+        int newMonth = (int)Math.floorMod(calcMonths, 12) + 1;
+        return with(newYear, newMonth);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this year-month with the specified period subtracted.
+     * <p>
+     * This method returns a new year-month based on this year-month with the specified period subtracted.
+     * The subtractor is typically {@link java.time.Period} but may be any other type implementing
+     * the {@link TemporalSubtractor} interface.
+     * The calculation is delegated to the specified adjuster, which typically calls
+     * back to {@link #minus(long, TemporalUnit)}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param subtractor  the subtractor to use, not null
+     * @return a {@code YearMonth} based on this year-month with the subtraction made, not null
+     * @throws DateTimeException if the subtraction cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public YearMonth minus(TemporalSubtractor subtractor) {
+        return (YearMonth) subtractor.subtractFrom(this);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public YearMonth minus(long amountToSubtract, TemporalUnit unit) {
+        return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
+    }
+
+    /**
+     * Returns a copy of this year-month with the specified period in years subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param yearsToSubtract  the years to subtract, may be negative
+     * @return a {@code YearMonth} based on this year-month with the years subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported range
+     */
+    public YearMonth minusYears(long yearsToSubtract) {
+        return (yearsToSubtract == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-yearsToSubtract));
+    }
+
+    /**
+     * Returns a copy of this year-month with the specified period in months subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param monthsToSubtract  the months to subtract, may be negative
+     * @return a {@code YearMonth} based on this year-month with the months subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported range
+     */
+    public YearMonth minusMonths(long monthsToSubtract) {
+        return (monthsToSubtract == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-monthsToSubtract));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this year-month using the specified query.
+     * <p>
+     * This queries this year-month using the specified query strategy object.
+     * The {@code TemporalQuery} object defines the logic to be used to
+     * obtain the result. Read the documentation of the query to understand
+     * what the result of this method will be.
+     * <p>
+     * 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 <R> 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> R query(TemporalQuery<R> query) {
+        if (query == Queries.chrono()) {
+            return (R) ISOChrono.INSTANCE;
+        } else if (query == Queries.precision()) {
+            return (R) MONTHS;
+        }
+        return Temporal.super.query(query);
+    }
+
+    /**
+     * Adjusts the specified temporal object to have this year-month.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with the year and month changed to be the same as this.
+     * <p>
+     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+     * passing {@link ChronoField#EPOCH_MONTH} as the field.
+     * If the specified temporal object does not use the ISO calendar system then
+     * a {@code DateTimeException} is thrown.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisYearMonth.adjustInto(temporal);
+     *   temporal = temporal.with(thisYearMonth);
+     * </pre>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param temporal  the target object to be adjusted, not null
+     * @return the adjusted object, not null
+     * @throws DateTimeException if unable to make the adjustment
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Temporal adjustInto(Temporal temporal) {
+        if (Chrono.from(temporal).equals(ISOChrono.INSTANCE) == false) {
+            throw new DateTimeException("Adjustment only supported on ISO date-time");
+        }
+        return temporal.with(EPOCH_MONTH, getEpochMonth());
+    }
+
+    /**
+     * Calculates the period between this year-month and another year-month in
+     * terms of the specified unit.
+     * <p>
+     * This calculates the period between two year-months in terms of a single unit.
+     * The start and end points are {@code this} and the specified year-month.
+     * The result will be negative if the end is before the start.
+     * The {@code Temporal} passed to this method must be a {@code YearMonth}.
+     * For example, the period in years between two year-months can be calculated
+     * using {@code startYearMonth.periodUntil(endYearMonth, YEARS)}.
+     * <p>
+     * The calculation returns a whole number, representing the number of
+     * complete units between the two year-months.
+     * For example, the period in decades between 2012-06 and 2032-05
+     * will only be one decade as it is one month short of two decades.
+     * <p>
+     * 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:
+     * <pre>
+     *   long period = start.periodUntil(end, YEARS);   // this method
+     *   dateTime.plus(YEARS.between(start, end));      // use in plus/minus
+     * </pre>
+     * <p>
+     * The calculation is implemented in this method for {@link ChronoUnit}.
+     * The units {@code MONTHS}, {@code YEARS}, {@code DECADES},
+     * {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS} are supported.
+     * Other {@code ChronoUnit} values will throw an exception.
+     * <p>
+     * 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.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param endYearMonth  the end year-month, which must be a {@code YearMonth}, not null
+     * @param unit  the unit to measure the period in, not null
+     * @return the amount of the period between this year-month and the end year-month
+     * @throws DateTimeException if the period cannot be calculated
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long periodUntil(Temporal endYearMonth, TemporalUnit unit) {
+        if (endYearMonth instanceof YearMonth == false) {
+            Objects.requireNonNull(endYearMonth, "endYearMonth");
+            throw new DateTimeException("Unable to calculate period between objects of two different types");
+        }
+        YearMonth end = (YearMonth) endYearMonth;
+        if (unit instanceof ChronoUnit) {
+            long monthsUntil = end.getEpochMonth() - getEpochMonth();  // no overflow
+            switch ((ChronoUnit) unit) {
+                case MONTHS: return monthsUntil;
+                case YEARS: return monthsUntil / 12;
+                case DECADES: return monthsUntil / 120;
+                case CENTURIES: return monthsUntil / 1200;
+                case MILLENNIA: return monthsUntil / 12000;
+                case ERAS: return end.getLong(ERA) - getLong(ERA);
+            }
+            throw new DateTimeException("Unsupported unit: " + unit.getName());
+        }
+        return unit.between(this, endYearMonth).getAmount();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a date formed from this year-month at the specified day-of-month.
+     * <p>
+     * This combines this year-month and the specified day-of-month to form a {@code LocalDate}.
+     * The day-of-month value must be valid for the year-month.
+     * <p>
+     * This method can be used as part of a chain to produce a date:
+     * <pre>
+     *  LocalDate date = year.atMonth(month).atDay(day);
+     * </pre>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param dayOfMonth  the day-of-month to use, from 1 to 31
+     * @return the date formed from this year-month and the specified day, not null
+     * @throws DateTimeException when the day is invalid for the year-month
+     * @see #isValidDay(int)
+     */
+    public LocalDate atDay(int dayOfMonth) {
+        return LocalDate.of(year, month, dayOfMonth);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this year-month to another year-month.
+     * <p>
+     * The comparison is based first on the value of the year, then on the value of the month.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     *
+     * @param other  the other year-month to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     */
+    @Override
+    public int compareTo(YearMonth other) {
+        int cmp = (year - other.year);
+        if (cmp == 0) {
+            cmp = (month - other.month);
+        }
+        return cmp;
+    }
+
+    /**
+     * Is this year-month after the specified year-month.
+     *
+     * @param other  the other year-month to compare to, not null
+     * @return true if this is after the specified year-month
+     */
+    public boolean isAfter(YearMonth other) {
+        return compareTo(other) > 0;
+    }
+
+    /**
+     * Is this year-month before the specified year-month.
+     *
+     * @param other  the other year-month to compare to, not null
+     * @return true if this point is before the specified year-month
+     */
+    public boolean isBefore(YearMonth other) {
+        return compareTo(other) < 0;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this year-month is equal to another year-month.
+     * <p>
+     * The comparison is based on the time-line position of the year-months.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other year-month
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof YearMonth) {
+            YearMonth other = (YearMonth) obj;
+            return year == other.year && month == other.month;
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this year-month.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return year ^ (month << 27);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this year-month as a {@code String}, such as {@code 2007-12}.
+     * <p>
+     * The output will be in the format {@code yyyy-MM}:
+     *
+     * @return a string representation of this year-month, not null
+     */
+    @Override
+    public String toString() {
+        int absYear = Math.abs(year);
+        StringBuilder buf = new StringBuilder(9);
+        if (absYear < 1000) {
+            if (year < 0) {
+                buf.append(year - 10000).deleteCharAt(1);
+            } else {
+                buf.append(year + 10000).deleteCharAt(0);
+            }
+        } else {
+            buf.append(year);
+        }
+        return buf.append(month < 10 ? "-0" : "-")
+            .append(month)
+            .toString();
+    }
+
+    /**
+     * Outputs this year-month as a {@code String} using the formatter.
+     * <p>
+     * This year-month will be passed to the formatter
+     * {@link DateTimeFormatter#print(TemporalAccessor) print method}.
+     *
+     * @param formatter  the formatter to use, not null
+     * @return the formatted year-month string, not null
+     * @throws DateTimeException if an error occurs during printing
+     */
+    public String toString(DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.print(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>.
+     * <pre>
+     *  out.writeByte(5);  // identifies this as a Year
+     *  out.writeInt(year);
+     *  out.writeByte(month);
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.YEAR_MONTH_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     * @return never
+     * @throws InvalidObjectException always
+     */
+    private Object readResolve() throws ObjectStreamException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        out.writeInt(year);
+        out.writeByte(month);
+    }
+
+    static YearMonth readExternal(DataInput in) throws IOException {
+        int year = in.readInt();
+        byte month = in.readByte();
+        return YearMonth.of(year, month);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/temporal/package-info.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * <p>
+ * Access to date and time using fields and units, additional value type classes and
+ * base support for calendar systems other than the default ISO.
+ * </p>
+ * <p>
+ * This package expands on the base package to provide additional functionality for
+ * more powerful use cases. Support is included for:
+ * </p>
+ * <ul>
+ * <li>Units of date-time, such as years, months, days and hours</li>
+ * <li>Fields of date-time, such as month-of-year, day-of-week or hour-of-day</li>
+ * <li>Date-time adjustment functions</li>
+ * <li>Different definitions of weeks</li>
+ * <li>Alternate calendar systems</li>
+ * <li>Additional value types</li>
+ * </ul>
+ *
+ * <h3>Fields and Units</h3>
+ * <p>
+ * Dates and times are expressed in terms of fields and units.
+ * A unit is used to measure an amount of time, such as years, days or minutes.
+ * All units implement {@link java.time.temporal.TemporalUnit}.
+ * The set of well known units is defined in {@link java.time.temporal.ChronoUnit}, such as {@code DAYS}.
+ * The unit interface is designed to allow applications defined units.
+ * </p>
+ * <p>
+ * A field is used to express part of a larger date-time, such as year, month-of-year or second-of-minute.
+ * All fields implement {@link java.time.temporal.TemporalField}.
+ * The set of well known fields are defined in {@link java.time.temporal.ChronoField}, such as {@code HOUR_OF_DAY}.
+ * Additional fields are defined by {@link java.time.temporal.JulianFields}, {@link java.time.temporal.WeekFields}
+ * and {@link java.time.temporal.ISOFields}.
+ * The field interface is designed to allow applications defined fields.
+ * </p>
+ * <p>
+ * This package provides tools that allow the units and fields of date and time to be accessed
+ * in a general way most suited for frameworks.
+ * {@link java.time.temporal.Temporal} provides the abstraction for date time types that support fields.
+ * Its methods support getting the value of a field, creating a new date time with the value of
+ * a field modified, and querying for additional information, typically used to extract the offset or time-zone.
+ * </p>
+ * <p>
+ * One use of fields in application code is to retrieve fields for which there is no convenience method.
+ * For example, getting the day-of-month is common enough that there is a method on {@code LocalDate}
+ * called {@code getDayOfMonth()}. However for more unusual fields it is necessary to use the field.
+ * For example, {@code date.get(ChronoField.ALIGNED_WEEK_OF_MONTH)}.
+ * The fields also provide access to the range of valid values.
+ * </p>
+ *
+ * <h3>Adjustment and Query</h3>
+ * <p>
+ * A key part of the date-time problem space is adjusting a date to a new, related value,
+ * such as the "last day of the month", or "next Wednesday".
+ * These are modeled as functions that adjust a base date-time.
+ * The functions implement {@link java.time.temporal.TemporalAdjuster} and operate on {@code Temporal}.
+ * A set of common functions are provided in {@link java.time.temporal.Adjusters}.
+ * For example, to find the first occurrence of a day-of-week after a given date, use
+ * {@link java.time.temporal.Adjusters#next(DayOfWeek)}, such as
+ * {@code date.with(next(MONDAY))}.
+ * Applications can also define adjusters by implementing {@code TemporalAdjuster}.
+ * </p>
+ * <p>
+ * 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}.
+ * </p>
+ * <p>
+ * In addition to adjusting a date-time, an interface is provided to enable querying -
+ * {@link java.time.temporal.TemporalQuery}.
+ * The most common implementations of the query interface are method references.
+ * The {@code from(TemporalAccessor)} methods on major classes can all be used, such as
+ * {@code LocalDate::from} or {@code Month::from}.
+ * Further implementations are provided in {@link java.time.temporal.Queries}.
+ * Applications can also define queries by implementing {@code TemporalQuery}.
+ * </p>
+ *
+ * <h3>Weeks</h3>
+ * <p>
+ * Different locales have different definitions of the week.
+ * For example, in Europe the week typically starts on a Monday, while in the US it starts on a Sunday.
+ * The {@link java.time.temporal.WeekFields} class models this distinction.
+ * </p>
+ * <p>
+ * 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}.
+ * </p>
+ *
+ * <h3>Alternate calendar systems</h3>
+ * <p>
+ * 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.
+ * </p>
+ * <p>
+ * 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.
+ * </p>
+ * <p>
+ * 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.
+ * </p>
+ * <p>
+ * 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.
+ * </p>
+ * <p>
+ * This example creates and uses a date in a non-ISO calendar system.
+ * </p>
+ * <pre>
+ *   // Print the Thai Buddhist date
+ *       ChronoLocalDate&lt;ThaiBuddhistChrono&gt; 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&lt;Chrono&lt;?&gt;&gt; chronos = Chrono.getAvailableChronologies();
+ *       for (Chrono&lt;?&gt; chrono : chronos) {
+ *         ChronoLocalDate&lt;?&gt; 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&lt;ThaiBuddhistChrono&gt; first = now1
+ *                 .with(ChronoField.DAY_OF_MONTH, 1)
+ *                 .with(ChronoField.MONTH_OF_YEAR, 1);
+ *       ChronoLocalDate&lt;ThaiBuddhistChrono&gt; 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);
+ *  </pre>
+ *
+ * <h3>Package specification</h3>
+ * <p>
+ * 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.
+ * </p>
+ * <p>
+ * All calculations should check for numeric overflow and throw either an {@link java.lang.ArithmeticException}
+ * or a {@link java.time.DateTimeException}.
+ * </p>
+ * @since JDK1.8
+ */
+package java.time.temporal;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/zone/Ser.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.zone;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.InvalidClassException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.StreamCorruptedException;
+import java.time.ZoneOffset;
+
+/**
+ * The shared serialization delegate for this package.
+ *
+ * <h3>Implementation notes</h3>
+ * This class is mutable and should be created once per serialization.
+ *
+ * @serial include
+ * @since 1.8
+ */
+final class Ser implements Externalizable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -8885321777449118786L;
+
+    /** Type for ZoneRules. */
+    static final byte ZRULES = 1;
+    /** Type for ZoneOffsetTransition. */
+    static final byte ZOT = 2;
+    /** Type for ZoneOffsetTransition. */
+    static final byte ZOTRULE = 3;
+
+    /** The type being serialized. */
+    private byte type;
+    /** The object being serialized. */
+    private Object object;
+
+    /**
+     * Constructor for deserialization.
+     */
+    public Ser() {
+    }
+
+    /**
+     * Creates an instance for serialization.
+     *
+     * @param type  the type
+     * @param object  the object
+     */
+    Ser(byte type, Object object) {
+        this.type = type;
+        this.object = object;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Implements the {@code Externalizable} interface to write the object.
+     *
+     * @param out  the data stream to write to, not null
+     */
+    public void writeExternal(ObjectOutput out) throws IOException {
+        writeInternal(type, object, out);
+    }
+
+    static void write(Object object, DataOutput out) throws IOException {
+        writeInternal(ZRULES, object, out);
+    }
+
+    private static void writeInternal(byte type, Object object, DataOutput out) throws IOException {
+        out.writeByte(type);
+        switch (type) {
+            case ZRULES:
+                ((ZoneRules) object).writeExternal(out);
+                break;
+            case ZOT:
+                ((ZoneOffsetTransition) object).writeExternal(out);
+                break;
+            case ZOTRULE:
+                ((ZoneOffsetTransitionRule) object).writeExternal(out);
+                break;
+            default:
+                throw new InvalidClassException("Unknown serialized type");
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Implements the {@code Externalizable} interface to read the object.
+     *
+     * @param in  the data to read, not null
+     */
+    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+        type = in.readByte();
+        object = readInternal(type, in);
+    }
+
+    static Object read(DataInput in) throws IOException, ClassNotFoundException {
+        byte type = in.readByte();
+        return readInternal(type, in);
+    }
+
+    private static Object readInternal(byte type, DataInput in) throws IOException, ClassNotFoundException {
+        switch (type) {
+            case ZRULES:
+                return ZoneRules.readExternal(in);
+            case ZOT:
+                return ZoneOffsetTransition.readExternal(in);
+            case ZOTRULE:
+                return ZoneOffsetTransitionRule.readExternal(in);
+            default:
+                throw new StreamCorruptedException("Unknown serialized type");
+        }
+    }
+
+    /**
+     * Returns the object that will replace this one.
+     *
+     * @return the read object, should never be null
+     */
+    private Object readResolve() {
+         return object;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the state to the stream.
+     *
+     * @param offset  the offset, not null
+     * @param out  the output stream, not null
+     * @throws IOException if an error occurs
+     */
+    static void writeOffset(ZoneOffset offset, DataOutput out) throws IOException {
+        final int offsetSecs = offset.getTotalSeconds();
+        int offsetByte = offsetSecs % 900 == 0 ? offsetSecs / 900 : 127;  // compress to -72 to +72
+        out.writeByte(offsetByte);
+        if (offsetByte == 127) {
+            out.writeInt(offsetSecs);
+        }
+    }
+
+    /**
+     * Reads the state from the stream.
+     *
+     * @param in  the input stream, not null
+     * @return the created object, not null
+     * @throws IOException if an error occurs
+     */
+    static ZoneOffset readOffset(DataInput in) throws IOException {
+        int offsetByte = in.readByte();
+        return (offsetByte == 127 ? ZoneOffset.ofTotalSeconds(in.readInt()) : ZoneOffset.ofTotalSeconds(offsetByte * 900));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the state to the stream.
+     *
+     * @param epochSec  the epoch seconds, not null
+     * @param out  the output stream, not null
+     * @throws IOException if an error occurs
+     */
+    static void writeEpochSec(long epochSec, DataOutput out) throws IOException {
+        if (epochSec >= -4575744000L && epochSec < 10413792000L && epochSec % 900 == 0) {  // quarter hours between 1825 and 2300
+            int store = (int) ((epochSec + 4575744000L) / 900);
+            out.writeByte((store >>> 16) & 255);
+            out.writeByte((store >>> 8) & 255);
+            out.writeByte(store & 255);
+        } else {
+            out.writeByte(255);
+            out.writeLong(epochSec);
+        }
+    }
+
+    /**
+     * Reads the state from the stream.
+     *
+     * @param in  the input stream, not null
+     * @return the epoch seconds, not null
+     * @throws IOException if an error occurs
+     */
+    static long readEpochSec(DataInput in) throws IOException {
+        int hiByte = in.readByte() & 255;
+        if (hiByte == 255) {
+            return in.readLong();
+        } else {
+            int midByte = in.readByte() & 255;
+            int loByte = in.readByte() & 255;
+            long tot = ((hiByte << 16) + (midByte << 8) + loByte);
+            return (tot * 900) - 4575744000L;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/zone/TzdbZoneRulesProvider.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.zone;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.StreamCorruptedException;
+import java.nio.file.FileSystems;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+import java.time.DateTimeException;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.NavigableMap;
+import java.util.Objects;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.concurrent.ConcurrentNavigableMap;
+import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.atomic.AtomicReferenceArray;
+import java.util.zip.ZipFile;
+
+/**
+ * Loads time-zone rules for 'TZDB'.
+ * <p>
+ * This class is public for the service loader to access.
+ *
+ * <h3>Specification for implementors</h3>
+ * 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<String> regionIds = new CopyOnWriteArraySet<>();
+    /**
+     * All the versions that are available.
+     */
+    private final ConcurrentNavigableMap<String, Version> versions = new ConcurrentSkipListMap<>();
+
+    /**
+     * Creates an instance.
+     * Created by the {@code ServiceLoader}.
+     *
+     * @throws ZoneRulesException if unable to load
+     */
+    public TzdbZoneRulesProvider() {
+        super();
+        if (load(ClassLoader.getSystemClassLoader()) == false) {
+            throw new ZoneRulesException("No time-zone rules found for 'TZDB'");
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    protected Set<String> provideZoneIds() {
+        return new HashSet<>(regionIds);
+    }
+
+    @Override
+    protected ZoneRules provideRules(String zoneId) {
+        Objects.requireNonNull(zoneId, "zoneId");
+        ZoneRules rules = versions.lastEntry().getValue().getRules(zoneId);
+        if (rules == null) {
+            throw new ZoneRulesException("Unknown time-zone ID: " + zoneId);
+        }
+        return rules;
+    }
+
+    @Override
+    protected NavigableMap<String, ZoneRules> provideVersions(String zoneId) {
+        TreeMap<String, ZoneRules> map = new TreeMap<>();
+        for (Version version : versions.values()) {
+            ZoneRules rules = version.getRules(zoneId);
+            if (rules != null) {
+                map.put(version.versionId, rules);
+            }
+        }
+        return map;
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Loads the rules.
+     *
+     * @param classLoader  the class loader to use, not null
+     * @return true if updated
+     * @throws ZoneRulesException if unable to load
+     */
+    private boolean load(ClassLoader classLoader) {
+        Object updated = Boolean.FALSE;
+        try {
+            updated = AccessController.doPrivileged(new PrivilegedExceptionAction() {
+                public Object run() throws IOException, ClassNotFoundException {
+                    File tzdbJar = null;
+                    // TBD: workaround for now, so test/java/time tests can be
+                    //      run against Java runtime that does not have tzdb
+                    String tzdbProp = System.getProperty("java.time.zone.tzdbjar");
+                    if (tzdbProp != null) {
+                        tzdbJar = new File(tzdbProp);
+                    } else {
+                        String libDir = System.getProperty("java.home") + File.separator + "lib";
+                        try {
+                            libDir = FileSystems.getDefault().getPath(libDir).toRealPath().toString();
+                        } catch(Exception e) {}
+                        tzdbJar = new File(libDir, "tzdb.jar");
+                    }
+                    try (ZipFile zf = new ZipFile(tzdbJar);
+                         DataInputStream dis = new DataInputStream(
+                             zf.getInputStream(zf.getEntry("TZDB.dat")))) {
+                        Iterable<Version> 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<Version> load(DataInputStream dis) throws ClassNotFoundException, IOException {
+        if (dis.readByte() != 1) {
+            throw new StreamCorruptedException("File format not recognised");
+        }
+        // group
+        String groupId = dis.readUTF();
+        if ("TZDB".equals(groupId) == false) {
+            throw new StreamCorruptedException("File format not recognised");
+        }
+        // versions
+        int versionCount = dis.readShort();
+        String[] versionArray = new String[versionCount];
+        for (int i = 0; i < versionCount; i++) {
+            versionArray[i] = dis.readUTF();
+        }
+        // regions
+        int regionCount = dis.readShort();
+        String[] regionArray = new String[regionCount];
+        for (int i = 0; i < regionCount; i++) {
+            regionArray[i] = dis.readUTF();
+        }
+        regionIds.addAll(Arrays.asList(regionArray));
+        // rules
+        int ruleCount = dis.readShort();
+        Object[] ruleArray = new Object[ruleCount];
+        for (int i = 0; i < ruleCount; i++) {
+            byte[] bytes = new byte[dis.readShort()];
+            dis.readFully(bytes);
+            ruleArray[i] = bytes;
+        }
+        AtomicReferenceArray<Object> ruleData = new AtomicReferenceArray<>(ruleArray);
+        // link version-region-rules
+        Set<Version> versionSet = new HashSet<Version>(versionCount);
+        for (int i = 0; i < versionCount; i++) {
+            int versionRegionCount = dis.readShort();
+            String[] versionRegionArray = new String[versionRegionCount];
+            short[] versionRulesArray = new short[versionRegionCount];
+            for (int j = 0; j < versionRegionCount; j++) {
+                versionRegionArray[j] = regionArray[dis.readShort()];
+                versionRulesArray[j] = dis.readShort();
+            }
+            versionSet.add(new Version(versionArray[i], versionRegionArray, versionRulesArray, ruleData));
+        }
+        return versionSet;
+    }
+
+    @Override
+    public String toString() {
+        return "TZDB";
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * A version of the TZDB rules.
+     */
+    static class Version {
+        private final String versionId;
+        private final String[] regionArray;
+        private final short[] ruleIndices;
+        private final AtomicReferenceArray<Object> ruleData;
+
+        Version(String versionId, String[] regionIds, short[] ruleIndices, AtomicReferenceArray<Object> 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;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/zone/ZoneOffsetTransition.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,431 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.zone;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.Serializable;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A transition between two offsets caused by a discontinuity in the local time-line.
+ * <p>
+ * A transition between two offsets is normally the result of a daylight savings cutover.
+ * The discontinuity is normally a gap in spring and an overlap in autumn.
+ * {@code ZoneOffsetTransition} models the transition between the two offsets.
+ * <p>
+ * Gaps occur where there are local date-times that simply do not not exist.
+ * An example would be when the offset changes from {@code +03:00} to {@code +04:00}.
+ * This might be described as 'the clocks will move forward one hour tonight at 1am'.
+ * <p>
+ * Overlaps occur where there are local date-times that exist twice.
+ * An example would be when the offset changes from {@code +04:00} to {@code +03:00}.
+ * This might be described as 'the clocks will move back one hour tonight at 2am'.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class ZoneOffsetTransition
+        implements Comparable<ZoneOffsetTransition>, Serializable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -6946044323557704546L;
+    /**
+     * The local transition date-time at the transition.
+     */
+    private final LocalDateTime transition;
+    /**
+     * The offset before transition.
+     */
+    private final ZoneOffset offsetBefore;
+    /**
+     * The offset after transition.
+     */
+    private final ZoneOffset offsetAfter;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance defining a transition between two offsets.
+     * <p>
+     * Applications should normally obtain an instance from {@link ZoneRules}.
+     * This factory is only intended for use when creating {@link ZoneRules}.
+     *
+     * @param transition  the transition date-time at the transition, which never
+     *  actually occurs, expressed local to the before offset, not null
+     * @param offsetBefore  the offset before the transition, not null
+     * @param offsetAfter  the offset at and after the transition, not null
+     * @return the transition, not null
+     * @throws IllegalArgumentException if {@code offsetBefore} and {@code offsetAfter}
+     *         are equal, or {@code transition.getNano()} returns non-zero value
+     */
+    public static ZoneOffsetTransition of(LocalDateTime transition, ZoneOffset offsetBefore, ZoneOffset offsetAfter) {
+        Objects.requireNonNull(transition, "transition");
+        Objects.requireNonNull(offsetBefore, "offsetBefore");
+        Objects.requireNonNull(offsetAfter, "offsetAfter");
+        if (offsetBefore.equals(offsetAfter)) {
+            throw new IllegalArgumentException("Offsets must not be equal");
+        }
+        if (transition.getNano() != 0) {
+            throw new IllegalArgumentException("Nano-of-second must be zero");
+        }
+        return new ZoneOffsetTransition(transition, offsetBefore, offsetAfter);
+    }
+
+    /**
+     * Creates an instance defining a transition between two offsets.
+     *
+     * @param transition  the transition date-time with the offset before the transition, not null
+     * @param offsetBefore  the offset before the transition, not null
+     * @param offsetAfter  the offset at and after the transition, not null
+     */
+    ZoneOffsetTransition(LocalDateTime transition, ZoneOffset offsetBefore, ZoneOffset offsetAfter) {
+        this.transition = transition;
+        this.offsetBefore = offsetBefore;
+        this.offsetAfter = offsetAfter;
+    }
+
+    /**
+     * Creates an instance from epoch-second and offsets.
+     *
+     * @param epochSecond  the transition epoch-second
+     * @param offsetBefore  the offset before the transition, not null
+     * @param offsetAfter  the offset at and after the transition, not null
+     */
+    ZoneOffsetTransition(long epochSecond, ZoneOffset offsetBefore, ZoneOffset offsetAfter) {
+        this.transition = LocalDateTime.ofEpochSecond(epochSecond, 0, offsetBefore);
+        this.offsetBefore = offsetBefore;
+        this.offsetAfter = offsetAfter;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Uses a serialization delegate.
+     *
+     * @return the replacing object, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.ZOT, this);
+    }
+
+    /**
+     * Writes the state to the stream.
+     *
+     * @param out  the output stream, not null
+     * @throws IOException if an error occurs
+     */
+    void writeExternal(DataOutput out) throws IOException {
+        Ser.writeEpochSec(toEpochSecond(), out);
+        Ser.writeOffset(offsetBefore, out);
+        Ser.writeOffset(offsetAfter, out);
+    }
+
+    /**
+     * Reads the state from the stream.
+     *
+     * @param in  the input stream, not null
+     * @return the created object, not null
+     * @throws IOException if an error occurs
+     */
+    static ZoneOffsetTransition readExternal(DataInput in) throws IOException {
+        long epochSecond = Ser.readEpochSec(in);
+        ZoneOffset before = Ser.readOffset(in);
+        ZoneOffset after = Ser.readOffset(in);
+        if (before.equals(after)) {
+            throw new IllegalArgumentException("Offsets must not be equal");
+        }
+        return new ZoneOffsetTransition(epochSecond, before, after);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the transition instant.
+     * <p>
+     * This is the instant of the discontinuity, which is defined as the first
+     * instant that the 'after' offset applies.
+     * <p>
+     * The methods {@link #getInstant()}, {@link #getDateTimeBefore()} and {@link #getDateTimeAfter()}
+     * all represent the same instant.
+     *
+     * @return the transition instant, not null
+     */
+    public Instant getInstant() {
+        return transition.toInstant(offsetBefore);
+    }
+
+    /**
+     * Gets the transition instant as an epoch second.
+     *
+     * @return the transition epoch second
+     */
+    public long toEpochSecond() {
+        return transition.toEpochSecond(offsetBefore);
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Gets the local transition date-time, as would be expressed with the 'before' offset.
+     * <p>
+     * This is the date-time where the discontinuity begins expressed with the 'before' offset.
+     * At this instant, the 'after' offset is actually used, therefore the combination of this
+     * date-time and the 'before' offset will never occur.
+     * <p>
+     * The combination of the 'before' date-time and offset represents the same instant
+     * as the 'after' date-time and offset.
+     *
+     * @return the transition date-time expressed with the before offset, not null
+     */
+    public LocalDateTime getDateTimeBefore() {
+        return transition;
+    }
+
+    /**
+     * Gets the local transition date-time, as would be expressed with the 'after' offset.
+     * <p>
+     * This is the first date-time after the discontinuity, when the new offset applies.
+     * <p>
+     * The combination of the 'before' date-time and offset represents the same instant
+     * as the 'after' date-time and offset.
+     *
+     * @return the transition date-time expressed with the after offset, not null
+     */
+    public LocalDateTime getDateTimeAfter() {
+        return transition.plusSeconds(getDurationSeconds());
+    }
+
+    /**
+     * Gets the offset before the transition.
+     * <p>
+     * This is the offset in use before the instant of the transition.
+     *
+     * @return the offset before the transition, not null
+     */
+    public ZoneOffset getOffsetBefore() {
+        return offsetBefore;
+    }
+
+    /**
+     * Gets the offset after the transition.
+     * <p>
+     * This is the offset in use on and after the instant of the transition.
+     *
+     * @return the offset after the transition, not null
+     */
+    public ZoneOffset getOffsetAfter() {
+        return offsetAfter;
+    }
+
+    /**
+     * Gets the duration of the transition.
+     * <p>
+     * In most cases, the transition duration is one hour, however this is not always the case.
+     * The duration will be positive for a gap and negative for an overlap.
+     * Time-zones are second-based, so the nanosecond part of the duration will be zero.
+     *
+     * @return the duration of the transition, positive for gaps, negative for overlaps
+     */
+    public Duration getDuration() {
+        return Duration.ofSeconds(getDurationSeconds());
+    }
+
+    /**
+     * Gets the duration of the transition in seconds.
+     *
+     * @return the duration in seconds
+     */
+    private int getDurationSeconds() {
+        return getOffsetAfter().getTotalSeconds() - getOffsetBefore().getTotalSeconds();
+    }
+
+    /**
+     * Does this transition represent a gap in the local time-line.
+     * <p>
+     * Gaps occur where there are local date-times that simply do not not exist.
+     * An example would be when the offset changes from {@code +01:00} to {@code +02:00}.
+     * This might be described as 'the clocks will move forward one hour tonight at 1am'.
+     *
+     * @return true if this transition is a gap, false if it is an overlap
+     */
+    public boolean isGap() {
+        return getOffsetAfter().getTotalSeconds() > getOffsetBefore().getTotalSeconds();
+    }
+
+    /**
+     * Does this transition represent a gap in the local time-line.
+     * <p>
+     * Overlaps occur where there are local date-times that exist twice.
+     * An example would be when the offset changes from {@code +02:00} to {@code +01:00}.
+     * This might be described as 'the clocks will move back one hour tonight at 2am'.
+     *
+     * @return true if this transition is an overlap, false if it is a gap
+     */
+    public boolean isOverlap() {
+        return getOffsetAfter().getTotalSeconds() < getOffsetBefore().getTotalSeconds();
+    }
+
+    /**
+     * Checks if the specified offset is valid during this transition.
+     * <p>
+     * This checks to see if the given offset will be valid at some point in the transition.
+     * A gap will always return false.
+     * An overlap will return true if the offset is either the before or after offset.
+     *
+     * @param offset  the offset to check, null returns false
+     * @return true if the offset is valid during the transition
+     */
+    public boolean isValidOffset(ZoneOffset offset) {
+        return isGap() ? false : (getOffsetBefore().equals(offset) || getOffsetAfter().equals(offset));
+    }
+
+    /**
+     * Gets the valid offsets during this transition.
+     * <p>
+     * A gap will return an empty list, while an overlap will return both offsets.
+     *
+     * @return the list of valid offsets
+     */
+    List<ZoneOffset> getValidOffsets() {
+        if (isGap()) {
+            return Collections.emptyList();
+        }
+        return Arrays.asList(getOffsetBefore(), getOffsetAfter());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this transition to another based on the transition instant.
+     * <p>
+     * This compares the instants of each transition.
+     * The offsets are ignored, making this order inconsistent with equals.
+     *
+     * @param transition  the transition to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     */
+    @Override
+    public int compareTo(ZoneOffsetTransition transition) {
+        return this.getInstant().compareTo(transition.getInstant());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this object equals another.
+     * <p>
+     * The entire state of the object is compared.
+     *
+     * @param other  the other object to compare to, null returns false
+     * @return true if equal
+     */
+    @Override
+    public boolean equals(Object other) {
+        if (other == this) {
+            return true;
+        }
+        if (other instanceof ZoneOffsetTransition) {
+            ZoneOffsetTransition d = (ZoneOffsetTransition) other;
+            return transition.equals(d.transition) &&
+                offsetBefore.equals(d.offsetBefore) && offsetAfter.equals(d.offsetAfter);
+        }
+        return false;
+    }
+
+    /**
+     * Returns a suitable hash code.
+     *
+     * @return the hash code
+     */
+    @Override
+    public int hashCode() {
+        return transition.hashCode() ^ offsetBefore.hashCode() ^ Integer.rotateLeft(offsetAfter.hashCode(), 16);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a string describing this object.
+     *
+     * @return a string for debugging, not null
+     */
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder();
+        buf.append("Transition[")
+            .append(isGap() ? "Gap" : "Overlap")
+            .append(" at ")
+            .append(transition)
+            .append(offsetBefore)
+            .append(" to ")
+            .append(offsetAfter)
+            .append(']');
+        return buf.toString();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/zone/ZoneOffsetTransitionRule.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,575 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.zone;
+
+import static java.time.temporal.Adjusters.nextOrSame;
+import static java.time.temporal.Adjusters.previousOrSame;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.Serializable;
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.Month;
+import java.time.ZoneOffset;
+import java.time.temporal.ISOChrono;
+import java.util.Objects;
+
+/**
+ * A rule expressing how to create a transition.
+ * <p>
+ * This class allows rules for identifying future transitions to be expressed.
+ * A rule might be written in many forms:
+ * <p><ul>
+ * <li>the 16th March
+ * <li>the Sunday on or after the 16th March
+ * <li>the Sunday on or before the 16th March
+ * <li>the last Sunday in February
+ * </ul><p>
+ * These different rule types can be expressed and queried.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class ZoneOffsetTransitionRule implements Serializable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 6889046316657758795L;
+
+    /**
+     * The month of the month-day of the first day of the cutover week.
+     * The actual date will be adjusted by the dowChange field.
+     */
+    private final Month month;
+    /**
+     * The day-of-month of the month-day of the cutover week.
+     * If positive, it is the start of the week where the cutover can occur.
+     * If negative, it represents the end of the week where cutover can occur.
+     * The value is the number of days from the end of the month, such that
+     * {@code -1} is the last day of the month, {@code -2} is the second
+     * to last day, and so on.
+     */
+    private final byte dom;
+    /**
+     * The cutover day-of-week, null to retain the day-of-month.
+     */
+    private final DayOfWeek dow;
+    /**
+     * The cutover time in the 'before' offset.
+     */
+    private final LocalTime time;
+    /**
+     * Whether the cutover time is midnight at the end of day.
+     */
+    private final boolean timeEndOfDay;
+    /**
+     * The definition of how the local time should be interpreted.
+     */
+    private final TimeDefinition timeDefinition;
+    /**
+     * The standard offset at the cutover.
+     */
+    private final ZoneOffset standardOffset;
+    /**
+     * The offset before the cutover.
+     */
+    private final ZoneOffset offsetBefore;
+    /**
+     * The offset after the cutover.
+     */
+    private final ZoneOffset offsetAfter;
+
+    /**
+     * Obtains an instance defining the yearly rule to create transitions between two offsets.
+     * <p>
+     * Applications should normally obtain an instance from {@link ZoneRules}.
+     * This factory is only intended for use when creating {@link ZoneRules}.
+     *
+     * @param month  the month of the month-day of the first day of the cutover week, not null
+     * @param dayOfMonthIndicator  the day of the month-day of the cutover week, positive if the week is that
+     *  day or later, negative if the week is that day or earlier, counting from the last day of the month,
+     *  from -28 to 31 excluding 0
+     * @param dayOfWeek  the required day-of-week, null if the month-day should not be changed
+     * @param time  the cutover time in the 'before' offset, not null
+     * @param timeEndOfDay  whether the time is midnight at the end of day
+     * @param timeDefnition  how to interpret the cutover
+     * @param standardOffset  the standard offset in force at the cutover, not null
+     * @param offsetBefore  the offset before the cutover, not null
+     * @param offsetAfter  the offset after the cutover, not null
+     * @return the rule, not null
+     * @throws IllegalArgumentException if the day of month indicator is invalid
+     * @throws IllegalArgumentException if the end of day flag is true when the time is not midnight
+     */
+    public static ZoneOffsetTransitionRule of(
+            Month month,
+            int dayOfMonthIndicator,
+            DayOfWeek dayOfWeek,
+            LocalTime time,
+            boolean timeEndOfDay,
+            TimeDefinition timeDefnition,
+            ZoneOffset standardOffset,
+            ZoneOffset offsetBefore,
+            ZoneOffset offsetAfter) {
+        Objects.requireNonNull(month, "month");
+        Objects.requireNonNull(time, "time");
+        Objects.requireNonNull(timeDefnition, "timeDefnition");
+        Objects.requireNonNull(standardOffset, "standardOffset");
+        Objects.requireNonNull(offsetBefore, "offsetBefore");
+        Objects.requireNonNull(offsetAfter, "offsetAfter");
+        if (dayOfMonthIndicator < -28 || dayOfMonthIndicator > 31 || dayOfMonthIndicator == 0) {
+            throw new IllegalArgumentException("Day of month indicator must be between -28 and 31 inclusive excluding zero");
+        }
+        if (timeEndOfDay && time.equals(LocalTime.MIDNIGHT) == false) {
+            throw new IllegalArgumentException("Time must be midnight when end of day flag is true");
+        }
+        return new ZoneOffsetTransitionRule(month, dayOfMonthIndicator, dayOfWeek, time, timeEndOfDay, timeDefnition, standardOffset, offsetBefore, offsetAfter);
+    }
+
+    /**
+     * Creates an instance defining the yearly rule to create transitions between two offsets.
+     *
+     * @param month  the month of the month-day of the first day of the cutover week, not null
+     * @param dayOfMonthIndicator  the day of the month-day of the cutover week, positive if the week is that
+     *  day or later, negative if the week is that day or earlier, counting from the last day of the month,
+     *  from -28 to 31 excluding 0
+     * @param dayOfWeek  the required day-of-week, null if the month-day should not be changed
+     * @param time  the cutover time in the 'before' offset, not null
+     * @param timeEndOfDay  whether the time is midnight at the end of day
+     * @param timeDefnition  how to interpret the cutover
+     * @param standardOffset  the standard offset in force at the cutover, not null
+     * @param offsetBefore  the offset before the cutover, not null
+     * @param offsetAfter  the offset after the cutover, not null
+     * @throws IllegalArgumentException if the day of month indicator is invalid
+     * @throws IllegalArgumentException if the end of day flag is true when the time is not midnight
+     */
+    ZoneOffsetTransitionRule(
+            Month month,
+            int dayOfMonthIndicator,
+            DayOfWeek dayOfWeek,
+            LocalTime time,
+            boolean timeEndOfDay,
+            TimeDefinition timeDefnition,
+            ZoneOffset standardOffset,
+            ZoneOffset offsetBefore,
+            ZoneOffset offsetAfter) {
+        this.month = month;
+        this.dom = (byte) dayOfMonthIndicator;
+        this.dow = dayOfWeek;
+        this.time = time;
+        this.timeEndOfDay = timeEndOfDay;
+        this.timeDefinition = timeDefnition;
+        this.standardOffset = standardOffset;
+        this.offsetBefore = offsetBefore;
+        this.offsetAfter = offsetAfter;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Uses a serialization delegate.
+     *
+     * @return the replacing object, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.ZOTRULE, this);
+    }
+
+    /**
+     * Writes the state to the stream.
+     *
+     * @param out  the output stream, not null
+     * @throws IOException if an error occurs
+     */
+    void writeExternal(DataOutput out) throws IOException {
+        final int timeSecs = (timeEndOfDay ? 86400 : time.toSecondOfDay());
+        final int stdOffset = standardOffset.getTotalSeconds();
+        final int beforeDiff = offsetBefore.getTotalSeconds() - stdOffset;
+        final int afterDiff = offsetAfter.getTotalSeconds() - stdOffset;
+        final int timeByte = (timeSecs % 3600 == 0 ? (timeEndOfDay ? 24 : time.getHour()) : 31);
+        final int stdOffsetByte = (stdOffset % 900 == 0 ? stdOffset / 900 + 128 : 255);
+        final int beforeByte = (beforeDiff == 0 || beforeDiff == 1800 || beforeDiff == 3600 ? beforeDiff / 1800 : 3);
+        final int afterByte = (afterDiff == 0 || afterDiff == 1800 || afterDiff == 3600 ? afterDiff / 1800 : 3);
+        final int dowByte = (dow == null ? 0 : dow.getValue());
+        int b = (month.getValue() << 28) +          // 4 bits
+                ((dom + 32) << 22) +                // 6 bits
+                (dowByte << 19) +                   // 3 bits
+                (timeByte << 14) +                  // 5 bits
+                (timeDefinition.ordinal() << 12) +  // 2 bits
+                (stdOffsetByte << 4) +              // 8 bits
+                (beforeByte << 2) +                 // 2 bits
+                afterByte;                          // 2 bits
+        out.writeInt(b);
+        if (timeByte == 31) {
+            out.writeInt(timeSecs);
+        }
+        if (stdOffsetByte == 255) {
+            out.writeInt(stdOffset);
+        }
+        if (beforeByte == 3) {
+            out.writeInt(offsetBefore.getTotalSeconds());
+        }
+        if (afterByte == 3) {
+            out.writeInt(offsetAfter.getTotalSeconds());
+        }
+    }
+
+    /**
+     * Reads the state from the stream.
+     *
+     * @param in  the input stream, not null
+     * @return the created object, not null
+     * @throws IOException if an error occurs
+     */
+    static ZoneOffsetTransitionRule readExternal(DataInput in) throws IOException {
+        int data = in.readInt();
+        Month month = Month.of(data >>> 28);
+        int dom = ((data & (63 << 22)) >>> 22) - 32;
+        int dowByte = (data & (7 << 19)) >>> 19;
+        DayOfWeek dow = dowByte == 0 ? null : DayOfWeek.of(dowByte);
+        int timeByte = (data & (31 << 14)) >>> 14;
+        TimeDefinition defn = TimeDefinition.values()[(data & (3 << 12)) >>> 12];
+        int stdByte = (data & (255 << 4)) >>> 4;
+        int beforeByte = (data & (3 << 2)) >>> 2;
+        int afterByte = (data & 3);
+        LocalTime time = (timeByte == 31 ? LocalTime.ofSecondOfDay(in.readInt()) : LocalTime.of(timeByte % 24, 0));
+        ZoneOffset std = (stdByte == 255 ? ZoneOffset.ofTotalSeconds(in.readInt()) : ZoneOffset.ofTotalSeconds((stdByte - 128) * 900));
+        ZoneOffset before = (beforeByte == 3 ? ZoneOffset.ofTotalSeconds(in.readInt()) : ZoneOffset.ofTotalSeconds(std.getTotalSeconds() + beforeByte * 1800));
+        ZoneOffset after = (afterByte == 3 ? ZoneOffset.ofTotalSeconds(in.readInt()) : ZoneOffset.ofTotalSeconds(std.getTotalSeconds() + afterByte * 1800));
+        return ZoneOffsetTransitionRule.of(month, dom, dow, time, timeByte == 24, defn, std, before, after);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the month of the transition.
+     * <p>
+     * If the rule defines an exact date then the month is the month of that date.
+     * <p>
+     * If the rule defines a week where the transition might occur, then the month
+     * if the month of either the earliest or latest possible date of the cutover.
+     *
+     * @return the month of the transition, not null
+     */
+    public Month getMonth() {
+        return month;
+    }
+
+    /**
+     * Gets the indicator of the day-of-month of the transition.
+     * <p>
+     * If the rule defines an exact date then the day is the month of that date.
+     * <p>
+     * If the rule defines a week where the transition might occur, then the day
+     * defines either the start of the end of the transition week.
+     * <p>
+     * If the value is positive, then it represents a normal day-of-month, and is the
+     * earliest possible date that the transition can be.
+     * The date may refer to 29th February which should be treated as 1st March in non-leap years.
+     * <p>
+     * If the value is negative, then it represents the number of days back from the
+     * end of the month where {@code -1} is the last day of the month.
+     * In this case, the day identified is the latest possible date that the transition can be.
+     *
+     * @return the day-of-month indicator, from -28 to 31 excluding 0
+     */
+    public int getDayOfMonthIndicator() {
+        return dom;
+    }
+
+    /**
+     * Gets the day-of-week of the transition.
+     * <p>
+     * If the rule defines an exact date then this returns null.
+     * <p>
+     * If the rule defines a week where the cutover might occur, then this method
+     * returns the day-of-week that the month-day will be adjusted to.
+     * If the day is positive then the adjustment is later.
+     * If the day is negative then the adjustment is earlier.
+     *
+     * @return the day-of-week that the transition occurs, null if the rule defines an exact date
+     */
+    public DayOfWeek getDayOfWeek() {
+        return dow;
+    }
+
+    /**
+     * Gets the local time of day of the transition which must be checked with
+     * {@link #isMidnightEndOfDay()}.
+     * <p>
+     * The time is converted into an instant using the time definition.
+     *
+     * @return the local time of day of the transition, not null
+     */
+    public LocalTime getLocalTime() {
+        return time;
+    }
+
+    /**
+     * Is the transition local time midnight at the end of day.
+     * <p>
+     * The transition may be represented as occurring at 24:00.
+     *
+     * @return whether a local time of midnight is at the start or end of the day
+     */
+    public boolean isMidnightEndOfDay() {
+        return timeEndOfDay;
+    }
+
+    /**
+     * Gets the time definition, specifying how to convert the time to an instant.
+     * <p>
+     * The local time can be converted to an instant using the standard offset,
+     * the wall offset or UTC.
+     *
+     * @return the time definition, not null
+     */
+    public TimeDefinition getTimeDefinition() {
+        return timeDefinition;
+    }
+
+    /**
+     * Gets the standard offset in force at the transition.
+     *
+     * @return the standard offset, not null
+     */
+    public ZoneOffset getStandardOffset() {
+        return standardOffset;
+    }
+
+    /**
+     * Gets the offset before the transition.
+     *
+     * @return the offset before, not null
+     */
+    public ZoneOffset getOffsetBefore() {
+        return offsetBefore;
+    }
+
+    /**
+     * Gets the offset after the transition.
+     *
+     * @return the offset after, not null
+     */
+    public ZoneOffset getOffsetAfter() {
+        return offsetAfter;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Creates a transition instance for the specified year.
+     * <p>
+     * Calculations are performed using the ISO-8601 chronology.
+     *
+     * @param year  the year to create a transition for, not null
+     * @return the transition instance, not null
+     */
+    public ZoneOffsetTransition createTransition(int year) {
+        LocalDate date;
+        if (dom < 0) {
+            date = LocalDate.of(year, month, month.length(ISOChrono.INSTANCE.isLeapYear(year)) + 1 + dom);
+            if (dow != null) {
+                date = date.with(previousOrSame(dow));
+            }
+        } else {
+            date = LocalDate.of(year, month, dom);
+            if (dow != null) {
+                date = date.with(nextOrSame(dow));
+            }
+        }
+        if (timeEndOfDay) {
+            date = date.plusDays(1);
+        }
+        LocalDateTime localDT = LocalDateTime.of(date, time);
+        LocalDateTime transition = timeDefinition.createDateTime(localDT, standardOffset, offsetBefore);
+        return new ZoneOffsetTransition(transition, offsetBefore, offsetAfter);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this object equals another.
+     * <p>
+     * The entire state of the object is compared.
+     *
+     * @param otherRule  the other object to compare to, null returns false
+     * @return true if equal
+     */
+    @Override
+    public boolean equals(Object otherRule) {
+        if (otherRule == this) {
+            return true;
+        }
+        if (otherRule instanceof ZoneOffsetTransitionRule) {
+            ZoneOffsetTransitionRule other = (ZoneOffsetTransitionRule) otherRule;
+            return month == other.month && dom == other.dom && dow == other.dow &&
+                timeDefinition == other.timeDefinition &&
+                time.equals(other.time) &&
+                timeEndOfDay == other.timeEndOfDay &&
+                standardOffset.equals(other.standardOffset) &&
+                offsetBefore.equals(other.offsetBefore) &&
+                offsetAfter.equals(other.offsetAfter);
+        }
+        return false;
+    }
+
+    /**
+     * Returns a suitable hash code.
+     *
+     * @return the hash code
+     */
+    @Override
+    public int hashCode() {
+        int hash = ((time.toSecondOfDay() + (timeEndOfDay ? 1 : 0)) << 15) +
+                (month.ordinal() << 11) + ((dom + 32) << 5) +
+                ((dow == null ? 7 : dow.ordinal()) << 2) + (timeDefinition.ordinal());
+        return hash ^ standardOffset.hashCode() ^
+                offsetBefore.hashCode() ^ offsetAfter.hashCode();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a string describing this object.
+     *
+     * @return a string for debugging, not null
+     */
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder();
+        buf.append("TransitionRule[")
+            .append(offsetBefore.compareTo(offsetAfter) > 0 ? "Gap " : "Overlap ")
+            .append(offsetBefore).append(" to ").append(offsetAfter).append(", ");
+        if (dow != null) {
+            if (dom == -1) {
+                buf.append(dow.name()).append(" on or before last day of ").append(month.name());
+            } else if (dom < 0) {
+                buf.append(dow.name()).append(" on or before last day minus ").append(-dom - 1).append(" of ").append(month.name());
+            } else {
+                buf.append(dow.name()).append(" on or after ").append(month.name()).append(' ').append(dom);
+            }
+        } else {
+            buf.append(month.name()).append(' ').append(dom);
+        }
+        buf.append(" at ").append(timeEndOfDay ? "24:00" : time.toString())
+            .append(" ").append(timeDefinition)
+            .append(", standard offset ").append(standardOffset)
+            .append(']');
+        return buf.toString();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * A definition of the way a local time can be converted to the actual
+     * transition date-time.
+     * <p>
+     * Time zone rules are expressed in one of three ways:
+     * <p><ul>
+     * <li>Relative to UTC</li>
+     * <li>Relative to the standard offset in force</li>
+     * <li>Relative to the wall offset (what you would see on a clock on the wall)</li>
+     * </ul><p>
+     */
+    public static enum TimeDefinition {
+        /** The local date-time is expressed in terms of the UTC offset. */
+        UTC,
+        /** The local date-time is expressed in terms of the wall offset. */
+        WALL,
+        /** The local date-time is expressed in terms of the standard offset. */
+        STANDARD;
+
+        /**
+         * Converts the specified local date-time to the local date-time actually
+         * seen on a wall clock.
+         * <p>
+         * This method converts using the type of this enum.
+         * The output is defined relative to the 'before' offset of the transition.
+         * <p>
+         * The UTC type uses the UTC offset.
+         * The STANDARD type uses the standard offset.
+         * The WALL type returns the input date-time.
+         * The result is intended for use with the wall-offset.
+         *
+         * @param dateTime  the local date-time, not null
+         * @param standardOffset  the standard offset, not null
+         * @param wallOffset  the wall offset, not null
+         * @return the date-time relative to the wall/before offset, not null
+         */
+        public LocalDateTime createDateTime(LocalDateTime dateTime, ZoneOffset standardOffset, ZoneOffset wallOffset) {
+            switch (this) {
+                case UTC: {
+                    int difference = wallOffset.getTotalSeconds() - ZoneOffset.UTC.getTotalSeconds();
+                    return dateTime.plusSeconds(difference);
+                }
+                case STANDARD: {
+                    int difference = wallOffset.getTotalSeconds() - standardOffset.getTotalSeconds();
+                    return dateTime.plusSeconds(difference);
+                }
+                default:  // WALL
+                    return dateTime;
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/zone/ZoneRules.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,959 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.zone;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.Serializable;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.temporal.Year;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * The rules defining how the zone offset varies for a single time-zone.
+ * <p>
+ * The rules model all the historic and future transitions for a time-zone.
+ * {@link ZoneOffsetTransition} is used for known transitions, typically historic.
+ * {@link ZoneOffsetTransitionRule} is used for future transitions that are based
+ * on the result of an algorithm.
+ * <p>
+ * The rules are loaded via {@link ZoneRulesProvider} using a {@link ZoneId}.
+ * The same rules may be shared internally between multiple zone IDs.
+ * <p>
+ * Serializing an instance of {@code ZoneRules} will store the entire set of rules.
+ * It does not store the zone ID as it is not part of the state of this object.
+ * <p>
+ * A rule implementation may or may not store full information about historic
+ * and future transitions, and the information stored is only as accurate as
+ * that supplied to the implementation by the rules provider.
+ * Applications should treat the data provided as representing the best information
+ * available to the implementation of this rule.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class ZoneRules implements Serializable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 3044319355680032515L;
+    /**
+     * The last year to have its transitions cached.
+     */
+    private static final int LAST_CACHED_YEAR = 2100;
+
+    /**
+     * The transitions between standard offsets (epoch seconds), sorted.
+     */
+    private final long[] standardTransitions;
+    /**
+     * The standard offsets.
+     */
+    private final ZoneOffset[] standardOffsets;
+    /**
+     * The transitions between instants (epoch seconds), sorted.
+     */
+    private final long[] savingsInstantTransitions;
+    /**
+     * The transitions between local date-times, sorted.
+     * This is a paired array, where the first entry is the start of the transition
+     * and the second entry is the end of the transition.
+     */
+    private final LocalDateTime[] savingsLocalTransitions;
+    /**
+     * The wall offsets.
+     */
+    private final ZoneOffset[] wallOffsets;
+    /**
+     * The last rule.
+     */
+    private final ZoneOffsetTransitionRule[] lastRules;
+    /**
+     * The map of recent transitions.
+     */
+    private final ConcurrentMap<Integer, ZoneOffsetTransition[]> lastRulesCache =
+                new ConcurrentHashMap<Integer, ZoneOffsetTransition[]>();
+    /**
+     * The zero-length long array.
+     */
+    private static final long[] EMPTY_LONG_ARRAY = new long[0];
+    /**
+     * The zero-length lastrules array.
+     */
+    private static final ZoneOffsetTransitionRule[] EMPTY_LASTRULES =
+        new ZoneOffsetTransitionRule[0];
+    /**
+     * The zero-length ldt array.
+     */
+    private static final LocalDateTime[] EMPTY_LDT_ARRAY = new LocalDateTime[0];
+
+    /**
+     * Obtains an instance of a ZoneRules.
+     *
+     * @param baseStandardOffset  the standard offset to use before legal rules were set, not null
+     * @param baseWallOffset  the wall offset to use before legal rules were set, not null
+     * @param standardOffsetTransitionList  the list of changes to the standard offset, not null
+     * @param transitionList  the list of transitions, not null
+     * @param lastRules  the recurring last rules, size 16 or less, not null
+     * @return the zone rules, not null
+     */
+    public static ZoneRules of(ZoneOffset baseStandardOffset,
+                               ZoneOffset baseWallOffset,
+                               List<ZoneOffsetTransition> standardOffsetTransitionList,
+                               List<ZoneOffsetTransition> transitionList,
+                               List<ZoneOffsetTransitionRule> lastRules) {
+        Objects.requireNonNull(baseStandardOffset, "baseStandardOffset");
+        Objects.requireNonNull(baseWallOffset, "baseWallOffset");
+        Objects.requireNonNull(standardOffsetTransitionList, "standardOffsetTransitionList");
+        Objects.requireNonNull(transitionList, "transitionList");
+        Objects.requireNonNull(lastRules, "lastRules");
+        return new ZoneRules(baseStandardOffset, baseWallOffset,
+                             standardOffsetTransitionList, transitionList, lastRules);
+    }
+
+    /**
+     * Obtains an instance of ZoneRules that has fixed zone rules.
+     *
+     * @param offset  the offset this fixed zone rules is based on, not null
+     * @return the zone rules, not null
+     * @see #isFixedOffset()
+     */
+    public static ZoneRules of(ZoneOffset offset) {
+        Objects.requireNonNull(offset, "offset");
+        return new ZoneRules(offset);
+    }
+
+    /**
+     * Creates an instance.
+     *
+     * @param baseStandardOffset  the standard offset to use before legal rules were set, not null
+     * @param baseWallOffset  the wall offset to use before legal rules were set, not null
+     * @param standardOffsetTransitionList  the list of changes to the standard offset, not null
+     * @param transitionList  the list of transitions, not null
+     * @param lastRules  the recurring last rules, size 16 or less, not null
+     */
+    ZoneRules(ZoneOffset baseStandardOffset,
+              ZoneOffset baseWallOffset,
+              List<ZoneOffsetTransition> standardOffsetTransitionList,
+              List<ZoneOffsetTransition> transitionList,
+              List<ZoneOffsetTransitionRule> lastRules) {
+        super();
+
+        // convert standard transitions
+
+        this.standardTransitions = new long[standardOffsetTransitionList.size()];
+
+        this.standardOffsets = new ZoneOffset[standardOffsetTransitionList.size() + 1];
+        this.standardOffsets[0] = baseStandardOffset;
+        for (int i = 0; i < standardOffsetTransitionList.size(); i++) {
+            this.standardTransitions[i] = standardOffsetTransitionList.get(i).toEpochSecond();
+            this.standardOffsets[i + 1] = standardOffsetTransitionList.get(i).getOffsetAfter();
+        }
+
+        // convert savings transitions to locals
+        List<LocalDateTime> localTransitionList = new ArrayList<>();
+        List<ZoneOffset> localTransitionOffsetList = new ArrayList<>();
+        localTransitionOffsetList.add(baseWallOffset);
+        for (ZoneOffsetTransition trans : transitionList) {
+            if (trans.isGap()) {
+                localTransitionList.add(trans.getDateTimeBefore());
+                localTransitionList.add(trans.getDateTimeAfter());
+            } else {
+                localTransitionList.add(trans.getDateTimeAfter());
+                localTransitionList.add(trans.getDateTimeBefore());
+            }
+            localTransitionOffsetList.add(trans.getOffsetAfter());
+        }
+        this.savingsLocalTransitions = localTransitionList.toArray(new LocalDateTime[localTransitionList.size()]);
+        this.wallOffsets = localTransitionOffsetList.toArray(new ZoneOffset[localTransitionOffsetList.size()]);
+
+        // convert savings transitions to instants
+        this.savingsInstantTransitions = new long[transitionList.size()];
+        for (int i = 0; i < transitionList.size(); i++) {
+            this.savingsInstantTransitions[i] = transitionList.get(i).toEpochSecond();
+        }
+
+        // last rules
+        if (lastRules.size() > 16) {
+            throw new IllegalArgumentException("Too many transition rules");
+        }
+        this.lastRules = lastRules.toArray(new ZoneOffsetTransitionRule[lastRules.size()]);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param standardTransitions  the standard transitions, not null
+     * @param standardOffsets  the standard offsets, not null
+     * @param savingsInstantTransitions  the standard transitions, not null
+     * @param wallOffsets  the wall offsets, not null
+     * @param lastRules  the recurring last rules, size 15 or less, not null
+     */
+    private ZoneRules(long[] standardTransitions,
+                      ZoneOffset[] standardOffsets,
+                      long[] savingsInstantTransitions,
+                      ZoneOffset[] wallOffsets,
+                      ZoneOffsetTransitionRule[] lastRules) {
+        super();
+
+        this.standardTransitions = standardTransitions;
+        this.standardOffsets = standardOffsets;
+        this.savingsInstantTransitions = savingsInstantTransitions;
+        this.wallOffsets = wallOffsets;
+        this.lastRules = lastRules;
+
+        if (savingsInstantTransitions.length == 0) {
+            this.savingsLocalTransitions = EMPTY_LDT_ARRAY;
+        } else {
+            // convert savings transitions to locals
+            List<LocalDateTime> localTransitionList = new ArrayList<>();
+            for (int i = 0; i < savingsInstantTransitions.length; i++) {
+                ZoneOffset before = wallOffsets[i];
+                ZoneOffset after = wallOffsets[i + 1];
+                ZoneOffsetTransition trans = new ZoneOffsetTransition(savingsInstantTransitions[i], before, after);
+                if (trans.isGap()) {
+                    localTransitionList.add(trans.getDateTimeBefore());
+                    localTransitionList.add(trans.getDateTimeAfter());
+                } else {
+                    localTransitionList.add(trans.getDateTimeAfter());
+                    localTransitionList.add(trans.getDateTimeBefore());
+               }
+            }
+            this.savingsLocalTransitions = localTransitionList.toArray(new LocalDateTime[localTransitionList.size()]);
+        }
+    }
+
+    /**
+     * Creates an instance of ZoneRules that has fixed zone rules.
+     *
+     * @param offset  the offset this fixed zone rules is based on, not null
+     * @return the zone rules, not null
+     * @see #isFixedOffset()
+     */
+    private ZoneRules(ZoneOffset offset) {
+        this.standardOffsets = new ZoneOffset[1];
+        this.standardOffsets[0] = offset;
+        this.standardTransitions = EMPTY_LONG_ARRAY;
+        this.savingsInstantTransitions = EMPTY_LONG_ARRAY;
+        this.savingsLocalTransitions = EMPTY_LDT_ARRAY;
+        this.wallOffsets = standardOffsets;
+        this.lastRules = EMPTY_LASTRULES;
+    }
+
+    /**
+     * Uses a serialization delegate.
+     *
+     * @return the replacing object, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.ZRULES, this);
+    }
+
+    /**
+     * Writes the state to the stream.
+     *
+     * @param out  the output stream, not null
+     * @throws IOException if an error occurs
+     */
+    void writeExternal(DataOutput out) throws IOException {
+        out.writeInt(standardTransitions.length);
+        for (long trans : standardTransitions) {
+            Ser.writeEpochSec(trans, out);
+        }
+        for (ZoneOffset offset : standardOffsets) {
+            Ser.writeOffset(offset, out);
+        }
+        out.writeInt(savingsInstantTransitions.length);
+        for (long trans : savingsInstantTransitions) {
+            Ser.writeEpochSec(trans, out);
+        }
+        for (ZoneOffset offset : wallOffsets) {
+            Ser.writeOffset(offset, out);
+        }
+        out.writeByte(lastRules.length);
+        for (ZoneOffsetTransitionRule rule : lastRules) {
+            rule.writeExternal(out);
+        }
+    }
+
+    /**
+     * Reads the state from the stream.
+     *
+     * @param in  the input stream, not null
+     * @return the created object, not null
+     * @throws IOException if an error occurs
+     */
+    static ZoneRules readExternal(DataInput in) throws IOException, ClassNotFoundException {
+        int stdSize = in.readInt();
+        long[] stdTrans = (stdSize == 0) ? EMPTY_LONG_ARRAY
+                                         : new long[stdSize];
+        for (int i = 0; i < stdSize; i++) {
+            stdTrans[i] = Ser.readEpochSec(in);
+        }
+        ZoneOffset[] stdOffsets = new ZoneOffset[stdSize + 1];
+        for (int i = 0; i < stdOffsets.length; i++) {
+            stdOffsets[i] = Ser.readOffset(in);
+        }
+        int savSize = in.readInt();
+        long[] savTrans = (savSize == 0) ? EMPTY_LONG_ARRAY
+                                         : new long[savSize];
+        for (int i = 0; i < savSize; i++) {
+            savTrans[i] = Ser.readEpochSec(in);
+        }
+        ZoneOffset[] savOffsets = new ZoneOffset[savSize + 1];
+        for (int i = 0; i < savOffsets.length; i++) {
+            savOffsets[i] = Ser.readOffset(in);
+        }
+        int ruleSize = in.readByte();
+        ZoneOffsetTransitionRule[] rules = (ruleSize == 0) ?
+            EMPTY_LASTRULES : new ZoneOffsetTransitionRule[ruleSize];
+        for (int i = 0; i < ruleSize; i++) {
+            rules[i] = ZoneOffsetTransitionRule.readExternal(in);
+        }
+        return new ZoneRules(stdTrans, stdOffsets, savTrans, savOffsets, rules);
+    }
+
+    /**
+     * Checks of the zone rules are fixed, such that the offset never varies.
+     *
+     * @return true if the time-zone is fixed and the offset never changes
+     */
+    public boolean isFixedOffset() {
+        return savingsInstantTransitions.length == 0;
+    }
+
+    /**
+     * Gets the offset applicable at the specified instant in these rules.
+     * <p>
+     * The mapping from an instant to an offset is simple, there is only
+     * one valid offset for each instant.
+     * This method returns that offset.
+     *
+     * @param instant  the instant to find the offset for, not null, but null
+     *  may be ignored if the rules have a single offset for all instants
+     * @return the offset, not null
+     */
+    public ZoneOffset getOffset(Instant instant) {
+        if (savingsInstantTransitions.length == 0) {
+            return standardOffsets[0];
+        }
+        long epochSec = instant.getEpochSecond();
+        // check if using last rules
+        if (lastRules.length > 0 &&
+                epochSec > savingsInstantTransitions[savingsInstantTransitions.length - 1]) {
+            int year = findYear(epochSec, wallOffsets[wallOffsets.length - 1]);
+            ZoneOffsetTransition[] transArray = findTransitionArray(year);
+            ZoneOffsetTransition trans = null;
+            for (int i = 0; i < transArray.length; i++) {
+                trans = transArray[i];
+                if (epochSec < trans.toEpochSecond()) {
+                    return trans.getOffsetBefore();
+                }
+            }
+            return trans.getOffsetAfter();
+        }
+
+        // using historic rules
+        int index  = Arrays.binarySearch(savingsInstantTransitions, epochSec);
+        if (index < 0) {
+            // switch negative insert position to start of matched range
+            index = -index - 2;
+        }
+        return wallOffsets[index + 1];
+    }
+
+    /**
+     * Gets a suitable offset for the specified local date-time in these rules.
+     * <p>
+     * The mapping from a local date-time to an offset is not straightforward.
+     * There are three cases:
+     * <p><ul>
+     * <li>Normal, with one valid offset. For the vast majority of the year, the normal
+     *  case applies, where there is a single valid offset for the local date-time.</li>
+     * <li>Gap, with zero valid offsets. This is when clocks jump forward typically
+     *  due to the spring daylight savings change from "winter" to "summer".
+     *  In a gap there are local date-time values with no valid offset.</li>
+     * <li>Overlap, with two valid offsets. This is when clocks are set back typically
+     *  due to the autumn daylight savings change from "summer" to "winter".
+     *  In an overlap there are local date-time values with two valid offsets.</li>
+     * </ul><p>
+     * Thus, for any given local date-time there can be zero, one or two valid offsets.
+     * This method returns the single offset in the Normal case, and in the Gap or Overlap
+     * case it returns the offset before the transition.
+     * <p>
+     * Since, in the case of Gap and Overlap, the offset returned is a "best" value, rather
+     * than the "correct" value, it should be treated with care. Applications that care
+     * about the correct offset should use a combination of this method,
+     * {@link #getValidOffsets(LocalDateTime)} and {@link #getTransition(LocalDateTime)}.
+     *
+     * @param localDateTime  the local date-time to query, not null, but null
+     *  may be ignored if the rules have a single offset for all instants
+     * @return the best available offset for the local date-time, not null
+     */
+    public ZoneOffset getOffset(LocalDateTime localDateTime) {
+        Object info = getOffsetInfo(localDateTime);
+        if (info instanceof ZoneOffsetTransition) {
+            return ((ZoneOffsetTransition) info).getOffsetBefore();
+        }
+        return (ZoneOffset) info;
+    }
+
+    /**
+     * Gets the offset applicable at the specified local date-time in these rules.
+     * <p>
+     * The mapping from a local date-time to an offset is not straightforward.
+     * There are three cases:
+     * <p><ul>
+     * <li>Normal, with one valid offset. For the vast majority of the year, the normal
+     *  case applies, where there is a single valid offset for the local date-time.</li>
+     * <li>Gap, with zero valid offsets. This is when clocks jump forward typically
+     *  due to the spring daylight savings change from "winter" to "summer".
+     *  In a gap there are local date-time values with no valid offset.</li>
+     * <li>Overlap, with two valid offsets. This is when clocks are set back typically
+     *  due to the autumn daylight savings change from "summer" to "winter".
+     *  In an overlap there are local date-time values with two valid offsets.</li>
+     * </ul><p>
+     * Thus, for any given local date-time there can be zero, one or two valid offsets.
+     * This method returns that list of valid offsets, which is a list of size 0, 1 or 2.
+     * In the case where there are two offsets, the earlier offset is returned at index 0
+     * and the later offset at index 1.
+     * <p>
+     * There are various ways to handle the conversion from a {@code LocalDateTime}.
+     * One technique, using this method, would be:
+     * <pre>
+     *  List&lt;ZoneOffset&gt; validOffsets = rules.getOffset(localDT);
+     *  if (validOffsets.size() == 1) {
+     *    // Normal case: only one valid offset
+     *    zoneOffset = validOffsets.get(0);
+     *  } else {
+     *    // Gap or Overlap: determine what to do from transition (which will be non-null)
+     *    ZoneOffsetTransition trans = rules.getTransition(localDT);
+     *  }
+     * </pre>
+     * <p>
+     * In theory, it is possible for there to be more than two valid offsets.
+     * This would happen if clocks to be put back more than once in quick succession.
+     * This has never happened in the history of time-zones and thus has no special handling.
+     * However, if it were to happen, then the list would return more than 2 entries.
+     *
+     * @param localDateTime  the local date-time to query for valid offsets, not null, but null
+     *  may be ignored if the rules have a single offset for all instants
+     * @return the list of valid offsets, may be immutable, not null
+     */
+    public List<ZoneOffset> getValidOffsets(LocalDateTime localDateTime) {
+        // should probably be optimized
+        Object info = getOffsetInfo(localDateTime);
+        if (info instanceof ZoneOffsetTransition) {
+            return ((ZoneOffsetTransition) info).getValidOffsets();
+        }
+        return Collections.singletonList((ZoneOffset) info);
+    }
+
+    /**
+     * Gets the offset transition applicable at the specified local date-time in these rules.
+     * <p>
+     * The mapping from a local date-time to an offset is not straightforward.
+     * There are three cases:
+     * <p><ul>
+     * <li>Normal, with one valid offset. For the vast majority of the year, the normal
+     *  case applies, where there is a single valid offset for the local date-time.</li>
+     * <li>Gap, with zero valid offsets. This is when clocks jump forward typically
+     *  due to the spring daylight savings change from "winter" to "summer".
+     *  In a gap there are local date-time values with no valid offset.</li>
+     * <li>Overlap, with two valid offsets. This is when clocks are set back typically
+     *  due to the autumn daylight savings change from "summer" to "winter".
+     *  In an overlap there are local date-time values with two valid offsets.</li>
+     * </ul><p>
+     * A transition is used to model the cases of a Gap or Overlap.
+     * The Normal case will return null.
+     * <p>
+     * There are various ways to handle the conversion from a {@code LocalDateTime}.
+     * One technique, using this method, would be:
+     * <pre>
+     *  ZoneOffsetTransition trans = rules.getTransition(localDT);
+     *  if (trans == null) {
+     *    // Gap or Overlap: determine what to do from transition
+     *  } else {
+     *    // Normal case: only one valid offset
+     *    zoneOffset = rule.getOffset(localDT);
+     *  }
+     * </pre>
+     *
+     * @param localDateTime  the local date-time to query for offset transition, not null, but null
+     *  may be ignored if the rules have a single offset for all instants
+     * @return the offset transition, null if the local date-time is not in transition
+     */
+    public ZoneOffsetTransition getTransition(LocalDateTime localDateTime) {
+        Object info = getOffsetInfo(localDateTime);
+        return (info instanceof ZoneOffsetTransition ? (ZoneOffsetTransition) info : null);
+    }
+
+    private Object getOffsetInfo(LocalDateTime dt) {
+        if (savingsInstantTransitions.length == 0) {
+            return standardOffsets[0];
+        }
+        // check if using last rules
+        if (lastRules.length > 0 &&
+                dt.isAfter(savingsLocalTransitions[savingsLocalTransitions.length - 1])) {
+            ZoneOffsetTransition[] transArray = findTransitionArray(dt.getYear());
+            Object info = null;
+            for (ZoneOffsetTransition trans : transArray) {
+                info = findOffsetInfo(dt, trans);
+                if (info instanceof ZoneOffsetTransition || info.equals(trans.getOffsetBefore())) {
+                    return info;
+                }
+            }
+            return info;
+        }
+
+        // using historic rules
+        int index  = Arrays.binarySearch(savingsLocalTransitions, dt);
+        if (index == -1) {
+            // before first transition
+            return wallOffsets[0];
+        }
+        if (index < 0) {
+            // switch negative insert position to start of matched range
+            index = -index - 2;
+        } else if (index < savingsLocalTransitions.length - 1 &&
+                savingsLocalTransitions[index].equals(savingsLocalTransitions[index + 1])) {
+            // handle overlap immediately following gap
+            index++;
+        }
+        if ((index & 1) == 0) {
+            // gap or overlap
+            LocalDateTime dtBefore = savingsLocalTransitions[index];
+            LocalDateTime dtAfter = savingsLocalTransitions[index + 1];
+            ZoneOffset offsetBefore = wallOffsets[index / 2];
+            ZoneOffset offsetAfter = wallOffsets[index / 2 + 1];
+            if (offsetAfter.getTotalSeconds() > offsetBefore.getTotalSeconds()) {
+                // gap
+                return new ZoneOffsetTransition(dtBefore, offsetBefore, offsetAfter);
+            } else {
+                // overlap
+                return new ZoneOffsetTransition(dtAfter, offsetBefore, offsetAfter);
+            }
+        } else {
+            // normal (neither gap or overlap)
+            return wallOffsets[index / 2 + 1];
+        }
+    }
+
+    /**
+     * Finds the offset info for a local date-time and transition.
+     *
+     * @param dt  the date-time, not null
+     * @param trans  the transition, not null
+     * @return the offset info, not null
+     */
+    private Object findOffsetInfo(LocalDateTime dt, ZoneOffsetTransition trans) {
+        LocalDateTime localTransition = trans.getDateTimeBefore();
+        if (trans.isGap()) {
+            if (dt.isBefore(localTransition)) {
+                return trans.getOffsetBefore();
+            }
+            if (dt.isBefore(trans.getDateTimeAfter())) {
+                return trans;
+            } else {
+                return trans.getOffsetAfter();
+            }
+        } else {
+            if (dt.isBefore(localTransition) == false) {
+                return trans.getOffsetAfter();
+            }
+            if (dt.isBefore(trans.getDateTimeAfter())) {
+                return trans.getOffsetBefore();
+            } else {
+                return trans;
+            }
+        }
+    }
+
+    /**
+     * Finds the appropriate transition array for the given year.
+     *
+     * @param year  the year, not null
+     * @return the transition array, not null
+     */
+    private ZoneOffsetTransition[] findTransitionArray(int year) {
+        Integer yearObj = year;  // should use Year class, but this saves a class load
+        ZoneOffsetTransition[] transArray = lastRulesCache.get(yearObj);
+        if (transArray != null) {
+            return transArray;
+        }
+        ZoneOffsetTransitionRule[] ruleArray = lastRules;
+        transArray  = new ZoneOffsetTransition[ruleArray.length];
+        for (int i = 0; i < ruleArray.length; i++) {
+            transArray[i] = ruleArray[i].createTransition(year);
+        }
+        if (year < LAST_CACHED_YEAR) {
+            lastRulesCache.putIfAbsent(yearObj, transArray);
+        }
+        return transArray;
+    }
+
+    /**
+     * Gets the standard offset for the specified instant in this zone.
+     * <p>
+     * This provides access to historic information on how the standard offset
+     * has changed over time.
+     * The standard offset is the offset before any daylight saving time is applied.
+     * This is typically the offset applicable during winter.
+     *
+     * @param instant  the instant to find the offset information for, not null, but null
+     *  may be ignored if the rules have a single offset for all instants
+     * @return the standard offset, not null
+     */
+    public ZoneOffset getStandardOffset(Instant instant) {
+        if (savingsInstantTransitions.length == 0) {
+            return standardOffsets[0];
+        }
+        long epochSec = instant.getEpochSecond();
+        int index  = Arrays.binarySearch(standardTransitions, epochSec);
+        if (index < 0) {
+            // switch negative insert position to start of matched range
+            index = -index - 2;
+        }
+        return standardOffsets[index + 1];
+    }
+
+    /**
+     * Gets the amount of daylight savings in use for the specified instant in this zone.
+     * <p>
+     * This provides access to historic information on how the amount of daylight
+     * savings has changed over time.
+     * This is the difference between the standard offset and the actual offset.
+     * Typically the amount is zero during winter and one hour during summer.
+     * Time-zones are second-based, so the nanosecond part of the duration will be zero.
+     * <p>
+     * This default implementation calculates the duration from the
+     * {@link #getOffset(java.time.Instant) actual} and
+     * {@link #getStandardOffset(java.time.Instant) standard} offsets.
+     *
+     * @param instant  the instant to find the daylight savings for, not null, but null
+     *  may be ignored if the rules have a single offset for all instants
+     * @return the difference between the standard and actual offset, not null
+     */
+    public Duration getDaylightSavings(Instant instant) {
+        if (savingsInstantTransitions.length == 0) {
+            return Duration.ZERO;
+        }
+        ZoneOffset standardOffset = getStandardOffset(instant);
+        ZoneOffset actualOffset = getOffset(instant);
+        return Duration.ofSeconds(actualOffset.getTotalSeconds() - standardOffset.getTotalSeconds());
+    }
+
+    /**
+     * Checks if the specified instant is in daylight savings.
+     * <p>
+     * This checks if the standard offset and the actual offset are the same
+     * for the specified instant.
+     * If they are not, it is assumed that daylight savings is in operation.
+     * <p>
+     * This default implementation compares the {@link #getOffset(java.time.Instant) actual}
+     * and {@link #getStandardOffset(java.time.Instant) standard} offsets.
+     *
+     * @param instant  the instant to find the offset information for, not null, but null
+     *  may be ignored if the rules have a single offset for all instants
+     * @return the standard offset, not null
+     */
+    public boolean isDaylightSavings(Instant instant) {
+        return (getStandardOffset(instant).equals(getOffset(instant)) == false);
+    }
+
+    /**
+     * Checks if the offset date-time is valid for these rules.
+     * <p>
+     * To be valid, the local date-time must not be in a gap and the offset
+     * must match one of the valid offsets.
+     * <p>
+     * This default implementation checks if {@link #getValidOffsets(java.time.LocalDateTime)}
+     * contains the specified offset.
+     *
+     * @param localDateTime  the date-time to check, not null, but null
+     *  may be ignored if the rules have a single offset for all instants
+     * @param offset  the offset to check, null returns false
+     * @return true if the offset date-time is valid for these rules
+     */
+    public boolean isValidOffset(LocalDateTime localDateTime, ZoneOffset offset) {
+        return getValidOffsets(localDateTime).contains(offset);
+    }
+
+    /**
+     * Gets the next transition after the specified instant.
+     * <p>
+     * This returns details of the next transition after the specified instant.
+     * For example, if the instant represents a point where "Summer" daylight savings time
+     * applies, then the method will return the transition to the next "Winter" time.
+     *
+     * @param instant  the instant to get the next transition after, not null, but null
+     *  may be ignored if the rules have a single offset for all instants
+     * @return the next transition after the specified instant, null if this is after the last transition
+     */
+    public ZoneOffsetTransition nextTransition(Instant instant) {
+        if (savingsInstantTransitions.length == 0) {
+            return null;
+        }
+        long epochSec = instant.getEpochSecond();
+        // check if using last rules
+        if (epochSec >= savingsInstantTransitions[savingsInstantTransitions.length - 1]) {
+            if (lastRules.length == 0) {
+                return null;
+            }
+            // search year the instant is in
+            int year = findYear(epochSec, wallOffsets[wallOffsets.length - 1]);
+            ZoneOffsetTransition[] transArray = findTransitionArray(year);
+            for (ZoneOffsetTransition trans : transArray) {
+                if (epochSec < trans.toEpochSecond()) {
+                    return trans;
+                }
+            }
+            // use first from following year
+            if (year < Year.MAX_VALUE) {
+                transArray = findTransitionArray(year + 1);
+                return transArray[0];
+            }
+            return null;
+        }
+
+        // using historic rules
+        int index  = Arrays.binarySearch(savingsInstantTransitions, epochSec);
+        if (index < 0) {
+            index = -index - 1;  // switched value is the next transition
+        } else {
+            index += 1;  // exact match, so need to add one to get the next
+        }
+        return new ZoneOffsetTransition(savingsInstantTransitions[index], wallOffsets[index], wallOffsets[index + 1]);
+    }
+
+    /**
+     * Gets the previous transition before the specified instant.
+     * <p>
+     * This returns details of the previous transition after the specified instant.
+     * For example, if the instant represents a point where "summer" daylight saving time
+     * applies, then the method will return the transition from the previous "winter" time.
+     *
+     * @param instant  the instant to get the previous transition after, not null, but null
+     *  may be ignored if the rules have a single offset for all instants
+     * @return the previous transition after the specified instant, null if this is before the first transition
+     */
+    public ZoneOffsetTransition previousTransition(Instant instant) {
+        if (savingsInstantTransitions.length == 0) {
+            return null;
+        }
+        long epochSec = instant.getEpochSecond();
+        if (instant.getNano() > 0 && epochSec < Long.MAX_VALUE) {
+            epochSec += 1;  // allow rest of method to only use seconds
+        }
+
+        // check if using last rules
+        long lastHistoric = savingsInstantTransitions[savingsInstantTransitions.length - 1];
+        if (lastRules.length > 0 && epochSec > lastHistoric) {
+            // search year the instant is in
+            ZoneOffset lastHistoricOffset = wallOffsets[wallOffsets.length - 1];
+            int year = findYear(epochSec, lastHistoricOffset);
+            ZoneOffsetTransition[] transArray = findTransitionArray(year);
+            for (int i = transArray.length - 1; i >= 0; i--) {
+                if (epochSec > transArray[i].toEpochSecond()) {
+                    return transArray[i];
+                }
+            }
+            // use last from preceeding year
+            int lastHistoricYear = findYear(lastHistoric, lastHistoricOffset);
+            if (--year > lastHistoricYear) {
+                transArray = findTransitionArray(year);
+                return transArray[transArray.length - 1];
+            }
+            // drop through
+        }
+
+        // using historic rules
+        int index  = Arrays.binarySearch(savingsInstantTransitions, epochSec);
+        if (index < 0) {
+            index = -index - 1;
+        }
+        if (index <= 0) {
+            return null;
+        }
+        return new ZoneOffsetTransition(savingsInstantTransitions[index - 1], wallOffsets[index - 1], wallOffsets[index]);
+    }
+
+    private int findYear(long epochSecond, ZoneOffset offset) {
+        // inline for performance
+        long localSecond = epochSecond + offset.getTotalSeconds();
+        long localEpochDay = Math.floorDiv(localSecond, 86400);
+        return LocalDate.ofEpochDay(localEpochDay).getYear();
+    }
+
+    /**
+     * Gets the complete list of fully defined transitions.
+     * <p>
+     * The complete set of transitions for this rules instance is defined by this method
+     * and {@link #getTransitionRules()}. This method returns those transitions that have
+     * been fully defined. These are typically historical, but may be in the future.
+     * <p>
+     * The list will be empty for fixed offset rules and for any time-zone where there has
+     * only ever been a single offset. The list will also be empty if the transition rules are unknown.
+     *
+     * @return an immutable list of fully defined transitions, not null
+     */
+    public List<ZoneOffsetTransition> getTransitions() {
+        List<ZoneOffsetTransition> list = new ArrayList<>();
+        for (int i = 0; i < savingsInstantTransitions.length; i++) {
+            list.add(new ZoneOffsetTransition(savingsInstantTransitions[i], wallOffsets[i], wallOffsets[i + 1]));
+        }
+        return Collections.unmodifiableList(list);
+    }
+
+    /**
+     * Gets the list of transition rules for years beyond those defined in the transition list.
+     * <p>
+     * The complete set of transitions for this rules instance is defined by this method
+     * and {@link #getTransitions()}. This method returns instances of {@link ZoneOffsetTransitionRule}
+     * that define an algorithm for when transitions will occur.
+     * <p>
+     * For any given {@code ZoneRules}, this list contains the transition rules for years
+     * beyond those years that have been fully defined. These rules typically refer to future
+     * daylight saving time rule changes.
+     * <p>
+     * If the zone defines daylight savings into the future, then the list will normally
+     * be of size two and hold information about entering and exiting daylight savings.
+     * If the zone does not have daylight savings, or information about future changes
+     * is uncertain, then the list will be empty.
+     * <p>
+     * The list will be empty for fixed offset rules and for any time-zone where there is no
+     * daylight saving time. The list will also be empty if the transition rules are unknown.
+     *
+     * @return an immutable list of transition rules, not null
+     */
+    public List<ZoneOffsetTransitionRule> getTransitionRules() {
+        return Collections.unmodifiableList(Arrays.asList(lastRules));
+    }
+
+    /**
+     * Checks if this set of rules equals another.
+     * <p>
+     * Two rule sets are equal if they will always result in the same output
+     * for any given input instant or local date-time.
+     * Rules from two different groups may return false even if they are in fact the same.
+     * <p>
+     * This definition should result in implementations comparing their entire state.
+     *
+     * @param otherRules  the other rules, null returns false
+     * @return true if this rules is the same as that specified
+     */
+    @Override
+    public boolean equals(Object otherRules) {
+        if (this == otherRules) {
+           return true;
+        }
+        if (otherRules instanceof ZoneRules) {
+            ZoneRules other = (ZoneRules) otherRules;
+            return Arrays.equals(standardTransitions, other.standardTransitions) &&
+                    Arrays.equals(standardOffsets, other.standardOffsets) &&
+                    Arrays.equals(savingsInstantTransitions, other.savingsInstantTransitions) &&
+                    Arrays.equals(wallOffsets, other.wallOffsets) &&
+                    Arrays.equals(lastRules, other.lastRules);
+        }
+        return false;
+    }
+
+    /**
+     * Returns a suitable hash code given the definition of {@code #equals}.
+     *
+     * @return the hash code
+     */
+    @Override
+    public int hashCode() {
+        return Arrays.hashCode(standardTransitions) ^
+                Arrays.hashCode(standardOffsets) ^
+                Arrays.hashCode(savingsInstantTransitions) ^
+                Arrays.hashCode(wallOffsets) ^
+                Arrays.hashCode(lastRules);
+    }
+
+    /**
+     * Returns a string describing this object.
+     *
+     * @return a string for debugging, not null
+     */
+    @Override
+    public String toString() {
+        return "ZoneRules[currentStandardOffset=" + standardOffsets[standardOffsets.length - 1] + "]";
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/zone/ZoneRulesException.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.zone;
+
+import java.time.DateTimeException;
+
+/**
+ * Thrown to indicate a problem with time-zone configuration.
+ * <p>
+ * This exception is used to indicate a problems with the configured
+ * time-zone rules.
+ *
+ * <h3>Specification for implementors</h3>
+ * This class is intended for use in a single thread.
+ *
+ * @since 1.8
+ */
+public class ZoneRulesException extends DateTimeException {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -1632418723876261839L;
+
+    /**
+     * Constructs a new date-time exception with the specified message.
+     *
+     * @param message  the message to use for this exception, may be null
+     */
+    public ZoneRulesException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new date-time exception with the specified message and cause.
+     *
+     * @param message  the message to use for this exception, may be null
+     * @param cause  the cause of the exception, may be null
+     */
+    public ZoneRulesException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/zone/ZoneRulesProvider.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,412 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.zone;
+
+import java.time.DateTimeException;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NavigableMap;
+import java.util.Objects;
+import java.util.ServiceConfigurationError;
+import java.util.ServiceLoader;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Provider of time-zone rules to the system.
+ * <p>
+ * This class manages the configuration of time-zone rules.
+ * The static methods provide the public API that can be used to manage the providers.
+ * The abstract methods provide the SPI that allows rules to be provided.
+ * <p>
+ * 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.
+ * <p>
+ * Time-zone rules are political, thus the data can change at any time.
+ * Each provider will provide the latest rules for each zone ID, but they
+ * may also provide the history of how the rules changed.
+ *
+ * <h3>Specification for implementors</h3>
+ * This interface is a service provider that can be called by multiple threads.
+ * Implementations must be immutable and thread-safe.
+ * <p>
+ * Providers must ensure that once a rule has been seen by the application, the
+ * rule must continue to be available.
+ * <p>
+ * Many systems would like to update time-zone rules dynamically without stopping the JVM.
+ * When examined in detail, this is a complex problem.
+ * Providers may choose to handle dynamic updates, however the default provider does not.
+ *
+ * @since 1.8
+ */
+public abstract class ZoneRulesProvider {
+
+    /**
+     * The set of loaded providers.
+     */
+    private static final CopyOnWriteArrayList<ZoneRulesProvider> PROVIDERS = new CopyOnWriteArrayList<>();
+    /**
+     * The lookup from zone region ID to provider.
+     */
+    private static final ConcurrentMap<String, ZoneRulesProvider> ZONES = new ConcurrentHashMap<>(512, 0.75f, 2);
+    static {
+        registerProvider(new TzdbZoneRulesProvider());
+        ServiceLoader<ZoneRulesProvider> sl = ServiceLoader.load(ZoneRulesProvider.class, ClassLoader.getSystemClassLoader());
+        List<ZoneRulesProvider> loaded = new ArrayList<>();
+        Iterator<ZoneRulesProvider> it = sl.iterator();
+        while (it.hasNext()) {
+            ZoneRulesProvider provider;
+            try {
+                provider = it.next();
+            } catch (ServiceConfigurationError ex) {
+                if (ex.getCause() instanceof SecurityException) {
+                    continue;  // ignore the security exception, try the next provider
+                }
+                throw ex;
+            }
+            registerProvider0(provider);
+        }
+        // CopyOnWriteList could be slow if lots of providers and each added individually
+        PROVIDERS.addAll(loaded);
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Gets the set of available zone IDs.
+     * <p>
+     * These zone IDs are loaded and available for use by {@code ZoneId}.
+     *
+     * @return a modifiable copy of the set of zone IDs, not null
+     */
+    public static Set<String> getAvailableZoneIds() {
+        return new HashSet<>(ZONES.keySet());
+    }
+
+    /**
+     * Gets the rules for the zone ID.
+     * <p>
+     * This returns the latest available rules for the zone ID.
+     * <p>
+     * This method relies on time-zone data provider files that are configured.
+     * These are loaded using a {@code ServiceLoader}.
+     *
+     * @param zoneId  the zone region ID as used by {@code ZoneId}, not null
+     * @return the rules for the ID, not null
+     * @throws ZoneRulesException if the zone ID is unknown
+     */
+    public static ZoneRules getRules(String zoneId) {
+        Objects.requireNonNull(zoneId, "zoneId");
+        return getProvider(zoneId).provideRules(zoneId);
+    }
+
+    /**
+     * Gets the history of rules for the zone ID.
+     * <p>
+     * Time-zones are defined by governments and change frequently.
+     * This method allows applications to find the history of changes to the
+     * rules for a single zone ID. The map is keyed by a string, which is the
+     * version string associated with the rules.
+     * <p>
+     * The exact meaning and format of the version is provider specific.
+     * The version must follow lexicographical order, thus the returned map will
+     * be order from the oldest known rules to the newest available rules.
+     * The default 'TZDB' group uses version numbering consisting of the year
+     * followed by a letter, such as '2009e' or '2012f'.
+     * <p>
+     * Implementations must provide a result for each valid zone ID, however
+     * they do not have to provide a history of rules.
+     * Thus the map will always contain one element, and will only contain more
+     * than one element if historical rule information is available.
+     *
+     * @param zoneId  the zone region ID as used by {@code ZoneId}, not null
+     * @return a modifiable copy of the history of the rules for the ID, sorted
+     *  from oldest to newest, not null
+     * @throws ZoneRulesException if the zone ID is unknown
+     */
+    public static NavigableMap<String, ZoneRules> getVersions(String zoneId) {
+        Objects.requireNonNull(zoneId, "zoneId");
+        return getProvider(zoneId).provideVersions(zoneId);
+    }
+
+    /**
+     * Gets the provider for the zone ID.
+     *
+     * @param zoneId  the zone region ID as used by {@code ZoneId}, not null
+     * @return the provider, not null
+     * @throws ZoneRulesException if the zone ID is unknown
+     */
+    private static ZoneRulesProvider getProvider(String zoneId) {
+        ZoneRulesProvider provider = ZONES.get(zoneId);
+        if (provider == null) {
+            if (ZONES.isEmpty()) {
+                throw new ZoneRulesException("No time-zone data files registered");
+            }
+            throw new ZoneRulesException("Unknown time-zone ID: " + zoneId);
+        }
+        return provider;
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Registers a zone rules provider.
+     * <p>
+     * This adds a new provider to those currently available.
+     * A provider supplies rules for one or more zone IDs.
+     * A provider cannot be registered if it supplies a zone ID that has already been
+     * registered. See the notes on time-zone IDs in {@link ZoneId}, especially
+     * the section on using the concept of a "group" to make IDs unique.
+     * <p>
+     * To ensure the integrity of time-zones already created, there is no way
+     * to deregister providers.
+     *
+     * @param provider  the provider to register, not null
+     * @throws ZoneRulesException if a region is already registered
+     */
+    public static void registerProvider(ZoneRulesProvider provider) {
+        Objects.requireNonNull(provider, "provider");
+        registerProvider0(provider);
+        PROVIDERS.add(provider);
+    }
+
+    /**
+     * Registers the provider.
+     *
+     * @param provider  the provider to register, not null
+     * @throws ZoneRulesException if unable to complete the registration
+     */
+    private static void registerProvider0(ZoneRulesProvider provider) {
+        for (String zoneId : provider.provideZoneIds()) {
+            Objects.requireNonNull(zoneId, "zoneId");
+            ZoneRulesProvider old = ZONES.putIfAbsent(zoneId, provider.provideBind(zoneId));
+            if (old != null) {
+                throw new ZoneRulesException(
+                    "Unable to register zone as one already registered with that ID: " + zoneId +
+                    ", currently loading from provider: " + provider);
+            }
+        }
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Refreshes the rules from the underlying data provider.
+     * <p>
+     * This method is an extension point that allows providers to refresh their
+     * rules dynamically at a time of the applications choosing.
+     * After calling this method, the offset stored in any {@link ZonedDateTime}
+     * may be invalid for the zone ID.
+     * <p>
+     * Dynamic behavior is entirely optional and most providers, including the
+     * default provider, do not support it.
+     *
+     * @return true if the rules were updated
+     * @throws ZoneRulesException if an error occurs during the refresh
+     */
+    public static boolean refresh() {
+        boolean changed = false;
+        for (ZoneRulesProvider provider : PROVIDERS) {
+            changed |= provider.provideRefresh();
+        }
+        return changed;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructor.
+     */
+    protected ZoneRulesProvider() {
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * SPI method to get the available zone IDs.
+     * <p>
+     * This obtains the IDs that this {@code ZoneRulesProvider} provides.
+     * A provider should provide data for at least one region.
+     * <p>
+     * The returned regions remain available and valid for the lifetime of the application.
+     * A dynamic provider may increase the set of regions as more data becomes available.
+     *
+     * @return the unmodifiable set of region IDs being provided, not null
+     */
+    protected abstract Set<String> provideZoneIds();
+
+    /**
+     * SPI method to bind to the specified zone ID.
+     * <p>
+     * {@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.
+     * <p>
+     * This optimization is optional. Returning {@code this} is acceptable.
+     * <p>
+     * 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.
+     * <p>
+     * This loads the rules for the region and version specified.
+     * The version may be null to indicate the "latest" version.
+     *
+     * @param regionId  the time-zone region ID, not null
+     * @return the rules, not null
+     * @throws DateTimeException if rules cannot be obtained
+     */
+    protected abstract ZoneRules provideRules(String regionId);
+
+    /**
+     * SPI method to get the history of rules for the zone ID.
+     * <p>
+     * This returns a map of historical rules keyed by a version string.
+     * The exact meaning and format of the version is provider specific.
+     * The version must follow lexicographical order, thus the returned map will
+     * be order from the oldest known rules to the newest available rules.
+     * The default 'TZDB' group uses version numbering consisting of the year
+     * followed by a letter, such as '2009e' or '2012f'.
+     * <p>
+     * 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.
+     * <p>
+     * The returned versions remain available and valid for the lifetime of the application.
+     * A dynamic provider may increase the set of versions as more data becomes available.
+     *
+     * @param zoneId  the zone region ID as used by {@code ZoneId}, not null
+     * @return a modifiable copy of the history of the rules for the ID, sorted
+     *  from oldest to newest, not null
+     * @throws ZoneRulesException if the zone ID is unknown
+     */
+    protected abstract NavigableMap<String, ZoneRules> provideVersions(String zoneId);
+
+    /**
+     * SPI method to refresh the rules from the underlying data provider.
+     * <p>
+     * This method provides the opportunity for a provider to dynamically
+     * recheck the underlying data provider to find the latest rules.
+     * This could be used to load new rules without stopping the JVM.
+     * Dynamic behavior is entirely optional and most providers do not support it.
+     * <p>
+     * This implementation returns false.
+     *
+     * @return true if the rules were updated
+     * @throws DateTimeException if an error occurs during the refresh
+     */
+    protected boolean provideRefresh() {
+        return false;
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * A provider bound to a single zone ID.
+     */
+    private static class BoundProvider extends ZoneRulesProvider {
+        private final ZoneRulesProvider provider;
+        private final String zoneId;
+        private final ZoneRules rules;
+
+        private BoundProvider(ZoneRulesProvider provider, String zoneId) {
+            this.provider = provider;
+            this.zoneId = zoneId;
+            this.rules = provider.provideRules(zoneId);
+        }
+
+        @Override
+        protected Set<String> provideZoneIds() {
+            return new HashSet<>(Collections.singleton(zoneId));
+        }
+
+        @Override
+        protected ZoneRules provideRules(String regionId) {
+            return rules;
+        }
+
+        @Override
+        protected NavigableMap<String, ZoneRules> provideVersions(String zoneId) {
+            return provider.provideVersions(zoneId);
+        }
+
+        @Override
+        public String toString() {
+            return zoneId;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/time/zone/package-info.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * <p>
+ * Support for time-zones and their rules.
+ * </p>
+ * <p>
+ * Daylight Saving Time and Time-Zones are concepts used by Governments to alter local time.
+ * This package provides support for time-zones, their rules and the resulting
+ * gaps and overlaps in the local time-line typically caused by Daylight Saving Time.
+ * </p>
+ *
+ * <h3>Package specification</h3>
+ * <p>
+ * 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.
+ * </p>
+ * <p>
+ * All calculations should check for numeric overflow and throw either an {@link java.lang.ArithmeticException}
+ * or a {@link java.time.DateTimeException}.
+ * </p>
+ * @since JDK1.8
+ */
+package java.time.zone;
--- a/jdk/src/share/classes/java/util/Formatter.java	Tue Jan 22 18:30:49 2013 -0800
+++ b/jdk/src/share/classes/java/util/Formatter.java	Tue Jan 22 20:59:21 2013 -0800
@@ -50,6 +50,21 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.Queries;
+import java.time.temporal.OffsetDate;
+import java.time.temporal.OffsetDateTime;
+import java.time.temporal.OffsetTime;
+import java.time.temporal.ChronoZonedDateTime;
+import java.time.format.TextStyle;
+import java.time.zone.ZoneRules;
+
 import sun.misc.DoubleConsts;
 import sun.misc.FormattedFloatingDecimal;
 
@@ -254,8 +269,8 @@
  * </ol>
  *
  * <li> <b>Date/Time</b> - may be applied to Java types which are capable of
- * encoding a date or time: {@code long}, {@link Long}, {@link Calendar}, and
- * {@link Date}.
+ * encoding a date or time: {@code long}, {@link Long}, {@link Calendar},
+ * {@link Date} and {@link TemporalAccessor TemporalAccessor}
  *
  * <li> <b>Percent</b> - produces a literal {@code '%'}
  * (<tt>'&#92;u0025'</tt>)
@@ -1488,7 +1503,7 @@
  * <h4><a name="ddt">Date/Time</a></h4>
  *
  * <p> This conversion may be applied to {@code long}, {@link Long}, {@link
- * Calendar}, and {@link Date}.
+ * Calendar}, {@link Date} and {@link TemporalAccessor TemporalAccessor}
  *
  * <table cellpadding=5 summary="DTConv">
  *
@@ -2782,6 +2797,9 @@
             } else if (arg instanceof Calendar) {
                 cal = (Calendar) ((Calendar)arg).clone();
                 cal.setLenient(true);
+            } else if (arg instanceof TemporalAccessor) {
+                print((TemporalAccessor)arg, c, l);
+                return;
             } else {
                 failConversion(c, arg);
             }
@@ -4032,6 +4050,242 @@
             return sb;
         }
 
+        private void print(TemporalAccessor t, char c, Locale l)  throws IOException {
+            StringBuilder sb = new StringBuilder();
+            print(sb, t, c, l);
+            // justify based on width
+            String s = justify(sb.toString());
+            if (f.contains(Flags.UPPERCASE))
+                s = s.toUpperCase();
+            a.append(s);
+        }
+
+        private Appendable print(StringBuilder sb, TemporalAccessor t, char c,
+                                 Locale l) throws IOException {
+            if (sb == null)
+                sb = new StringBuilder();
+            try {
+                switch (c) {
+                case DateTime.HOUR_OF_DAY_0: {  // 'H' (00 - 23)
+                    int i = t.get(ChronoField.HOUR_OF_DAY);
+                    sb.append(localizedMagnitude(null, i, Flags.ZERO_PAD, 2, l));
+                    break;
+                }
+                case DateTime.HOUR_OF_DAY: {   // 'k' (0 - 23) -- like H
+                    int i = t.get(ChronoField.HOUR_OF_DAY);
+                    sb.append(localizedMagnitude(null, i, Flags.NONE, 2, l));
+                    break;
+                }
+                case DateTime.HOUR_0:      {  // 'I' (01 - 12)
+                    int i = t.get(ChronoField.CLOCK_HOUR_OF_AMPM);
+                    sb.append(localizedMagnitude(null, i, Flags.ZERO_PAD, 2, l));
+                    break;
+                }
+                case DateTime.HOUR:        { // 'l' (1 - 12) -- like I
+                    int i = t.get(ChronoField.CLOCK_HOUR_OF_AMPM);
+                    sb.append(localizedMagnitude(null, i, Flags.NONE, 2, l));
+                    break;
+                }
+                case DateTime.MINUTE:      { // 'M' (00 - 59)
+                    int i = t.get(ChronoField.MINUTE_OF_HOUR);
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, 2, l));
+                    break;
+                }
+                case DateTime.NANOSECOND:  { // 'N' (000000000 - 999999999)
+                    int i = t.get(ChronoField.MILLI_OF_SECOND) * 1000000;
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, 9, l));
+                    break;
+                }
+                case DateTime.MILLISECOND: { // 'L' (000 - 999)
+                    int i = t.get(ChronoField.MILLI_OF_SECOND);
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, 3, l));
+                    break;
+                }
+                case DateTime.MILLISECOND_SINCE_EPOCH: { // 'Q' (0 - 99...?)
+                    long i = t.getLong(ChronoField.INSTANT_SECONDS) * 1000L +
+                             t.getLong(ChronoField.MILLI_OF_SECOND);
+                    Flags flags = Flags.NONE;
+                    sb.append(localizedMagnitude(null, i, flags, width, l));
+                    break;
+                }
+                case DateTime.AM_PM:       { // 'p' (am or pm)
+                    // Calendar.AM = 0, Calendar.PM = 1, LocaleElements defines upper
+                    String[] ampm = { "AM", "PM" };
+                    if (l != null && l != Locale.US) {
+                        DateFormatSymbols dfs = DateFormatSymbols.getInstance(l);
+                        ampm = dfs.getAmPmStrings();
+                    }
+                    String s = ampm[t.get(ChronoField.AMPM_OF_DAY)];
+                    sb.append(s.toLowerCase(l != null ? l : Locale.US));
+                    break;
+                }
+                case DateTime.SECONDS_SINCE_EPOCH: { // 's' (0 - 99...?)
+                    long i = t.getLong(ChronoField.INSTANT_SECONDS);
+                    Flags flags = Flags.NONE;
+                    sb.append(localizedMagnitude(null, i, flags, width, l));
+                    break;
+                }
+                case DateTime.SECOND:      { // 'S' (00 - 60 - leap second)
+                    int i = t.get(ChronoField.SECOND_OF_MINUTE);
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, 2, l));
+                    break;
+                }
+                case DateTime.ZONE_NUMERIC: { // 'z' ({-|+}####) - ls minus?
+                    int i = t.get(ChronoField.OFFSET_SECONDS);
+                    boolean neg = i < 0;
+                    sb.append(neg ? '-' : '+');
+                    if (neg)
+                        i = -i;
+                    int min = i / 60;
+                    // combine minute and hour into a single integer
+                    int offset = (min / 60) * 100 + (min % 60);
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, offset, flags, 4, l));
+                    break;
+                }
+                case DateTime.ZONE:        { // 'Z' (symbol)
+                    ZoneId zid = t.query(Queries.zone());
+                    if (zid == null) {
+                        throw new IllegalFormatConversionException(c, t.getClass());
+                    }
+                    if (!(zid instanceof ZoneOffset) &&
+                        t.isSupported(ChronoField.INSTANT_SECONDS)) {
+                        Instant instant = Instant.from(t);
+                        sb.append(TimeZone.getTimeZone(zid.getId())
+                                          .getDisplayName(zid.getRules().isDaylightSavings(instant),
+                                                          TimeZone.SHORT,
+                                                          (l == null) ? Locale.US : l));
+                        break;
+                    }
+                    sb.append(zid.getId());
+                    break;
+                }
+                // Date
+                case DateTime.NAME_OF_DAY_ABBREV:     // 'a'
+                case DateTime.NAME_OF_DAY:          { // 'A'
+                    int i = t.get(ChronoField.DAY_OF_WEEK) % 7 + 1;
+                    Locale lt = ((l == null) ? Locale.US : l);
+                    DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt);
+                    if (c == DateTime.NAME_OF_DAY)
+                        sb.append(dfs.getWeekdays()[i]);
+                    else
+                        sb.append(dfs.getShortWeekdays()[i]);
+                    break;
+                }
+                case DateTime.NAME_OF_MONTH_ABBREV:   // 'b'
+                case DateTime.NAME_OF_MONTH_ABBREV_X: // 'h' -- same b
+                case DateTime.NAME_OF_MONTH:        { // 'B'
+                    int i = t.get(ChronoField.MONTH_OF_YEAR) - 1;
+                    Locale lt = ((l == null) ? Locale.US : l);
+                    DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt);
+                    if (c == DateTime.NAME_OF_MONTH)
+                        sb.append(dfs.getMonths()[i]);
+                    else
+                        sb.append(dfs.getShortMonths()[i]);
+                    break;
+                }
+                case DateTime.CENTURY:                // 'C' (00 - 99)
+                case DateTime.YEAR_2:                 // 'y' (00 - 99)
+                case DateTime.YEAR_4:               { // 'Y' (0000 - 9999)
+                    int i = t.get(ChronoField.YEAR);
+                    int size = 2;
+                    switch (c) {
+                    case DateTime.CENTURY:
+                        i /= 100;
+                        break;
+                    case DateTime.YEAR_2:
+                        i %= 100;
+                        break;
+                    case DateTime.YEAR_4:
+                        size = 4;
+                        break;
+                    }
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, size, l));
+                    break;
+                }
+                case DateTime.DAY_OF_MONTH_0:         // 'd' (01 - 31)
+                case DateTime.DAY_OF_MONTH:         { // 'e' (1 - 31) -- like d
+                    int i = t.get(ChronoField.DAY_OF_MONTH);
+                    Flags flags = (c == DateTime.DAY_OF_MONTH_0
+                                   ? Flags.ZERO_PAD
+                                   : Flags.NONE);
+                    sb.append(localizedMagnitude(null, i, flags, 2, l));
+                    break;
+                }
+                case DateTime.DAY_OF_YEAR:          { // 'j' (001 - 366)
+                    int i = t.get(ChronoField.DAY_OF_YEAR);
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, 3, l));
+                    break;
+                }
+                case DateTime.MONTH:                { // 'm' (01 - 12)
+                    int i = t.get(ChronoField.MONTH_OF_YEAR);
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, 2, l));
+                    break;
+                }
+
+                // Composites
+                case DateTime.TIME:         // 'T' (24 hour hh:mm:ss - %tH:%tM:%tS)
+                case DateTime.TIME_24_HOUR:    { // 'R' (hh:mm same as %H:%M)
+                    char sep = ':';
+                    print(sb, t, DateTime.HOUR_OF_DAY_0, l).append(sep);
+                    print(sb, t, DateTime.MINUTE, l);
+                    if (c == DateTime.TIME) {
+                        sb.append(sep);
+                        print(sb, t, DateTime.SECOND, l);
+                    }
+                    break;
+                }
+                case DateTime.TIME_12_HOUR:    { // 'r' (hh:mm:ss [AP]M)
+                    char sep = ':';
+                    print(sb, t, DateTime.HOUR_0, l).append(sep);
+                    print(sb, t, DateTime.MINUTE, l).append(sep);
+                    print(sb, t, DateTime.SECOND, l).append(' ');
+                    // this may be in wrong place for some locales
+                    StringBuilder tsb = new StringBuilder();
+                    print(tsb, t, DateTime.AM_PM, l);
+                    sb.append(tsb.toString().toUpperCase(l != null ? l : Locale.US));
+                    break;
+                }
+                case DateTime.DATE_TIME:    { // 'c' (Sat Nov 04 12:02:33 EST 1999)
+                    char sep = ' ';
+                    print(sb, t, DateTime.NAME_OF_DAY_ABBREV, l).append(sep);
+                    print(sb, t, DateTime.NAME_OF_MONTH_ABBREV, l).append(sep);
+                    print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep);
+                    print(sb, t, DateTime.TIME, l).append(sep);
+                    print(sb, t, DateTime.ZONE, l).append(sep);
+                    print(sb, t, DateTime.YEAR_4, l);
+                    break;
+                }
+                case DateTime.DATE:            { // 'D' (mm/dd/yy)
+                    char sep = '/';
+                    print(sb, t, DateTime.MONTH, l).append(sep);
+                    print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep);
+                    print(sb, t, DateTime.YEAR_2, l);
+                    break;
+                }
+                case DateTime.ISO_STANDARD_DATE: { // 'F' (%Y-%m-%d)
+                    char sep = '-';
+                    print(sb, t, DateTime.YEAR_4, l).append(sep);
+                    print(sb, t, DateTime.MONTH, l).append(sep);
+                    print(sb, t, DateTime.DAY_OF_MONTH_0, l);
+                    break;
+                }
+                default:
+                    assert false;
+                }
+            } catch (DateTimeException x) {
+                throw new IllegalFormatConversionException(c, t.getClass());
+            }
+            return sb;
+        }
+
         // -- Methods to support throwing exceptions --
 
         private void failMismatch(Flags f, char c) {
--- a/jdk/test/Makefile	Tue Jan 22 18:30:49 2013 -0800
+++ b/jdk/test/Makefile	Tue Jan 22 20:59:21 2013 -0800
@@ -498,6 +498,11 @@
 jdk_math: $(call TestDirs, java/math)
 	$(call RunAgentvmBatch)
 
+# Stable agentvm testruns (TestNG)
+JDK_DEFAULT_TARGETS += jdk_time
+jdk_time: $(call TestDirs, java/time)
+	$(call RunOthervmBatch)
+
 # Stable agentvm testruns (minus items from PROBLEM_LIST)
 JDK_ALL_TARGETS += jdk_other
 JDK_DEFAULT_TARGETS += jdk_other
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/META-INF/services/java.time.temporal.Chrono	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,1 @@
+tck.java.time.calendar.CopticChrono
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/TEST.properties	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,3 @@
+# Threeten test uses TestNG
+TestNG.dirs = .
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/AbstractDateTimeTest.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time;
+
+import java.time.*;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+
+import java.util.List;
+
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.TemporalField;
+
+import org.testng.annotations.Test;
+import test.java.time.AbstractTest;
+import test.java.time.temporal.MockFieldNoValue;
+
+/**
+ * Base test class for {@code Temporal}.
+ */
+public abstract class AbstractDateTimeTest extends AbstractTCKTest {
+
+    /**
+     * Sample {@code Temporal} objects.
+     * @return the objects, not null
+     */
+    protected abstract List<TemporalAccessor> samples();
+
+    /**
+     * List of valid supported fields.
+     * @return the fields, not null
+     */
+    protected abstract List<TemporalField> validFields();
+
+    /**
+     * List of invalid unsupported fields.
+     * @return the fields, not null
+     */
+    protected abstract List<TemporalField> invalidFields();
+
+    //-----------------------------------------------------------------------
+    // isSupported(TemporalField)
+    //-----------------------------------------------------------------------
+    @Test(groups = "tck")
+    public void basicTest_isSupported_TemporalField_supported() {
+        for (TemporalAccessor sample : samples()) {
+            for (TemporalField field : validFields()) {
+                assertEquals(sample.isSupported(field), true, "Failed on " + sample + " " + field);
+            }
+        }
+    }
+
+    @Test(groups = "tck")
+    public void basicTest_isSupported_TemporalField_unsupported() {
+        for (TemporalAccessor sample : samples()) {
+            for (TemporalField field : invalidFields()) {
+                assertEquals(sample.isSupported(field), false, "Failed on " + sample + " " + field);
+            }
+        }
+    }
+
+    @Test(groups = "tck")
+    public void basicTest_isSupported_TemporalField_null() {
+        for (TemporalAccessor sample : samples()) {
+            assertEquals(sample.isSupported(null), false, "Failed on " + sample);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // range(TemporalField)
+    //-----------------------------------------------------------------------
+    @Test(groups = "tck")
+    public void basicTest_range_TemporalField_supported() {
+        for (TemporalAccessor sample : samples()) {
+            for (TemporalField field : validFields()) {
+                sample.range(field);  // no exception
+            }
+        }
+    }
+
+    @Test(groups = "tck")
+    public void basicTest_range_TemporalField_unsupported() {
+        for (TemporalAccessor sample : samples()) {
+            for (TemporalField field : invalidFields()) {
+                try {
+                    sample.range(field);
+                    fail("Failed on " + sample + " " + field);
+                } catch (DateTimeException ex) {
+                    // expected
+                }
+            }
+        }
+    }
+
+    @Test(groups = "tck")
+    public void basicTest_range_TemporalField_null() {
+        for (TemporalAccessor sample : samples()) {
+            try {
+                sample.range(null);
+                fail("Failed on " + sample);
+            } catch (NullPointerException ex) {
+                // expected
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // get(TemporalField)
+    //-----------------------------------------------------------------------
+    @Test(groups = "tck")
+    public void basicTest_get_TemporalField_supported() {
+        for (TemporalAccessor sample : samples()) {
+            for (TemporalField field : validFields()) {
+                if (sample.range(field).isIntValue()) {
+                    sample.get(field);  // no exception
+                } else {
+                    try {
+                        sample.get(field);
+                        fail("Failed on " + sample + " " + field);
+                    } catch (DateTimeException ex) {
+                        // expected
+                    }
+                }
+            }
+        }
+    }
+
+    @Test(groups = "tck")
+    public void basicTest_get_TemporalField_unsupported() {
+        for (TemporalAccessor sample : samples()) {
+            for (TemporalField field : invalidFields()) {
+                try {
+                    sample.get(field);
+                    fail("Failed on " + sample + " " + field);
+                } catch (DateTimeException ex) {
+                    // expected
+                }
+            }
+        }
+    }
+
+    @Test(expectedExceptions=DateTimeException.class)
+    public void test_get_TemporalField_invalidField() {
+        for (TemporalAccessor sample : samples()) {
+            sample.get(MockFieldNoValue.INSTANCE);
+        }
+    }
+
+    @Test(groups = "tck")
+    public void basicTest_get_TemporalField_null() {
+        for (TemporalAccessor sample : samples()) {
+            try {
+                sample.get(null);
+                fail("Failed on " + sample);
+            } catch (NullPointerException ex) {
+                // expected
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // getLong(TemporalField)
+    //-----------------------------------------------------------------------
+    @Test(groups = "tck")
+    public void basicTest_getLong_TemporalField_supported() {
+        for (TemporalAccessor sample : samples()) {
+            for (TemporalField field : validFields()) {
+                sample.getLong(field);  // no exception
+            }
+        }
+    }
+
+    @Test(groups = "tck")
+    public void basicTest_getLong_TemporalField_unsupported() {
+        for (TemporalAccessor sample : samples()) {
+            for (TemporalField field : invalidFields()) {
+                try {
+                    sample.getLong(field);
+                    fail("Failed on " + sample + " " + field);
+                } catch (DateTimeException ex) {
+                    // expected
+                }
+            }
+        }
+    }
+
+    @Test(expectedExceptions=DateTimeException.class)
+    public void test_getLong_TemporalField_invalidField() {
+        for (TemporalAccessor sample : samples()) {
+            sample.getLong(MockFieldNoValue.INSTANCE);
+        }
+    }
+
+    @Test(groups = "tck")
+    public void basicTest_getLong_TemporalField_null() {
+        for (TemporalAccessor sample : samples()) {
+            try {
+                sample.getLong(null);
+                fail("Failed on " + sample);
+            } catch (NullPointerException ex) {
+                // expected
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void basicTest_query() {
+        for (TemporalAccessor sample : samples()) {
+            assertEquals(sample.query(new TemporalQuery<String>() {
+                @Override
+                public String queryFrom(TemporalAccessor temporal) {
+                    return "foo";
+                }
+            }), "foo");
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/AbstractTCKTest.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamConstants;
+import java.io.Serializable;
+import java.lang.reflect.Field;
+
+/**
+ * Base test class.
+ */
+public abstract class AbstractTCKTest {
+
+    protected static boolean isIsoLeap(long year) {
+        if (year % 4 != 0) {
+            return false;
+        }
+        if (year % 100 == 0 && year % 400 != 0) {
+            return false;
+        }
+        return true;
+    }
+
+    protected static void assertSerializable(Object object) throws IOException, ClassNotFoundException {
+        assertEquals(object instanceof Serializable, true);
+        Object deserializedObject = writeThenRead(object);
+        assertEquals(deserializedObject, object);
+    }
+
+    private static Object writeThenRead(Object object) throws IOException, ClassNotFoundException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try (ObjectOutputStream oos = new ObjectOutputStream(baos) ) {
+            oos.writeObject(object);
+        }
+        try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) {
+            return ois.readObject();
+        }
+    }
+
+    protected static void assertSerializedBySer(Object object, byte[] expectedBytes, byte[]... matches) throws Exception {
+        String serClass = object.getClass().getPackage().getName() + ".Ser";
+        Class<?> serCls = Class.forName(serClass);
+        Field field = serCls.getDeclaredField("serialVersionUID");
+        field.setAccessible(true);
+        long serVer = (Long) field.get(null);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try (ObjectOutputStream oos = new ObjectOutputStream(baos) ) {
+            oos.writeObject(object);
+        }
+        byte[] bytes = baos.toByteArray();
+        ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+        try (DataInputStream dis = new DataInputStream(bais)) {
+            assertEquals(dis.readShort(), ObjectStreamConstants.STREAM_MAGIC);
+            assertEquals(dis.readShort(), ObjectStreamConstants.STREAM_VERSION);
+            assertEquals(dis.readByte(), ObjectStreamConstants.TC_OBJECT);
+            assertEquals(dis.readByte(), ObjectStreamConstants.TC_CLASSDESC);
+            assertEquals(dis.readUTF(), serClass);
+            assertEquals(dis.readLong(), serVer);
+            assertEquals(dis.readByte(), ObjectStreamConstants.SC_EXTERNALIZABLE | ObjectStreamConstants.SC_BLOCK_DATA);
+            assertEquals(dis.readShort(), 0);  // number of fields
+            assertEquals(dis.readByte(), ObjectStreamConstants.TC_ENDBLOCKDATA);  // end of classdesc
+            assertEquals(dis.readByte(), ObjectStreamConstants.TC_NULL);  // no superclasses
+            if (expectedBytes.length < 256) {
+                assertEquals(dis.readByte(), ObjectStreamConstants.TC_BLOCKDATA);
+                assertEquals(dis.readUnsignedByte(), expectedBytes.length);
+            } else {
+                assertEquals(dis.readByte(), ObjectStreamConstants.TC_BLOCKDATALONG);
+                assertEquals(dis.readInt(), expectedBytes.length);
+            }
+            byte[] input = new byte[expectedBytes.length];
+            dis.readFully(input);
+            assertEquals(input, expectedBytes);
+            if (matches.length > 0) {
+                for (byte[] match : matches) {
+                    boolean matched = false;
+                    while (matched == false) {
+                        try {
+                            dis.mark(1000);
+                            byte[] possible = new byte[match.length];
+                            dis.readFully(possible);
+                            assertEquals(possible, match);
+                            matched = true;
+                        } catch (AssertionError ex) {
+                            dis.reset();
+                            dis.readByte();  // ignore
+                        }
+                    }
+                }
+            } else {
+                assertEquals(dis.readByte(), ObjectStreamConstants.TC_ENDBLOCKDATA);  // end of blockdata
+                assertEquals(dis.read(), -1);
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/TCKClock.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012 Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time;
+
+import java.time.*;
+
+import static org.testng.Assert.assertEquals;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test Clock.
+ */
+@Test
+public class TCKClock {
+
+    static class MockInstantClock extends Clock {
+        final long millis;
+        final ZoneId zone;
+        MockInstantClock(long millis, ZoneId zone) {
+            this.millis = millis;
+            this.zone = zone;
+        }
+        @Override
+        public long millis() {
+            return millis;
+        }
+        @Override
+        public ZoneId getZone() {
+            return zone;
+        }
+        @Override
+        public Clock withZone(ZoneId timeZone) {
+            return new MockInstantClock(millis, timeZone);
+        }
+        @Override
+        public boolean equals(Object obj) {
+            return false;
+        }
+        @Override
+        public int hashCode() {
+            return 0;
+        }
+        @Override
+        public String toString() {
+            return "Mock";
+        }
+    }
+
+    private static final Instant INSTANT = Instant.ofEpochSecond(1873687, 357000000);
+    private static final ZoneId ZONE = ZoneId.of("Europe/Paris");
+    private static final Clock MOCK_INSTANT = new MockInstantClock(INSTANT.toEpochMilli(), ZONE);
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_mockInstantClock_get() {
+        assertEquals(MOCK_INSTANT.instant(), INSTANT);
+        assertEquals(MOCK_INSTANT.millis(), INSTANT.toEpochMilli());
+        assertEquals(MOCK_INSTANT.getZone(), ZONE);
+    }
+
+    @Test
+    public void test_mockInstantClock_withZone() {
+        ZoneId london = ZoneId.of("Europe/London");
+        Clock changed = MOCK_INSTANT.withZone(london);
+        assertEquals(MOCK_INSTANT.instant(), INSTANT);
+        assertEquals(MOCK_INSTANT.millis(), INSTANT.toEpochMilli());
+        assertEquals(changed.getZone(), london);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/TCKClock_Fixed.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012 Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.IOException;
+import java.time.Clock;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test fixed clock.
+ */
+@Test
+public class TCKClock_Fixed extends AbstractTCKTest {
+
+    private static final ZoneId MOSCOW = ZoneId.of("Europe/Moscow");
+    private static final ZoneId PARIS = ZoneId.of("Europe/Paris");
+    private static final Instant INSTANT = LocalDateTime.of(2008, 6, 30, 11, 30, 10, 500).atZone(ZoneOffset.ofHours(2)).toInstant();
+
+    //-----------------------------------------------------------------------
+    public void test_isSerializable() throws IOException, ClassNotFoundException {
+        assertSerializable(Clock.fixed(INSTANT, ZoneOffset.UTC));
+        assertSerializable(Clock.fixed(INSTANT, PARIS));
+    }
+
+    //-------------------------------------------------------------------------
+    public void test_fixed_InstantZoneId() {
+        Clock test = Clock.fixed(INSTANT, PARIS);
+        assertEquals(test.instant(), INSTANT);
+        assertEquals(test.getZone(), PARIS);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void test_fixed_InstantZoneId_nullInstant() {
+        Clock.fixed(null, PARIS);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void test_fixed_InstantZoneId_nullZoneId() {
+        Clock.fixed(INSTANT, null);
+    }
+
+    //-------------------------------------------------------------------------
+    public void test_withZone() {
+        Clock test = Clock.fixed(INSTANT, PARIS);
+        Clock changed = test.withZone(MOSCOW);
+        assertEquals(test.getZone(), PARIS);
+        assertEquals(changed.getZone(), MOSCOW);
+    }
+
+    public void test_withZone_equal() {
+        Clock test = Clock.fixed(INSTANT, PARIS);
+        Clock changed = test.withZone(PARIS);
+        assertEquals(changed.getZone(), PARIS);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void test_withZone_null() {
+        Clock.fixed(INSTANT, PARIS).withZone(null);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_equals() {
+        Clock a = Clock.fixed(INSTANT, ZoneOffset.UTC);
+        Clock b = Clock.fixed(INSTANT, ZoneOffset.UTC);
+        assertEquals(a.equals(a), true);
+        assertEquals(a.equals(b), true);
+        assertEquals(b.equals(a), true);
+        assertEquals(b.equals(b), true);
+
+        Clock c = Clock.fixed(INSTANT, PARIS);
+        assertEquals(a.equals(c), false);
+
+        Clock d = Clock.fixed(INSTANT.minusNanos(1), ZoneOffset.UTC);
+        assertEquals(a.equals(d), false);
+
+        assertEquals(a.equals(null), false);
+        assertEquals(a.equals("other type"), false);
+        assertEquals(a.equals(Clock.systemUTC()), false);
+    }
+
+    public void test_hashCode() {
+        Clock a = Clock.fixed(INSTANT, ZoneOffset.UTC);
+        Clock b = Clock.fixed(INSTANT, ZoneOffset.UTC);
+        assertEquals(a.hashCode(), a.hashCode());
+        assertEquals(a.hashCode(), b.hashCode());
+
+        Clock c = Clock.fixed(INSTANT, PARIS);
+        assertEquals(a.hashCode() == c.hashCode(), false);
+
+        Clock d = Clock.fixed(INSTANT.minusNanos(1), ZoneOffset.UTC);
+        assertEquals(a.hashCode() == d.hashCode(), false);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_toString() {
+        // spec requires "full state" in toString()
+        Clock test = Clock.fixed(INSTANT, PARIS);
+        assertEquals(test.toString().contains("Europe/Paris"), true);
+        assertEquals(test.toString().contains("2008-06-30T09:30:10.000000500Z"), true);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/TCKClock_Offset.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012 Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertSame;
+
+import java.io.IOException;
+import java.time.Clock;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test offset clock.
+ */
+@Test
+public class TCKClock_Offset extends AbstractTCKTest {
+
+    private static final ZoneId MOSCOW = ZoneId.of("Europe/Moscow");
+    private static final ZoneId PARIS = ZoneId.of("Europe/Paris");
+    private static final Instant INSTANT = LocalDateTime.of(2008, 6, 30, 11, 30, 10, 500).atZone(ZoneOffset.ofHours(2)).toInstant();
+    private static final Duration OFFSET = Duration.ofSeconds(2);
+
+    //-----------------------------------------------------------------------
+    public void test_isSerializable() throws IOException, ClassNotFoundException {
+        assertSerializable(Clock.offset(Clock.system(PARIS), OFFSET));
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_offset_ClockDuration() {
+        Clock test = Clock.offset(Clock.fixed(INSTANT, PARIS), OFFSET);
+        System.out.println(test.instant());
+        System.out.println(INSTANT.plus(OFFSET));
+        assertEquals(test.instant(), INSTANT.plus(OFFSET));
+        assertEquals(test.getZone(), PARIS);
+    }
+
+    public void test_offset_ClockDuration_zeroDuration() {
+        Clock underlying = Clock.system(PARIS);
+        Clock test = Clock.offset(underlying, Duration.ZERO);
+        assertSame(test, underlying);  // spec says same
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void test_offset_ClockDuration_nullClock() {
+        Clock.offset(null, Duration.ZERO);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void test_offset_ClockDuration_nullDuration() {
+        Clock.offset(Clock.systemUTC(), null);
+    }
+
+    //-------------------------------------------------------------------------
+    public void test_withZone() {
+        Clock test = Clock.offset(Clock.system(PARIS), OFFSET);
+        Clock changed = test.withZone(MOSCOW);
+        assertEquals(test.getZone(), PARIS);
+        assertEquals(changed.getZone(), MOSCOW);
+    }
+
+    public void test_withZone_equal() {
+        Clock test = Clock.offset(Clock.system(PARIS), OFFSET);
+        Clock changed = test.withZone(PARIS);
+        assertEquals(test, changed);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void test_withZone_null() {
+        Clock.offset(Clock.system(PARIS), OFFSET).withZone(null);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_equals() {
+        Clock a = Clock.offset(Clock.system(PARIS), OFFSET);
+        Clock b = Clock.offset(Clock.system(PARIS), OFFSET);
+        assertEquals(a.equals(a), true);
+        assertEquals(a.equals(b), true);
+        assertEquals(b.equals(a), true);
+        assertEquals(b.equals(b), true);
+
+        Clock c = Clock.offset(Clock.system(MOSCOW), OFFSET);
+        assertEquals(a.equals(c), false);
+
+        Clock d = Clock.offset(Clock.system(PARIS), OFFSET.minusNanos(1));
+        assertEquals(a.equals(d), false);
+
+        assertEquals(a.equals(null), false);
+        assertEquals(a.equals("other type"), false);
+        assertEquals(a.equals(Clock.systemUTC()), false);
+    }
+
+    public void test_hashCode() {
+        Clock a = Clock.offset(Clock.system(PARIS), OFFSET);
+        Clock b = Clock.offset(Clock.system(PARIS), OFFSET);
+        assertEquals(a.hashCode(), a.hashCode());
+        assertEquals(a.hashCode(), b.hashCode());
+
+        Clock c = Clock.offset(Clock.system(MOSCOW), OFFSET);
+        assertEquals(a.hashCode() == c.hashCode(), false);
+
+        Clock d = Clock.offset(Clock.system(PARIS), OFFSET.minusNanos(1));
+        assertEquals(a.hashCode() == d.hashCode(), false);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_toString() {
+        // spec requires "full state" in toString()
+        Clock test = Clock.offset(Clock.system(PARIS), OFFSET);
+        assertEquals(test.toString().contains("Europe/Paris"), true);
+        assertEquals(test.toString().contains("PT2S"), true);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/TCKClock_System.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012 Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+
+import java.io.IOException;
+import java.time.Clock;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test system clock.
+ */
+@Test
+public class TCKClock_System extends AbstractTCKTest {
+
+    private static final ZoneId MOSCOW = ZoneId.of("Europe/Moscow");
+    private static final ZoneId PARIS = ZoneId.of("Europe/Paris");
+
+    //-----------------------------------------------------------------------
+    public void test_isSerializable() throws IOException, ClassNotFoundException {
+        assertSerializable(Clock.systemUTC());
+        assertSerializable(Clock.systemDefaultZone());
+        assertSerializable(Clock.system(PARIS));
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_instant() {
+        Clock system = Clock.systemUTC();
+        assertEquals(system.getZone(), ZoneOffset.UTC);
+        for (int i = 0; i < 10000; i++) {
+            // assume can eventually get these within 10 milliseconds
+            Instant instant = system.instant();
+            long systemMillis = System.currentTimeMillis();
+            if (systemMillis - instant.toEpochMilli() < 10) {
+                return;  // success
+            }
+        }
+        fail();
+    }
+
+    public void test_millis() {
+        Clock system = Clock.systemUTC();
+        assertEquals(system.getZone(), ZoneOffset.UTC);
+        for (int i = 0; i < 10000; i++) {
+            // assume can eventually get these within 10 milliseconds
+            long instant = system.millis();
+            long systemMillis = System.currentTimeMillis();
+            if (systemMillis - instant < 10) {
+                return;  // success
+            }
+        }
+        fail();
+    }
+
+    //-------------------------------------------------------------------------
+    public void test_systemUTC() {
+        Clock test = Clock.systemUTC();
+        assertEquals(test.getZone(), ZoneOffset.UTC);
+        assertEquals(test, Clock.system(ZoneOffset.UTC));
+    }
+
+    public void test_systemDefaultZone() {
+        Clock test = Clock.systemDefaultZone();
+        assertEquals(test.getZone(), ZoneId.systemDefault());
+        assertEquals(test, Clock.system(ZoneId.systemDefault()));
+    }
+
+    public void test_system_ZoneId() {
+        Clock test = Clock.system(PARIS);
+        assertEquals(test.getZone(), PARIS);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void test_zoneId_nullZoneId() {
+        Clock.system(null);
+    }
+
+    //-------------------------------------------------------------------------
+    public void test_withZone() {
+        Clock test = Clock.system(PARIS);
+        Clock changed = test.withZone(MOSCOW);
+        assertEquals(test.getZone(), PARIS);
+        assertEquals(changed.getZone(), MOSCOW);
+    }
+
+    public void test_withZone_equal() {
+        Clock test = Clock.system(PARIS);
+        Clock changed = test.withZone(PARIS);
+        assertEquals(changed.getZone(), PARIS);
+    }
+
+    public void test_withZone_fromUTC() {
+        Clock test = Clock.systemUTC();
+        Clock changed = test.withZone(PARIS);
+        assertEquals(changed.getZone(), PARIS);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void test_withZone_null() {
+        Clock.systemUTC().withZone(null);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_equals() {
+        Clock a = Clock.systemUTC();
+        Clock b = Clock.systemUTC();
+        assertEquals(a.equals(a), true);
+        assertEquals(a.equals(b), true);
+        assertEquals(b.equals(a), true);
+        assertEquals(b.equals(b), true);
+
+        Clock c = Clock.system(PARIS);
+        Clock d = Clock.system(PARIS);
+        assertEquals(c.equals(c), true);
+        assertEquals(c.equals(d), true);
+        assertEquals(d.equals(c), true);
+        assertEquals(d.equals(d), true);
+
+        assertEquals(a.equals(c), false);
+        assertEquals(c.equals(a), false);
+
+        assertEquals(a.equals(null), false);
+        assertEquals(a.equals("other type"), false);
+        assertEquals(a.equals(Clock.fixed(Instant.now(), ZoneOffset.UTC)), false);
+    }
+
+    public void test_hashCode() {
+        Clock a = Clock.system(ZoneOffset.UTC);
+        Clock b = Clock.system(ZoneOffset.UTC);
+        assertEquals(a.hashCode(), a.hashCode());
+        assertEquals(a.hashCode(), b.hashCode());
+
+        Clock c = Clock.system(PARIS);
+        assertEquals(a.hashCode() == c.hashCode(), false);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_toString() {
+        // spec requires "full state" in toString()
+        Clock test = Clock.system(PARIS);
+        assertEquals(test.toString().contains("Europe/Paris"), true);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/TCKClock_Tick.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012 Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertSame;
+
+import java.io.IOException;
+import java.time.Clock;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test tick clock.
+ */
+@Test
+public class TCKClock_Tick extends AbstractTCKTest {
+
+    private static final ZoneId MOSCOW = ZoneId.of("Europe/Moscow");
+    private static final ZoneId PARIS = ZoneId.of("Europe/Paris");
+    private static final Duration AMOUNT = Duration.ofSeconds(2);
+    private static final ZonedDateTime ZDT = LocalDateTime.of(2008, 6, 30, 11, 30, 10, 500).atZone(ZoneOffset.ofHours(2));
+    private static final Instant INSTANT = ZDT.toInstant();
+
+    //-----------------------------------------------------------------------
+    public void test_isSerializable() throws IOException, ClassNotFoundException {
+        assertSerializable(Clock.tickSeconds(PARIS));
+        assertSerializable(Clock.tickMinutes(MOSCOW));
+        assertSerializable(Clock.tick(Clock.fixed(INSTANT, PARIS), AMOUNT));
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_tick_ClockDuration_250millis() {
+        for (int i = 0; i < 1000; i++) {
+            Clock test = Clock.tick(Clock.fixed(ZDT.withNano(i * 1000_000).toInstant(), PARIS), Duration.ofMillis(250));
+            assertEquals(test.instant(), ZDT.withNano((i / 250) * 250_000_000).toInstant());
+            assertEquals(test.getZone(), PARIS);
+        }
+    }
+
+    public void test_tick_ClockDuration_250micros() {
+        for (int i = 0; i < 1000; i++) {
+            Clock test = Clock.tick(Clock.fixed(ZDT.withNano(i * 1000).toInstant(), PARIS), Duration.ofNanos(250_000));
+            assertEquals(test.instant(), ZDT.withNano((i / 250) * 250_000).toInstant());
+            assertEquals(test.getZone(), PARIS);
+        }
+    }
+
+    public void test_tick_ClockDuration_20nanos() {
+        for (int i = 0; i < 1000; i++) {
+            Clock test = Clock.tick(Clock.fixed(ZDT.withNano(i).toInstant(), PARIS), Duration.ofNanos(20));
+            assertEquals(test.instant(), ZDT.withNano((i / 20) * 20).toInstant());
+            assertEquals(test.getZone(), PARIS);
+        }
+    }
+
+    public void test_tick_ClockDuration_zeroDuration() {
+        Clock underlying = Clock.system(PARIS);
+        Clock test = Clock.tick(underlying, Duration.ZERO);
+        assertSame(test, underlying);  // spec says same
+    }
+
+    public void test_tick_ClockDuration_1nsDuration() {
+        Clock underlying = Clock.system(PARIS);
+        Clock test = Clock.tick(underlying, Duration.ofNanos(1));
+        assertSame(test, underlying);  // spec says same
+    }
+
+    @Test(expectedExceptions = ArithmeticException.class)
+    public void test_tick_ClockDuration_maxDuration() {
+        Clock.tick(Clock.systemUTC(), Duration.ofSeconds(Long.MAX_VALUE));
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void test_tick_ClockDuration_subMilliNotDivisible_123ns() {
+        Clock.tick(Clock.systemUTC(), Duration.ofSeconds(0, 123));
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void test_tick_ClockDuration_subMilliNotDivisible_999ns() {
+        Clock.tick(Clock.systemUTC(), Duration.ofSeconds(0, 999));
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void test_tick_ClockDuration_subMilliNotDivisible_999_999_999ns() {
+        Clock.tick(Clock.systemUTC(), Duration.ofSeconds(0, 999_999_999));
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void test_tick_ClockDuration_negative1ns() {
+        Clock.tick(Clock.systemUTC(), Duration.ofSeconds(0, -1));
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void test_tick_ClockDuration_negative1s() {
+        Clock.tick(Clock.systemUTC(), Duration.ofSeconds(-1));
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void test_tick_ClockDuration_nullClock() {
+        Clock.tick(null, Duration.ZERO);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void test_tick_ClockDuration_nullDuration() {
+        Clock.tick(Clock.systemUTC(), null);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_tickSeconds_ZoneId() throws Exception {
+        Clock test = Clock.tickSeconds(PARIS);
+        assertEquals(test.getZone(), PARIS);
+        assertEquals(test.instant().getNano(), 0);
+        Thread.sleep(100);
+        assertEquals(test.instant().getNano(), 0);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void test_tickSeconds_ZoneId_nullZoneId() {
+        Clock.tickSeconds(null);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_tickMinutes_ZoneId() {
+        Clock test = Clock.tickMinutes(PARIS);
+        assertEquals(test.getZone(), PARIS);
+        Instant instant = test.instant();
+        assertEquals(instant.getEpochSecond() % 60, 0);
+        assertEquals(instant.getNano(), 0);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void test_tickMinutes_ZoneId_nullZoneId() {
+        Clock.tickMinutes(null);
+    }
+
+    //-------------------------------------------------------------------------
+    public void test_withZone() {
+        Clock test = Clock.tick(Clock.system(PARIS), Duration.ofMillis(500));
+        Clock changed = test.withZone(MOSCOW);
+        assertEquals(test.getZone(), PARIS);
+        assertEquals(changed.getZone(), MOSCOW);
+    }
+
+    public void test_withZone_equal() {
+        Clock test = Clock.tick(Clock.system(PARIS), Duration.ofMillis(500));
+        Clock changed = test.withZone(PARIS);
+        assertEquals(test, changed);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void test_withZone_null() {
+        Clock.tick(Clock.system(PARIS), Duration.ofMillis(500)).withZone(null);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test__equals() {
+        Clock a = Clock.tick(Clock.system(PARIS), Duration.ofMillis(500));
+        Clock b = Clock.tick(Clock.system(PARIS), Duration.ofMillis(500));
+        assertEquals(a.equals(a), true);
+        assertEquals(a.equals(b), true);
+        assertEquals(b.equals(a), true);
+        assertEquals(b.equals(b), true);
+
+        Clock c = Clock.tick(Clock.system(MOSCOW), Duration.ofMillis(500));
+        assertEquals(a.equals(c), false);
+
+        Clock d = Clock.tick(Clock.system(PARIS), Duration.ofMillis(499));
+        assertEquals(a.equals(d), false);
+
+        assertEquals(a.equals(null), false);
+        assertEquals(a.equals("other type"), false);
+        assertEquals(a.equals(Clock.systemUTC()), false);
+    }
+
+    public void test_hashCode() {
+        Clock a = Clock.tick(Clock.system(PARIS), Duration.ofMillis(500));
+        Clock b = Clock.tick(Clock.system(PARIS), Duration.ofMillis(500));
+        assertEquals(a.hashCode(), a.hashCode());
+        assertEquals(a.hashCode(), b.hashCode());
+
+        Clock c = Clock.tick(Clock.system(MOSCOW), Duration.ofMillis(500));
+        assertEquals(a.hashCode() == c.hashCode(), false);
+
+        Clock d = Clock.tick(Clock.system(PARIS), Duration.ofMillis(499));
+        assertEquals(a.hashCode() == d.hashCode(), false);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_toString() {
+        // spec requires "full state" in toString()
+        Clock test = Clock.tick(Clock.system(PARIS), AMOUNT);
+        assertEquals(test.toString().contains("Europe/Paris"), true);
+        assertEquals(test.toString().contains("PT2S"), true);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/TCKDayOfWeek.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,351 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time;
+
+import static java.time.DayOfWeek.MONDAY;
+import static java.time.DayOfWeek.SUNDAY;
+import static java.time.DayOfWeek.WEDNESDAY;
+import static java.time.temporal.ChronoField.DAY_OF_WEEK;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertSame;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+
+import java.time.DateTimeException;
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.Month;
+import java.time.format.TextStyle;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.ISOChrono;
+import java.time.temporal.JulianFields;
+import java.time.temporal.Queries;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalField;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test DayOfWeek.
+ */
+@Test
+public class TCKDayOfWeek extends AbstractDateTimeTest {
+
+    @BeforeMethod
+    public void setUp() {
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    protected List<TemporalAccessor> samples() {
+        TemporalAccessor[] array = {MONDAY, WEDNESDAY, SUNDAY, };
+        return Arrays.asList(array);
+    }
+
+    @Override
+    protected List<TemporalField> validFields() {
+        TemporalField[] array = {
+            DAY_OF_WEEK,
+        };
+        return Arrays.asList(array);
+    }
+
+    @Override
+    protected List<TemporalField> invalidFields() {
+        List<TemporalField> list = new ArrayList<>(Arrays.<TemporalField>asList(ChronoField.values()));
+        list.removeAll(validFields());
+        list.add(JulianFields.JULIAN_DAY);
+        list.add(JulianFields.MODIFIED_JULIAN_DAY);
+        list.add(JulianFields.RATA_DIE);
+        return list;
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_factory_int_singleton() {
+        for (int i = 1; i <= 7; i++) {
+            DayOfWeek test = DayOfWeek.of(i);
+            assertEquals(test.getValue(), i);
+            assertSame(DayOfWeek.of(i), test);
+        }
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_int_valueTooLow() {
+        DayOfWeek.of(0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_int_valueTooHigh() {
+        DayOfWeek.of(8);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_factory_CalendricalObject() {
+        assertEquals(DayOfWeek.from(LocalDate.of(2011, 6, 6)), DayOfWeek.MONDAY);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_CalendricalObject_invalid_noDerive() {
+        DayOfWeek.from(LocalTime.of(12, 30));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_factory_CalendricalObject_null() {
+        DayOfWeek.from((TemporalAccessor) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // get(TemporalField)
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_get_TemporalField() {
+        assertEquals(DayOfWeek.WEDNESDAY.getLong(ChronoField.DAY_OF_WEEK), 3);
+    }
+
+    @Test
+    public void test_getLong_TemporalField() {
+        assertEquals(DayOfWeek.WEDNESDAY.getLong(ChronoField.DAY_OF_WEEK), 3);
+    }
+
+    //-----------------------------------------------------------------------
+    // query(TemporalQuery)
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_query_chrono() {
+        assertEquals(DayOfWeek.FRIDAY.query(Queries.chrono()), null);
+        assertEquals(Queries.chrono().queryFrom(DayOfWeek.FRIDAY), null);
+    }
+
+    @Test
+    public void test_query_zoneId() {
+        assertEquals(DayOfWeek.FRIDAY.query(Queries.zoneId()), null);
+        assertEquals(Queries.zoneId().queryFrom(DayOfWeek.FRIDAY), null);
+    }
+
+    @Test
+    public void test_query_precision() {
+        assertEquals(DayOfWeek.FRIDAY.query(Queries.precision()), ChronoUnit.DAYS);
+        assertEquals(Queries.precision().queryFrom(DayOfWeek.FRIDAY), ChronoUnit.DAYS);
+    }
+
+    @Test
+    public void test_query_offset() {
+        assertEquals(DayOfWeek.FRIDAY.query(Queries.offset()), null);
+        assertEquals(Queries.offset().queryFrom(DayOfWeek.FRIDAY), null);
+    }
+
+    @Test
+    public void test_query_zone() {
+        assertEquals(DayOfWeek.FRIDAY.query(Queries.zone()), null);
+        assertEquals(Queries.zone().queryFrom(DayOfWeek.FRIDAY), null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_query_null() {
+        DayOfWeek.FRIDAY.query(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // getText()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_getText() {
+        assertEquals(DayOfWeek.MONDAY.getText(TextStyle.SHORT, Locale.US), "Mon");
+    }
+
+    @Test(expectedExceptions = NullPointerException.class, groups={"tck"})
+    public void test_getText_nullStyle() {
+        DayOfWeek.MONDAY.getText(null, Locale.US);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class, groups={"tck"})
+    public void test_getText_nullLocale() {
+        DayOfWeek.MONDAY.getText(TextStyle.FULL, null);
+    }
+
+    //-----------------------------------------------------------------------
+    // plus(long), plus(long,unit)
+    //-----------------------------------------------------------------------
+    @DataProvider(name="plus")
+    Object[][] data_plus() {
+        return new Object[][] {
+            {1, -8, 7},
+            {1, -7, 1},
+            {1, -6, 2},
+            {1, -5, 3},
+            {1, -4, 4},
+            {1, -3, 5},
+            {1, -2, 6},
+            {1, -1, 7},
+            {1, 0, 1},
+            {1, 1, 2},
+            {1, 2, 3},
+            {1, 3, 4},
+            {1, 4, 5},
+            {1, 5, 6},
+            {1, 6, 7},
+            {1, 7, 1},
+            {1, 8, 2},
+
+            {1, 1, 2},
+            {2, 1, 3},
+            {3, 1, 4},
+            {4, 1, 5},
+            {5, 1, 6},
+            {6, 1, 7},
+            {7, 1, 1},
+
+            {1, -1, 7},
+            {2, -1, 1},
+            {3, -1, 2},
+            {4, -1, 3},
+            {5, -1, 4},
+            {6, -1, 5},
+            {7, -1, 6},
+        };
+    }
+
+    @Test(dataProvider="plus", groups={"tck"})
+    public void test_plus_long(int base, long amount, int expected) {
+        assertEquals(DayOfWeek.of(base).plus(amount), DayOfWeek.of(expected));
+    }
+
+    //-----------------------------------------------------------------------
+    // minus(long), minus(long,unit)
+    //-----------------------------------------------------------------------
+    @DataProvider(name="minus")
+    Object[][] data_minus() {
+        return new Object[][] {
+            {1, -8, 2},
+            {1, -7, 1},
+            {1, -6, 7},
+            {1, -5, 6},
+            {1, -4, 5},
+            {1, -3, 4},
+            {1, -2, 3},
+            {1, -1, 2},
+            {1, 0, 1},
+            {1, 1, 7},
+            {1, 2, 6},
+            {1, 3, 5},
+            {1, 4, 4},
+            {1, 5, 3},
+            {1, 6, 2},
+            {1, 7, 1},
+            {1, 8, 7},
+        };
+    }
+
+    @Test(dataProvider="minus", groups={"tck"})
+    public void test_minus_long(int base, long amount, int expected) {
+        assertEquals(DayOfWeek.of(base).minus(amount), DayOfWeek.of(expected));
+    }
+
+    //-----------------------------------------------------------------------
+    // adjustInto()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_adjustInto() {
+        assertEquals(DayOfWeek.MONDAY.adjustInto(LocalDate.of(2012, 9, 2)), LocalDate.of(2012, 8, 27));
+        assertEquals(DayOfWeek.MONDAY.adjustInto(LocalDate.of(2012, 9, 3)), LocalDate.of(2012, 9, 3));
+        assertEquals(DayOfWeek.MONDAY.adjustInto(LocalDate.of(2012, 9, 4)), LocalDate.of(2012, 9, 3));
+        assertEquals(DayOfWeek.MONDAY.adjustInto(LocalDate.of(2012, 9, 10)), LocalDate.of(2012, 9, 10));
+        assertEquals(DayOfWeek.MONDAY.adjustInto(LocalDate.of(2012, 9, 11)), LocalDate.of(2012, 9, 10));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_adjustInto_null() {
+        DayOfWeek.MONDAY.adjustInto((Temporal) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // toString()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_toString() {
+        assertEquals(DayOfWeek.MONDAY.toString(), "MONDAY");
+        assertEquals(DayOfWeek.TUESDAY.toString(), "TUESDAY");
+        assertEquals(DayOfWeek.WEDNESDAY.toString(), "WEDNESDAY");
+        assertEquals(DayOfWeek.THURSDAY.toString(), "THURSDAY");
+        assertEquals(DayOfWeek.FRIDAY.toString(), "FRIDAY");
+        assertEquals(DayOfWeek.SATURDAY.toString(), "SATURDAY");
+        assertEquals(DayOfWeek.SUNDAY.toString(), "SUNDAY");
+    }
+
+    //-----------------------------------------------------------------------
+    // generated methods
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_enum() {
+        assertEquals(DayOfWeek.valueOf("MONDAY"), DayOfWeek.MONDAY);
+        assertEquals(DayOfWeek.values()[0], DayOfWeek.MONDAY);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/TCKDuration.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,2135 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time;
+
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.HALF_DAYS;
+import static java.time.temporal.ChronoUnit.HOURS;
+import static java.time.temporal.ChronoUnit.MICROS;
+import static java.time.temporal.ChronoUnit.MILLIS;
+import static java.time.temporal.ChronoUnit.MINUTES;
+import static java.time.temporal.ChronoUnit.NANOS;
+import static java.time.temporal.ChronoUnit.SECONDS;
+import static java.time.temporal.ChronoUnit.WEEKS;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import java.time.DateTimeException;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.TemporalUnit;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test Duration.
+ */
+@Test
+public class TCKDuration extends AbstractTCKTest {
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_serialization() throws Exception {
+        assertSerializable(Duration.ofHours(5));
+        assertSerializable(Duration.ofHours(0));
+        assertSerializable(Duration.ofHours(-5));
+    }
+
+    @Test
+    public void test_serialization_format() throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try (DataOutputStream dos = new DataOutputStream(baos) ) {
+            dos.writeByte(1);
+            dos.writeLong(654321);
+            dos.writeInt(123456789);
+        }
+        byte[] bytes = baos.toByteArray();
+        assertSerializedBySer(Duration.ofSeconds(654321, 123456789), bytes);
+    }
+
+    //-----------------------------------------------------------------------
+    // constants
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_zero() {
+        assertEquals(Duration.ZERO.getSeconds(), 0L);
+        assertEquals(Duration.ZERO.getNano(), 0);
+    }
+
+    //-----------------------------------------------------------------------
+    // ofSeconds(long)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_seconds_long() {
+        for (long i = -2; i <= 2; i++) {
+            Duration t = Duration.ofSeconds(i);
+            assertEquals(t.getSeconds(), i);
+            assertEquals(t.getNano(), 0);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // ofSeconds(long,long)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_seconds_long_long() {
+        for (long i = -2; i <= 2; i++) {
+            for (int j = 0; j < 10; j++) {
+                Duration t = Duration.ofSeconds(i, j);
+                assertEquals(t.getSeconds(), i);
+                assertEquals(t.getNano(), j);
+            }
+            for (int j = -10; j < 0; j++) {
+                Duration t = Duration.ofSeconds(i, j);
+                assertEquals(t.getSeconds(), i - 1);
+                assertEquals(t.getNano(), j + 1000000000);
+            }
+            for (int j = 999999990; j < 1000000000; j++) {
+                Duration t = Duration.ofSeconds(i, j);
+                assertEquals(t.getSeconds(), i);
+                assertEquals(t.getNano(), j);
+            }
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void factory_seconds_long_long_nanosNegativeAdjusted() {
+        Duration test = Duration.ofSeconds(2L, -1);
+        assertEquals(test.getSeconds(), 1);
+        assertEquals(test.getNano(), 999999999);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void factory_seconds_long_long_tooBig() {
+        Duration.ofSeconds(Long.MAX_VALUE, 1000000000);
+    }
+
+    //-----------------------------------------------------------------------
+    // ofMillis(long)
+    //-----------------------------------------------------------------------
+    @DataProvider(name="MillisDurationNoNanos")
+    Object[][] provider_factory_millis_long() {
+        return new Object[][] {
+            {0, 0, 0},
+            {1, 0, 1000000},
+            {2, 0, 2000000},
+            {999, 0, 999000000},
+            {1000, 1, 0},
+            {1001, 1, 1000000},
+            {-1, -1, 999000000},
+            {-2, -1, 998000000},
+            {-999, -1, 1000000},
+            {-1000, -1, 0},
+            {-1001, -2, 999000000},
+        };
+    }
+
+    @Test(dataProvider="MillisDurationNoNanos", groups={"tck"})
+    public void factory_millis_long(long millis, long expectedSeconds, int expectedNanoOfSecond) {
+        Duration test = Duration.ofMillis(millis);
+        assertEquals(test.getSeconds(), expectedSeconds);
+        assertEquals(test.getNano(), expectedNanoOfSecond);
+    }
+
+    //-----------------------------------------------------------------------
+    // ofNanos(long)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_nanos_nanos() {
+        Duration test = Duration.ofNanos(1);
+        assertEquals(test.getSeconds(), 0);
+        assertEquals(test.getNano(), 1);
+    }
+
+    @Test(groups={"tck"})
+    public void factory_nanos_nanosSecs() {
+        Duration test = Duration.ofNanos(1000000002);
+        assertEquals(test.getSeconds(), 1);
+        assertEquals(test.getNano(), 2);
+    }
+
+    @Test(groups={"tck"})
+    public void factory_nanos_negative() {
+        Duration test = Duration.ofNanos(-2000000001);
+        assertEquals(test.getSeconds(), -3);
+        assertEquals(test.getNano(), 999999999);
+    }
+
+    @Test(groups={"tck"})
+    public void factory_nanos_max() {
+        Duration test = Duration.ofNanos(Long.MAX_VALUE);
+        assertEquals(test.getSeconds(), Long.MAX_VALUE / 1000000000);
+        assertEquals(test.getNano(), Long.MAX_VALUE % 1000000000);
+    }
+
+    @Test(groups={"tck"})
+    public void factory_nanos_min() {
+        Duration test = Duration.ofNanos(Long.MIN_VALUE);
+        assertEquals(test.getSeconds(), Long.MIN_VALUE / 1000000000 - 1);
+        assertEquals(test.getNano(), Long.MIN_VALUE % 1000000000 + 1000000000);
+    }
+
+    //-----------------------------------------------------------------------
+    // ofMinutes()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_minutes() {
+        Duration test = Duration.ofMinutes(2);
+        assertEquals(test.getSeconds(), 120);
+        assertEquals(test.getNano(), 0);
+    }
+
+    @Test(groups={"tck"})
+    public void factory_minutes_max() {
+        Duration test = Duration.ofMinutes(Long.MAX_VALUE / 60);
+        assertEquals(test.getSeconds(), (Long.MAX_VALUE / 60) * 60);
+        assertEquals(test.getNano(), 0);
+    }
+
+    @Test(groups={"tck"})
+    public void factory_minutes_min() {
+        Duration test = Duration.ofMinutes(Long.MIN_VALUE / 60);
+        assertEquals(test.getSeconds(), (Long.MIN_VALUE / 60) * 60);
+        assertEquals(test.getNano(), 0);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void factory_minutes_tooBig() {
+        Duration.ofMinutes(Long.MAX_VALUE / 60 + 1);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void factory_minutes_tooSmall() {
+        Duration.ofMinutes(Long.MIN_VALUE / 60 - 1);
+    }
+
+    //-----------------------------------------------------------------------
+    // ofHours()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_hours() {
+        Duration test = Duration.ofHours(2);
+        assertEquals(test.getSeconds(), 2 * 3600);
+        assertEquals(test.getNano(), 0);
+    }
+
+    @Test(groups={"tck"})
+    public void factory_hours_max() {
+        Duration test = Duration.ofHours(Long.MAX_VALUE / 3600);
+        assertEquals(test.getSeconds(), (Long.MAX_VALUE / 3600) * 3600);
+        assertEquals(test.getNano(), 0);
+    }
+
+    @Test(groups={"tck"})
+    public void factory_hours_min() {
+        Duration test = Duration.ofHours(Long.MIN_VALUE / 3600);
+        assertEquals(test.getSeconds(), (Long.MIN_VALUE / 3600) * 3600);
+        assertEquals(test.getNano(), 0);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void factory_hours_tooBig() {
+        Duration.ofHours(Long.MAX_VALUE / 3600 + 1);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void factory_hours_tooSmall() {
+        Duration.ofHours(Long.MIN_VALUE / 3600 - 1);
+    }
+
+    //-----------------------------------------------------------------------
+    // ofDays()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_days() {
+        Duration test = Duration.ofDays(2);
+        assertEquals(test.getSeconds(), 2 * 86400);
+        assertEquals(test.getNano(), 0);
+    }
+
+    @Test(groups={"tck"})
+    public void factory_days_max() {
+        Duration test = Duration.ofDays(Long.MAX_VALUE / 86400);
+        assertEquals(test.getSeconds(), (Long.MAX_VALUE / 86400) * 86400);
+        assertEquals(test.getNano(), 0);
+    }
+
+    @Test(groups={"tck"})
+    public void factory_days_min() {
+        Duration test = Duration.ofDays(Long.MIN_VALUE / 86400);
+        assertEquals(test.getSeconds(), (Long.MIN_VALUE / 86400) * 86400);
+        assertEquals(test.getNano(), 0);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void factory_days_tooBig() {
+        Duration.ofDays(Long.MAX_VALUE / 86400 + 1);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void factory_days_tooSmall() {
+        Duration.ofDays(Long.MIN_VALUE / 86400 - 1);
+    }
+
+    //-----------------------------------------------------------------------
+    // of(long,TemporalUnit)
+    //-----------------------------------------------------------------------
+    @DataProvider(name="OfTemporalUnit")
+    Object[][] provider_factory_of_longTemporalUnit() {
+        return new Object[][] {
+            {0, NANOS, 0, 0},
+            {0, MICROS, 0, 0},
+            {0, MILLIS, 0, 0},
+            {0, SECONDS, 0, 0},
+            {0, MINUTES, 0, 0},
+            {0, HOURS, 0, 0},
+            {0, HALF_DAYS, 0, 0},
+            {0, DAYS, 0, 0},
+            {1, NANOS, 0, 1},
+            {1, MICROS, 0, 1000},
+            {1, MILLIS, 0, 1000000},
+            {1, SECONDS, 1, 0},
+            {1, MINUTES, 60, 0},
+            {1, HOURS, 3600, 0},
+            {1, HALF_DAYS, 43200, 0},
+            {1, DAYS, 86400, 0},
+            {3, NANOS, 0, 3},
+            {3, MICROS, 0, 3000},
+            {3, MILLIS, 0, 3000000},
+            {3, SECONDS, 3, 0},
+            {3, MINUTES, 3 * 60, 0},
+            {3, HOURS, 3 * 3600, 0},
+            {3, HALF_DAYS, 3 * 43200, 0},
+            {3, DAYS, 3 * 86400, 0},
+            {-1, NANOS, -1, 999999999},
+            {-1, MICROS, -1, 999999000},
+            {-1, MILLIS, -1, 999000000},
+            {-1, SECONDS, -1, 0},
+            {-1, MINUTES, -60, 0},
+            {-1, HOURS, -3600, 0},
+            {-1, HALF_DAYS, -43200, 0},
+            {-1, DAYS, -86400, 0},
+            {-3, NANOS, -1, 999999997},
+            {-3, MICROS, -1, 999997000},
+            {-3, MILLIS, -1, 997000000},
+            {-3, SECONDS, -3, 0},
+            {-3, MINUTES, -3 * 60, 0},
+            {-3, HOURS, -3 * 3600, 0},
+            {-3, HALF_DAYS, -3 * 43200, 0},
+            {-3, DAYS, -3 * 86400, 0},
+            {Long.MAX_VALUE, NANOS, Long.MAX_VALUE / 1000000000, (int) (Long.MAX_VALUE % 1000000000)},
+            {Long.MIN_VALUE, NANOS, Long.MIN_VALUE / 1000000000 - 1, (int) (Long.MIN_VALUE % 1000000000 + 1000000000)},
+            {Long.MAX_VALUE, MICROS, Long.MAX_VALUE / 1000000, (int) ((Long.MAX_VALUE % 1000000) * 1000)},
+            {Long.MIN_VALUE, MICROS, Long.MIN_VALUE / 1000000 - 1, (int) ((Long.MIN_VALUE % 1000000 + 1000000) * 1000)},
+            {Long.MAX_VALUE, MILLIS, Long.MAX_VALUE / 1000, (int) ((Long.MAX_VALUE % 1000) * 1000000)},
+            {Long.MIN_VALUE, MILLIS, Long.MIN_VALUE / 1000 - 1, (int) ((Long.MIN_VALUE % 1000 + 1000) * 1000000)},
+            {Long.MAX_VALUE, SECONDS, Long.MAX_VALUE, 0},
+            {Long.MIN_VALUE, SECONDS, Long.MIN_VALUE, 0},
+            {Long.MAX_VALUE / 60, MINUTES, (Long.MAX_VALUE / 60) * 60, 0},
+            {Long.MIN_VALUE / 60, MINUTES, (Long.MIN_VALUE / 60) * 60, 0},
+            {Long.MAX_VALUE / 3600, HOURS, (Long.MAX_VALUE / 3600) * 3600, 0},
+            {Long.MIN_VALUE / 3600, HOURS, (Long.MIN_VALUE / 3600) * 3600, 0},
+            {Long.MAX_VALUE / 43200, HALF_DAYS, (Long.MAX_VALUE / 43200) * 43200, 0},
+            {Long.MIN_VALUE / 43200, HALF_DAYS, (Long.MIN_VALUE / 43200) * 43200, 0},
+        };
+    }
+
+    @Test(dataProvider="OfTemporalUnit", groups={"tck"})
+    public void factory_of_longTemporalUnit(long amount, TemporalUnit unit, long expectedSeconds, int expectedNanoOfSecond) {
+        Duration t = Duration.of(amount, unit);
+        assertEquals(t.getSeconds(), expectedSeconds);
+        assertEquals(t.getNano(), expectedNanoOfSecond);
+    }
+
+    @DataProvider(name="OfTemporalUnitOutOfRange")
+    Object[][] provider_factory_of_longTemporalUnit_outOfRange() {
+        return new Object[][] {
+            {Long.MAX_VALUE / 60 + 1, MINUTES},
+            {Long.MIN_VALUE / 60 - 1, MINUTES},
+            {Long.MAX_VALUE / 3600 + 1, HOURS},
+            {Long.MIN_VALUE / 3600 - 1, HOURS},
+            {Long.MAX_VALUE / 43200 + 1, HALF_DAYS},
+            {Long.MIN_VALUE / 43200 - 1, HALF_DAYS},
+        };
+    }
+
+    @Test(dataProvider="OfTemporalUnitOutOfRange", expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void factory_of_longTemporalUnit_outOfRange(long amount, TemporalUnit unit) {
+        Duration.of(amount, unit);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_longTemporalUnit_estimatedUnit() {
+        Duration.of(2, WEEKS);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_of_longTemporalUnit_null() {
+        Duration.of(1, (TemporalUnit) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // between()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="DurationBetween")
+    Object[][] provider_factory_between_Instant_Instant() {
+        return new Object[][] {
+            {0, 0, 0, 0, 0, 0},
+            {3, 0, 7, 0, 4, 0},
+            {3, 20, 7, 50, 4, 30},
+            {3, 80, 7, 50, 3, 999999970},
+            {7, 0, 3, 0, -4, 0},
+        };
+    }
+
+    @Test(dataProvider="DurationBetween", groups={"tck"})
+    public void factory_between_Instant_Instant(long secs1, int nanos1, long secs2, int nanos2, long expectedSeconds, int expectedNanoOfSecond) {
+        Instant start = Instant.ofEpochSecond(secs1, nanos1);
+        Instant end = Instant.ofEpochSecond(secs2, nanos2);
+        Duration t = Duration.between(start, end);
+        assertEquals(t.getSeconds(), expectedSeconds);
+        assertEquals(t.getNano(), expectedNanoOfSecond);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_between_Instant_Instant_startNull() {
+        Instant end = Instant.ofEpochSecond(1);
+        Duration.between(null, end);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_between_Instant_Instant_endNull() {
+        Instant start = Instant.ofEpochSecond(1);
+        Duration.between(start, null);
+    }
+
+    //-----------------------------------------------------------------------
+    // parse(String)
+    //-----------------------------------------------------------------------
+    @DataProvider(name="Parse")
+    Object[][] provider_factory_parse() {
+        return new Object[][] {
+            {"PT0S", 0, 0},
+            {"pT0S", 0, 0},
+            {"Pt0S", 0, 0},
+            {"PT0s", 0, 0},
+
+            {"PT1S", 1, 0},
+            {"PT12S", 12, 0},
+            {"PT123456789S", 123456789, 0},
+            {"PT" + Long.MAX_VALUE + "S", Long.MAX_VALUE, 0},
+
+            {"PT-1S", -1, 0},
+            {"PT-12S", -12, 0},
+            {"PT-123456789S", -123456789, 0},
+            {"PT" + Long.MIN_VALUE + "S", Long.MIN_VALUE, 0},
+
+            {"PT1.1S", 1, 100000000},
+            {"PT1.12S", 1, 120000000},
+            {"PT1.123S", 1, 123000000},
+            {"PT1.1234S", 1, 123400000},
+            {"PT1.12345S", 1, 123450000},
+            {"PT1.123456S", 1, 123456000},
+            {"PT1.1234567S", 1, 123456700},
+            {"PT1.12345678S", 1, 123456780},
+            {"PT1.123456789S", 1, 123456789},
+
+            {"PT-1.1S", -2, 1000000000 - 100000000},
+            {"PT-1.12S", -2, 1000000000 - 120000000},
+            {"PT-1.123S", -2, 1000000000 - 123000000},
+            {"PT-1.1234S", -2, 1000000000 - 123400000},
+            {"PT-1.12345S", -2, 1000000000 - 123450000},
+            {"PT-1.123456S", -2, 1000000000 - 123456000},
+            {"PT-1.1234567S", -2, 1000000000 - 123456700},
+            {"PT-1.12345678S", -2, 1000000000 - 123456780},
+            {"PT-1.123456789S", -2, 1000000000 - 123456789},
+
+            {"PT" + Long.MAX_VALUE + ".123456789S", Long.MAX_VALUE, 123456789},
+            {"PT" + Long.MIN_VALUE + ".000000000S", Long.MIN_VALUE, 0},
+        };
+    }
+
+    @Test(dataProvider="Parse", groups={"tck"})
+    public void factory_parse(String text, long expectedSeconds, int expectedNanoOfSecond) {
+        Duration t = Duration.parse(text);
+        assertEquals(t.getSeconds(), expectedSeconds);
+        assertEquals(t.getNano(), expectedNanoOfSecond);
+    }
+
+    @Test(dataProvider="Parse", groups={"tck"})
+    public void factory_parse_comma(String text, long expectedSeconds, int expectedNanoOfSecond) {
+        text = text.replace('.', ',');
+        Duration t = Duration.parse(text);
+        assertEquals(t.getSeconds(), expectedSeconds);
+        assertEquals(t.getNano(), expectedNanoOfSecond);
+    }
+
+    @DataProvider(name="ParseFailures")
+    Object[][] provider_factory_parseFailures() {
+        return new Object[][] {
+            {""},
+            {"PTS"},
+            {"AT0S"},
+            {"PA0S"},
+            {"PT0A"},
+
+            {"PT+S"},
+            {"PT-S"},
+            {"PT.S"},
+            {"PTAS"},
+
+            {"PT+0S"},
+            {"PT+00S"},
+            {"PT+000S"},
+            {"PT-0S"},
+            {"PT-00S"},
+            {"PT-000S"},
+            {"PT+1S"},
+            {"PT-.S"},
+            {"PT+.S"},
+
+            {"PT1ABC2S"},
+            {"PT1.1ABC2S"},
+
+            {"PT123456789123456789123456789S"},
+            {"PT0.1234567891S"},
+            {"PT1.S"},
+            {"PT.1S"},
+
+            {"PT2.-3"},
+            {"PT-2.-3"},
+            {"PT2.+3"},
+            {"PT-2.+3"},
+        };
+    }
+
+    @Test(dataProvider="ParseFailures", expectedExceptions=DateTimeParseException.class, groups={"tck"})
+    public void factory_parseFailures(String text) {
+        Duration.parse(text);
+    }
+
+    @Test(dataProvider="ParseFailures", expectedExceptions=DateTimeParseException.class, groups={"tck"})
+    public void factory_parseFailures_comma(String text) {
+        text = text.replace('.', ',');
+        Duration.parse(text);
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"})
+    public void factory_parse_tooBig() {
+        Duration.parse("PT" + Long.MAX_VALUE + "1S");
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"})
+    public void factory_parse_tooBig_decimal() {
+        Duration.parse("PT" + Long.MAX_VALUE + "1.1S");
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"})
+    public void factory_parse_tooSmall() {
+        Duration.parse("PT" + Long.MIN_VALUE + "1S");
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"})
+    public void factory_parse_tooSmall_decimal() {
+        Duration.parse("PT" + Long.MIN_VALUE + ".1S");
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_parse_nullText() {
+        Duration.parse((String) null);
+    }
+
+    @Test(groups={"tck"})
+    public void test_deserialization() throws Exception {
+        Duration orginal = Duration.ofSeconds(2);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream(baos);
+        out.writeObject(orginal);
+        out.close();
+        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+        ObjectInputStream in = new ObjectInputStream(bais);
+        Duration ser = (Duration) in.readObject();
+        assertEquals(Duration.ofSeconds(2), ser);
+    }
+
+    //-----------------------------------------------------------------------
+    // isZero(), isPositive(), isPositiveOrZero(), isNegative(), isNegativeOrZero()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_isZero() {
+        assertEquals(Duration.ofNanos(0).isZero(), true);
+        assertEquals(Duration.ofSeconds(0).isZero(), true);
+        assertEquals(Duration.ofNanos(1).isZero(), false);
+        assertEquals(Duration.ofSeconds(1).isZero(), false);
+        assertEquals(Duration.ofSeconds(1, 1).isZero(), false);
+        assertEquals(Duration.ofNanos(-1).isZero(), false);
+        assertEquals(Duration.ofSeconds(-1).isZero(), false);
+        assertEquals(Duration.ofSeconds(-1, -1).isZero(), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_isPositive() {
+        assertEquals(Duration.ofNanos(0).isPositive(), false);
+        assertEquals(Duration.ofSeconds(0).isPositive(), false);
+        assertEquals(Duration.ofNanos(1).isPositive(), true);
+        assertEquals(Duration.ofSeconds(1).isPositive(), true);
+        assertEquals(Duration.ofSeconds(1, 1).isPositive(), true);
+        assertEquals(Duration.ofNanos(-1).isPositive(), false);
+        assertEquals(Duration.ofSeconds(-1).isPositive(), false);
+        assertEquals(Duration.ofSeconds(-1, -1).isPositive(), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_isNegative() {
+        assertEquals(Duration.ofNanos(0).isNegative(), false);
+        assertEquals(Duration.ofSeconds(0).isNegative(), false);
+        assertEquals(Duration.ofNanos(1).isNegative(), false);
+        assertEquals(Duration.ofSeconds(1).isNegative(), false);
+        assertEquals(Duration.ofSeconds(1, 1).isNegative(), false);
+        assertEquals(Duration.ofNanos(-1).isNegative(), true);
+        assertEquals(Duration.ofSeconds(-1).isNegative(), true);
+        assertEquals(Duration.ofSeconds(-1, -1).isNegative(), true);
+    }
+
+    //-----------------------------------------------------------------------
+    // plus()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="Plus")
+    Object[][] provider_plus() {
+        return new Object[][] {
+            {Long.MIN_VALUE, 0, Long.MAX_VALUE, 0, -1, 0},
+
+            {-4, 666666667, -4, 666666667, -7, 333333334},
+            {-4, 666666667, -3,         0, -7, 666666667},
+            {-4, 666666667, -2,         0, -6, 666666667},
+            {-4, 666666667, -1,         0, -5, 666666667},
+            {-4, 666666667, -1, 333333334, -4,         1},
+            {-4, 666666667, -1, 666666667, -4, 333333334},
+            {-4, 666666667, -1, 999999999, -4, 666666666},
+            {-4, 666666667,  0,         0, -4, 666666667},
+            {-4, 666666667,  0,         1, -4, 666666668},
+            {-4, 666666667,  0, 333333333, -3,         0},
+            {-4, 666666667,  0, 666666666, -3, 333333333},
+            {-4, 666666667,  1,         0, -3, 666666667},
+            {-4, 666666667,  2,         0, -2, 666666667},
+            {-4, 666666667,  3,         0, -1, 666666667},
+            {-4, 666666667,  3, 333333333,  0,         0},
+
+            {-3, 0, -4, 666666667, -7, 666666667},
+            {-3, 0, -3,         0, -6,         0},
+            {-3, 0, -2,         0, -5,         0},
+            {-3, 0, -1,         0, -4,         0},
+            {-3, 0, -1, 333333334, -4, 333333334},
+            {-3, 0, -1, 666666667, -4, 666666667},
+            {-3, 0, -1, 999999999, -4, 999999999},
+            {-3, 0,  0,         0, -3,         0},
+            {-3, 0,  0,         1, -3,         1},
+            {-3, 0,  0, 333333333, -3, 333333333},
+            {-3, 0,  0, 666666666, -3, 666666666},
+            {-3, 0,  1,         0, -2,         0},
+            {-3, 0,  2,         0, -1,         0},
+            {-3, 0,  3,         0,  0,         0},
+            {-3, 0,  3, 333333333,  0, 333333333},
+
+            {-2, 0, -4, 666666667, -6, 666666667},
+            {-2, 0, -3,         0, -5,         0},
+            {-2, 0, -2,         0, -4,         0},
+            {-2, 0, -1,         0, -3,         0},
+            {-2, 0, -1, 333333334, -3, 333333334},
+            {-2, 0, -1, 666666667, -3, 666666667},
+            {-2, 0, -1, 999999999, -3, 999999999},
+            {-2, 0,  0,         0, -2,         0},
+            {-2, 0,  0,         1, -2,         1},
+            {-2, 0,  0, 333333333, -2, 333333333},
+            {-2, 0,  0, 666666666, -2, 666666666},
+            {-2, 0,  1,         0, -1,         0},
+            {-2, 0,  2,         0,  0,         0},
+            {-2, 0,  3,         0,  1,         0},
+            {-2, 0,  3, 333333333,  1, 333333333},
+
+            {-1, 0, -4, 666666667, -5, 666666667},
+            {-1, 0, -3,         0, -4,         0},
+            {-1, 0, -2,         0, -3,         0},
+            {-1, 0, -1,         0, -2,         0},
+            {-1, 0, -1, 333333334, -2, 333333334},
+            {-1, 0, -1, 666666667, -2, 666666667},
+            {-1, 0, -1, 999999999, -2, 999999999},
+            {-1, 0,  0,         0, -1,         0},
+            {-1, 0,  0,         1, -1,         1},
+            {-1, 0,  0, 333333333, -1, 333333333},
+            {-1, 0,  0, 666666666, -1, 666666666},
+            {-1, 0,  1,         0,  0,         0},
+            {-1, 0,  2,         0,  1,         0},
+            {-1, 0,  3,         0,  2,         0},
+            {-1, 0,  3, 333333333,  2, 333333333},
+
+            {-1, 666666667, -4, 666666667, -4, 333333334},
+            {-1, 666666667, -3,         0, -4, 666666667},
+            {-1, 666666667, -2,         0, -3, 666666667},
+            {-1, 666666667, -1,         0, -2, 666666667},
+            {-1, 666666667, -1, 333333334, -1,         1},
+            {-1, 666666667, -1, 666666667, -1, 333333334},
+            {-1, 666666667, -1, 999999999, -1, 666666666},
+            {-1, 666666667,  0,         0, -1, 666666667},
+            {-1, 666666667,  0,         1, -1, 666666668},
+            {-1, 666666667,  0, 333333333,  0,         0},
+            {-1, 666666667,  0, 666666666,  0, 333333333},
+            {-1, 666666667,  1,         0,  0, 666666667},
+            {-1, 666666667,  2,         0,  1, 666666667},
+            {-1, 666666667,  3,         0,  2, 666666667},
+            {-1, 666666667,  3, 333333333,  3,         0},
+
+            {0, 0, -4, 666666667, -4, 666666667},
+            {0, 0, -3,         0, -3,         0},
+            {0, 0, -2,         0, -2,         0},
+            {0, 0, -1,         0, -1,         0},
+            {0, 0, -1, 333333334, -1, 333333334},
+            {0, 0, -1, 666666667, -1, 666666667},
+            {0, 0, -1, 999999999, -1, 999999999},
+            {0, 0,  0,         0,  0,         0},
+            {0, 0,  0,         1,  0,         1},
+            {0, 0,  0, 333333333,  0, 333333333},
+            {0, 0,  0, 666666666,  0, 666666666},
+            {0, 0,  1,         0,  1,         0},
+            {0, 0,  2,         0,  2,         0},
+            {0, 0,  3,         0,  3,         0},
+            {0, 0,  3, 333333333,  3, 333333333},
+
+            {0, 333333333, -4, 666666667, -3,         0},
+            {0, 333333333, -3,         0, -3, 333333333},
+            {0, 333333333, -2,         0, -2, 333333333},
+            {0, 333333333, -1,         0, -1, 333333333},
+            {0, 333333333, -1, 333333334, -1, 666666667},
+            {0, 333333333, -1, 666666667,  0,         0},
+            {0, 333333333, -1, 999999999,  0, 333333332},
+            {0, 333333333,  0,         0,  0, 333333333},
+            {0, 333333333,  0,         1,  0, 333333334},
+            {0, 333333333,  0, 333333333,  0, 666666666},
+            {0, 333333333,  0, 666666666,  0, 999999999},
+            {0, 333333333,  1,         0,  1, 333333333},
+            {0, 333333333,  2,         0,  2, 333333333},
+            {0, 333333333,  3,         0,  3, 333333333},
+            {0, 333333333,  3, 333333333,  3, 666666666},
+
+            {1, 0, -4, 666666667, -3, 666666667},
+            {1, 0, -3,         0, -2,         0},
+            {1, 0, -2,         0, -1,         0},
+            {1, 0, -1,         0,  0,         0},
+            {1, 0, -1, 333333334,  0, 333333334},
+            {1, 0, -1, 666666667,  0, 666666667},
+            {1, 0, -1, 999999999,  0, 999999999},
+            {1, 0,  0,         0,  1,         0},
+            {1, 0,  0,         1,  1,         1},
+            {1, 0,  0, 333333333,  1, 333333333},
+            {1, 0,  0, 666666666,  1, 666666666},
+            {1, 0,  1,         0,  2,         0},
+            {1, 0,  2,         0,  3,         0},
+            {1, 0,  3,         0,  4,         0},
+            {1, 0,  3, 333333333,  4, 333333333},
+
+            {2, 0, -4, 666666667, -2, 666666667},
+            {2, 0, -3,         0, -1,         0},
+            {2, 0, -2,         0,  0,         0},
+            {2, 0, -1,         0,  1,         0},
+            {2, 0, -1, 333333334,  1, 333333334},
+            {2, 0, -1, 666666667,  1, 666666667},
+            {2, 0, -1, 999999999,  1, 999999999},
+            {2, 0,  0,         0,  2,         0},
+            {2, 0,  0,         1,  2,         1},
+            {2, 0,  0, 333333333,  2, 333333333},
+            {2, 0,  0, 666666666,  2, 666666666},
+            {2, 0,  1,         0,  3,         0},
+            {2, 0,  2,         0,  4,         0},
+            {2, 0,  3,         0,  5,         0},
+            {2, 0,  3, 333333333,  5, 333333333},
+
+            {3, 0, -4, 666666667, -1, 666666667},
+            {3, 0, -3,         0,  0,         0},
+            {3, 0, -2,         0,  1,         0},
+            {3, 0, -1,         0,  2,         0},
+            {3, 0, -1, 333333334,  2, 333333334},
+            {3, 0, -1, 666666667,  2, 666666667},
+            {3, 0, -1, 999999999,  2, 999999999},
+            {3, 0,  0,         0,  3,         0},
+            {3, 0,  0,         1,  3,         1},
+            {3, 0,  0, 333333333,  3, 333333333},
+            {3, 0,  0, 666666666,  3, 666666666},
+            {3, 0,  1,         0,  4,         0},
+            {3, 0,  2,         0,  5,         0},
+            {3, 0,  3,         0,  6,         0},
+            {3, 0,  3, 333333333,  6, 333333333},
+
+            {3, 333333333, -4, 666666667,  0,         0},
+            {3, 333333333, -3,         0,  0, 333333333},
+            {3, 333333333, -2,         0,  1, 333333333},
+            {3, 333333333, -1,         0,  2, 333333333},
+            {3, 333333333, -1, 333333334,  2, 666666667},
+            {3, 333333333, -1, 666666667,  3,         0},
+            {3, 333333333, -1, 999999999,  3, 333333332},
+            {3, 333333333,  0,         0,  3, 333333333},
+            {3, 333333333,  0,         1,  3, 333333334},
+            {3, 333333333,  0, 333333333,  3, 666666666},
+            {3, 333333333,  0, 666666666,  3, 999999999},
+            {3, 333333333,  1,         0,  4, 333333333},
+            {3, 333333333,  2,         0,  5, 333333333},
+            {3, 333333333,  3,         0,  6, 333333333},
+            {3, 333333333,  3, 333333333,  6, 666666666},
+
+            {Long.MAX_VALUE, 0, Long.MIN_VALUE, 0, -1, 0},
+       };
+    }
+
+    @Test(dataProvider="Plus", groups={"tck"})
+    public void plus(long seconds, int nanos, long otherSeconds, int otherNanos, long expectedSeconds, int expectedNanoOfSecond) {
+       Duration t = Duration.ofSeconds(seconds, nanos).plus(Duration.ofSeconds(otherSeconds, otherNanos));
+       assertEquals(t.getSeconds(), expectedSeconds);
+       assertEquals(t.getNano(), expectedNanoOfSecond);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void plusOverflowTooBig() {
+       Duration t = Duration.ofSeconds(Long.MAX_VALUE, 999999999);
+       t.plus(Duration.ofSeconds(0, 1));
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void plusOverflowTooSmall() {
+       Duration t = Duration.ofSeconds(Long.MIN_VALUE);
+       t.plus(Duration.ofSeconds(-1, 999999999));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void plus_longTemporalUnit_seconds() {
+        Duration t = Duration.ofSeconds(1);
+        t = t.plus(1, SECONDS);
+        assertEquals(2, t.getSeconds());
+        assertEquals(0, t.getNano());
+     }
+
+    @Test(groups={"tck"})
+    public void plus_longTemporalUnit_millis() {
+        Duration t = Duration.ofSeconds(1);
+        t = t.plus(1, MILLIS);
+        assertEquals(1, t.getSeconds());
+        assertEquals(1000000, t.getNano());
+     }
+
+    @Test(groups={"tck"})
+    public void plus_longTemporalUnit_micros() {
+        Duration t = Duration.ofSeconds(1);
+        t = t.plus(1, MICROS);
+        assertEquals(1, t.getSeconds());
+        assertEquals(1000, t.getNano());
+     }
+
+    @Test(groups={"tck"})
+    public void plus_longTemporalUnit_nanos() {
+        Duration t = Duration.ofSeconds(1);
+        t = t.plus(1, NANOS);
+        assertEquals(1, t.getSeconds());
+        assertEquals(1, t.getNano());
+     }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void plus_longTemporalUnit_null() {
+       Duration t = Duration.ofSeconds(1);
+       t.plus(1, (TemporalUnit) null);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="PlusSeconds")
+    Object[][] provider_plusSeconds_long() {
+        return new Object[][] {
+            {0, 0, 0, 0, 0},
+            {0, 0, 1, 1, 0},
+            {0, 0, -1, -1, 0},
+            {0, 0, Long.MAX_VALUE, Long.MAX_VALUE, 0},
+            {0, 0, Long.MIN_VALUE, Long.MIN_VALUE, 0},
+            {1, 0, 0, 1, 0},
+            {1, 0, 1, 2, 0},
+            {1, 0, -1, 0, 0},
+            {1, 0, Long.MAX_VALUE - 1, Long.MAX_VALUE, 0},
+            {1, 0, Long.MIN_VALUE, Long.MIN_VALUE + 1, 0},
+            {1, 1, 0, 1, 1},
+            {1, 1, 1, 2, 1},
+            {1, 1, -1, 0, 1},
+            {1, 1, Long.MAX_VALUE - 1, Long.MAX_VALUE, 1},
+            {1, 1, Long.MIN_VALUE, Long.MIN_VALUE + 1, 1},
+            {-1, 1, 0, -1, 1},
+            {-1, 1, 1, 0, 1},
+            {-1, 1, -1, -2, 1},
+            {-1, 1, Long.MAX_VALUE, Long.MAX_VALUE - 1, 1},
+            {-1, 1, Long.MIN_VALUE + 1, Long.MIN_VALUE, 1},
+        };
+    }
+
+    @Test(dataProvider="PlusSeconds", groups={"tck"})
+    public void plusSeconds_long(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) {
+        Duration t = Duration.ofSeconds(seconds, nanos);
+        t = t.plusSeconds(amount);
+        assertEquals(t.getSeconds(), expectedSeconds);
+        assertEquals(t.getNano(), expectedNanoOfSecond);
+    }
+
+    @Test(expectedExceptions = {ArithmeticException.class}, groups={"tck"})
+    public void plusSeconds_long_overflowTooBig() {
+        Duration t = Duration.ofSeconds(1, 0);
+        t.plusSeconds(Long.MAX_VALUE);
+    }
+
+    @Test(expectedExceptions = {ArithmeticException.class}, groups={"tck"})
+    public void plusSeconds_long_overflowTooSmall() {
+        Duration t = Duration.ofSeconds(-1, 0);
+        t.plusSeconds(Long.MIN_VALUE);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="PlusMillis")
+    Object[][] provider_plusMillis_long() {
+        return new Object[][] {
+            {0, 0, 0,       0, 0},
+            {0, 0, 1,       0, 1000000},
+            {0, 0, 999,     0, 999000000},
+            {0, 0, 1000,    1, 0},
+            {0, 0, 1001,    1, 1000000},
+            {0, 0, 1999,    1, 999000000},
+            {0, 0, 2000,    2, 0},
+            {0, 0, -1,      -1, 999000000},
+            {0, 0, -999,    -1, 1000000},
+            {0, 0, -1000,   -1, 0},
+            {0, 0, -1001,   -2, 999000000},
+            {0, 0, -1999,   -2, 1000000},
+
+            {0, 1, 0,       0, 1},
+            {0, 1, 1,       0, 1000001},
+            {0, 1, 998,     0, 998000001},
+            {0, 1, 999,     0, 999000001},
+            {0, 1, 1000,    1, 1},
+            {0, 1, 1998,    1, 998000001},
+            {0, 1, 1999,    1, 999000001},
+            {0, 1, 2000,    2, 1},
+            {0, 1, -1,      -1, 999000001},
+            {0, 1, -2,      -1, 998000001},
+            {0, 1, -1000,   -1, 1},
+            {0, 1, -1001,   -2, 999000001},
+
+            {0, 1000000, 0,       0, 1000000},
+            {0, 1000000, 1,       0, 2000000},
+            {0, 1000000, 998,     0, 999000000},
+            {0, 1000000, 999,     1, 0},
+            {0, 1000000, 1000,    1, 1000000},
+            {0, 1000000, 1998,    1, 999000000},
+            {0, 1000000, 1999,    2, 0},
+            {0, 1000000, 2000,    2, 1000000},
+            {0, 1000000, -1,      0, 0},
+            {0, 1000000, -2,      -1, 999000000},
+            {0, 1000000, -999,    -1, 2000000},
+            {0, 1000000, -1000,   -1, 1000000},
+            {0, 1000000, -1001,   -1, 0},
+            {0, 1000000, -1002,   -2, 999000000},
+
+            {0, 999999999, 0,     0, 999999999},
+            {0, 999999999, 1,     1, 999999},
+            {0, 999999999, 999,   1, 998999999},
+            {0, 999999999, 1000,  1, 999999999},
+            {0, 999999999, 1001,  2, 999999},
+            {0, 999999999, -1,    0, 998999999},
+            {0, 999999999, -1000, -1, 999999999},
+            {0, 999999999, -1001, -1, 998999999},
+        };
+    }
+
+    @Test(dataProvider="PlusMillis", groups={"tck"})
+    public void plusMillis_long(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) {
+        Duration t = Duration.ofSeconds(seconds, nanos);
+        t = t.plusMillis(amount);
+        assertEquals(t.getSeconds(), expectedSeconds);
+        assertEquals(t.getNano(), expectedNanoOfSecond);
+    }
+    @Test(dataProvider="PlusMillis", groups={"tck"})
+    public void plusMillis_long_oneMore(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) {
+        Duration t = Duration.ofSeconds(seconds + 1, nanos);
+        t = t.plusMillis(amount);
+        assertEquals(t.getSeconds(), expectedSeconds + 1);
+        assertEquals(t.getNano(), expectedNanoOfSecond);
+    }
+    @Test(dataProvider="PlusMillis", groups={"tck"})
+    public void plusMillis_long_minusOneLess(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) {
+        Duration t = Duration.ofSeconds(seconds - 1, nanos);
+        t = t.plusMillis(amount);
+        assertEquals(t.getSeconds(), expectedSeconds - 1);
+        assertEquals(t.getNano(), expectedNanoOfSecond);
+    }
+
+    @Test(groups={"tck"})
+    public void plusMillis_long_max() {
+        Duration t = Duration.ofSeconds(Long.MAX_VALUE, 998999999);
+        t = t.plusMillis(1);
+        assertEquals(t.getSeconds(), Long.MAX_VALUE);
+        assertEquals(t.getNano(), 999999999);
+    }
+
+    @Test(expectedExceptions = {ArithmeticException.class}, groups={"tck"})
+    public void plusMillis_long_overflowTooBig() {
+        Duration t = Duration.ofSeconds(Long.MAX_VALUE, 999000000);
+        t.plusMillis(1);
+    }
+
+    @Test(groups={"tck"})
+    public void plusMillis_long_min() {
+        Duration t = Duration.ofSeconds(Long.MIN_VALUE, 1000000);
+        t = t.plusMillis(-1);
+        assertEquals(t.getSeconds(), Long.MIN_VALUE);
+        assertEquals(t.getNano(), 0);
+    }
+
+    @Test(expectedExceptions = {ArithmeticException.class}, groups={"tck"})
+    public void plusMillis_long_overflowTooSmall() {
+        Duration t = Duration.ofSeconds(Long.MIN_VALUE, 0);
+        t.plusMillis(-1);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="PlusNanos")
+    Object[][] provider_plusNanos_long() {
+        return new Object[][] {
+            {0, 0, 0,           0, 0},
+            {0, 0, 1,           0, 1},
+            {0, 0, 999999999,   0, 999999999},
+            {0, 0, 1000000000,  1, 0},
+            {0, 0, 1000000001,  1, 1},
+            {0, 0, 1999999999,  1, 999999999},
+            {0, 0, 2000000000,  2, 0},
+            {0, 0, -1,          -1, 999999999},
+            {0, 0, -999999999,  -1, 1},
+            {0, 0, -1000000000, -1, 0},
+            {0, 0, -1000000001, -2, 999999999},
+            {0, 0, -1999999999, -2, 1},
+
+            {1, 0, 0,           1, 0},
+            {1, 0, 1,           1, 1},
+            {1, 0, 999999999,   1, 999999999},
+            {1, 0, 1000000000,  2, 0},
+            {1, 0, 1000000001,  2, 1},
+            {1, 0, 1999999999,  2, 999999999},
+            {1, 0, 2000000000,  3, 0},
+            {1, 0, -1,          0, 999999999},
+            {1, 0, -999999999,  0, 1},
+            {1, 0, -1000000000, 0, 0},
+            {1, 0, -1000000001, -1, 999999999},
+            {1, 0, -1999999999, -1, 1},
+
+            {-1, 0, 0,           -1, 0},
+            {-1, 0, 1,           -1, 1},
+            {-1, 0, 999999999,   -1, 999999999},
+            {-1, 0, 1000000000,  0, 0},
+            {-1, 0, 1000000001,  0, 1},
+            {-1, 0, 1999999999,  0, 999999999},
+            {-1, 0, 2000000000,  1, 0},
+            {-1, 0, -1,          -2, 999999999},
+            {-1, 0, -999999999,  -2, 1},
+            {-1, 0, -1000000000, -2, 0},
+            {-1, 0, -1000000001, -3, 999999999},
+            {-1, 0, -1999999999, -3, 1},
+
+            {1, 1, 0,           1, 1},
+            {1, 1, 1,           1, 2},
+            {1, 1, 999999998,   1, 999999999},
+            {1, 1, 999999999,   2, 0},
+            {1, 1, 1000000000,  2, 1},
+            {1, 1, 1999999998,  2, 999999999},
+            {1, 1, 1999999999,  3, 0},
+            {1, 1, 2000000000,  3, 1},
+            {1, 1, -1,          1, 0},
+            {1, 1, -2,          0, 999999999},
+            {1, 1, -1000000000, 0, 1},
+            {1, 1, -1000000001, 0, 0},
+            {1, 1, -1000000002, -1, 999999999},
+            {1, 1, -2000000000, -1, 1},
+
+            {1, 999999999, 0,           1, 999999999},
+            {1, 999999999, 1,           2, 0},
+            {1, 999999999, 999999999,   2, 999999998},
+            {1, 999999999, 1000000000,  2, 999999999},
+            {1, 999999999, 1000000001,  3, 0},
+            {1, 999999999, -1,          1, 999999998},
+            {1, 999999999, -1000000000, 0, 999999999},
+            {1, 999999999, -1000000001, 0, 999999998},
+            {1, 999999999, -1999999999, 0, 0},
+            {1, 999999999, -2000000000, -1, 999999999},
+
+            {Long.MAX_VALUE, 0, 999999999, Long.MAX_VALUE, 999999999},
+            {Long.MAX_VALUE - 1, 0, 1999999999, Long.MAX_VALUE, 999999999},
+            {Long.MIN_VALUE, 1, -1, Long.MIN_VALUE, 0},
+            {Long.MIN_VALUE + 1, 1, -1000000001, Long.MIN_VALUE, 0},
+        };
+    }
+
+    @Test(dataProvider="PlusNanos", groups={"tck"})
+    public void plusNanos_long(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) {
+        Duration t = Duration.ofSeconds(seconds, nanos);
+        t = t.plusNanos(amount);
+        assertEquals(t.getSeconds(), expectedSeconds);
+        assertEquals(t.getNano(), expectedNanoOfSecond);
+    }
+
+    @Test(expectedExceptions = {ArithmeticException.class}, groups={"tck"})
+    public void plusNanos_long_overflowTooBig() {
+        Duration t = Duration.ofSeconds(Long.MAX_VALUE, 999999999);
+        t.plusNanos(1);
+    }
+
+    @Test(expectedExceptions = {ArithmeticException.class}, groups={"tck"})
+    public void plusNanos_long_overflowTooSmall() {
+        Duration t = Duration.ofSeconds(Long.MIN_VALUE, 0);
+        t.plusNanos(-1);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="Minus")
+    Object[][] provider_minus() {
+        return new Object[][] {
+            {Long.MIN_VALUE, 0, Long.MIN_VALUE + 1, 0, -1, 0},
+
+            {-4, 666666667, -4, 666666667,  0,         0},
+            {-4, 666666667, -3,         0, -1, 666666667},
+            {-4, 666666667, -2,         0, -2, 666666667},
+            {-4, 666666667, -1,         0, -3, 666666667},
+            {-4, 666666667, -1, 333333334, -3, 333333333},
+            {-4, 666666667, -1, 666666667, -3,         0},
+            {-4, 666666667, -1, 999999999, -4, 666666668},
+            {-4, 666666667,  0,         0, -4, 666666667},
+            {-4, 666666667,  0,         1, -4, 666666666},
+            {-4, 666666667,  0, 333333333, -4, 333333334},
+            {-4, 666666667,  0, 666666666, -4,         1},
+            {-4, 666666667,  1,         0, -5, 666666667},
+            {-4, 666666667,  2,         0, -6, 666666667},
+            {-4, 666666667,  3,         0, -7, 666666667},
+            {-4, 666666667,  3, 333333333, -7, 333333334},
+
+            {-3, 0, -4, 666666667,  0, 333333333},
+            {-3, 0, -3,         0,  0,         0},
+            {-3, 0, -2,         0, -1,         0},
+            {-3, 0, -1,         0, -2,         0},
+            {-3, 0, -1, 333333334, -3, 666666666},
+            {-3, 0, -1, 666666667, -3, 333333333},
+            {-3, 0, -1, 999999999, -3,         1},
+            {-3, 0,  0,         0, -3,         0},
+            {-3, 0,  0,         1, -4, 999999999},
+            {-3, 0,  0, 333333333, -4, 666666667},
+            {-3, 0,  0, 666666666, -4, 333333334},
+            {-3, 0,  1,         0, -4,         0},
+            {-3, 0,  2,         0, -5,         0},
+            {-3, 0,  3,         0, -6,         0},
+            {-3, 0,  3, 333333333, -7, 666666667},
+
+            {-2, 0, -4, 666666667,  1, 333333333},
+            {-2, 0, -3,         0,  1,         0},
+            {-2, 0, -2,         0,  0,         0},
+            {-2, 0, -1,         0, -1,         0},
+            {-2, 0, -1, 333333334, -2, 666666666},
+            {-2, 0, -1, 666666667, -2, 333333333},
+            {-2, 0, -1, 999999999, -2,         1},
+            {-2, 0,  0,         0, -2,         0},
+            {-2, 0,  0,         1, -3, 999999999},
+            {-2, 0,  0, 333333333, -3, 666666667},
+            {-2, 0,  0, 666666666, -3, 333333334},
+            {-2, 0,  1,         0, -3,         0},
+            {-2, 0,  2,         0, -4,         0},
+            {-2, 0,  3,         0, -5,         0},
+            {-2, 0,  3, 333333333, -6, 666666667},
+
+            {-1, 0, -4, 666666667,  2, 333333333},
+            {-1, 0, -3,         0,  2,         0},
+            {-1, 0, -2,         0,  1,         0},
+            {-1, 0, -1,         0,  0,         0},
+            {-1, 0, -1, 333333334, -1, 666666666},
+            {-1, 0, -1, 666666667, -1, 333333333},
+            {-1, 0, -1, 999999999, -1,         1},
+            {-1, 0,  0,         0, -1,         0},
+            {-1, 0,  0,         1, -2, 999999999},
+            {-1, 0,  0, 333333333, -2, 666666667},
+            {-1, 0,  0, 666666666, -2, 333333334},
+            {-1, 0,  1,         0, -2,         0},
+            {-1, 0,  2,         0, -3,         0},
+            {-1, 0,  3,         0, -4,         0},
+            {-1, 0,  3, 333333333, -5, 666666667},
+
+            {-1, 666666667, -4, 666666667,  3,         0},
+            {-1, 666666667, -3,         0,  2, 666666667},
+            {-1, 666666667, -2,         0,  1, 666666667},
+            {-1, 666666667, -1,         0,  0, 666666667},
+            {-1, 666666667, -1, 333333334,  0, 333333333},
+            {-1, 666666667, -1, 666666667,  0,         0},
+            {-1, 666666667, -1, 999999999, -1, 666666668},
+            {-1, 666666667,  0,         0, -1, 666666667},
+            {-1, 666666667,  0,         1, -1, 666666666},
+            {-1, 666666667,  0, 333333333, -1, 333333334},
+            {-1, 666666667,  0, 666666666, -1,         1},
+            {-1, 666666667,  1,         0, -2, 666666667},
+            {-1, 666666667,  2,         0, -3, 666666667},
+            {-1, 666666667,  3,         0, -4, 666666667},
+            {-1, 666666667,  3, 333333333, -4, 333333334},
+
+            {0, 0, -4, 666666667,  3, 333333333},
+            {0, 0, -3,         0,  3,         0},
+            {0, 0, -2,         0,  2,         0},
+            {0, 0, -1,         0,  1,         0},
+            {0, 0, -1, 333333334,  0, 666666666},
+            {0, 0, -1, 666666667,  0, 333333333},
+            {0, 0, -1, 999999999,  0,         1},
+            {0, 0,  0,         0,  0,         0},
+            {0, 0,  0,         1, -1, 999999999},
+            {0, 0,  0, 333333333, -1, 666666667},
+            {0, 0,  0, 666666666, -1, 333333334},
+            {0, 0,  1,         0, -1,         0},
+            {0, 0,  2,         0, -2,         0},
+            {0, 0,  3,         0, -3,         0},
+            {0, 0,  3, 333333333, -4, 666666667},
+
+            {0, 333333333, -4, 666666667,  3, 666666666},
+            {0, 333333333, -3,         0,  3, 333333333},
+            {0, 333333333, -2,         0,  2, 333333333},
+            {0, 333333333, -1,         0,  1, 333333333},
+            {0, 333333333, -1, 333333334,  0, 999999999},
+            {0, 333333333, -1, 666666667,  0, 666666666},
+            {0, 333333333, -1, 999999999,  0, 333333334},
+            {0, 333333333,  0,         0,  0, 333333333},
+            {0, 333333333,  0,         1,  0, 333333332},
+            {0, 333333333,  0, 333333333,  0,         0},
+            {0, 333333333,  0, 666666666, -1, 666666667},
+            {0, 333333333,  1,         0, -1, 333333333},
+            {0, 333333333,  2,         0, -2, 333333333},
+            {0, 333333333,  3,         0, -3, 333333333},
+            {0, 333333333,  3, 333333333, -3,         0},
+
+            {1, 0, -4, 666666667,  4, 333333333},
+            {1, 0, -3,         0,  4,         0},
+            {1, 0, -2,         0,  3,         0},
+            {1, 0, -1,         0,  2,         0},
+            {1, 0, -1, 333333334,  1, 666666666},
+            {1, 0, -1, 666666667,  1, 333333333},
+            {1, 0, -1, 999999999,  1,         1},
+            {1, 0,  0,         0,  1,         0},
+            {1, 0,  0,         1,  0, 999999999},
+            {1, 0,  0, 333333333,  0, 666666667},
+            {1, 0,  0, 666666666,  0, 333333334},
+            {1, 0,  1,         0,  0,         0},
+            {1, 0,  2,         0, -1,         0},
+            {1, 0,  3,         0, -2,         0},
+            {1, 0,  3, 333333333, -3, 666666667},
+
+            {2, 0, -4, 666666667,  5, 333333333},
+            {2, 0, -3,         0,  5,         0},
+            {2, 0, -2,         0,  4,         0},
+            {2, 0, -1,         0,  3,         0},
+            {2, 0, -1, 333333334,  2, 666666666},
+            {2, 0, -1, 666666667,  2, 333333333},
+            {2, 0, -1, 999999999,  2,         1},
+            {2, 0,  0,         0,  2,         0},
+            {2, 0,  0,         1,  1, 999999999},
+            {2, 0,  0, 333333333,  1, 666666667},
+            {2, 0,  0, 666666666,  1, 333333334},
+            {2, 0,  1,         0,  1,         0},
+            {2, 0,  2,         0,  0,         0},
+            {2, 0,  3,         0, -1,         0},
+            {2, 0,  3, 333333333, -2, 666666667},
+
+            {3, 0, -4, 666666667,  6, 333333333},
+            {3, 0, -3,         0,  6,         0},
+            {3, 0, -2,         0,  5,         0},
+            {3, 0, -1,         0,  4,         0},
+            {3, 0, -1, 333333334,  3, 666666666},
+            {3, 0, -1, 666666667,  3, 333333333},
+            {3, 0, -1, 999999999,  3,         1},
+            {3, 0,  0,         0,  3,         0},
+            {3, 0,  0,         1,  2, 999999999},
+            {3, 0,  0, 333333333,  2, 666666667},
+            {3, 0,  0, 666666666,  2, 333333334},
+            {3, 0,  1,         0,  2,         0},
+            {3, 0,  2,         0,  1,         0},
+            {3, 0,  3,         0,  0,         0},
+            {3, 0,  3, 333333333, -1, 666666667},
+
+            {3, 333333333, -4, 666666667,  6, 666666666},
+            {3, 333333333, -3,         0,  6, 333333333},
+            {3, 333333333, -2,         0,  5, 333333333},
+            {3, 333333333, -1,         0,  4, 333333333},
+            {3, 333333333, -1, 333333334,  3, 999999999},
+            {3, 333333333, -1, 666666667,  3, 666666666},
+            {3, 333333333, -1, 999999999,  3, 333333334},
+            {3, 333333333,  0,         0,  3, 333333333},
+            {3, 333333333,  0,         1,  3, 333333332},
+            {3, 333333333,  0, 333333333,  3,         0},
+            {3, 333333333,  0, 666666666,  2, 666666667},
+            {3, 333333333,  1,         0,  2, 333333333},
+            {3, 333333333,  2,         0,  1, 333333333},
+            {3, 333333333,  3,         0,  0, 333333333},
+            {3, 333333333,  3, 333333333,  0,         0},
+
+            {Long.MAX_VALUE, 0, Long.MAX_VALUE, 0, 0, 0},
+       };
+    }
+
+    @Test(dataProvider="Minus", groups={"tck"})
+    public void minus(long seconds, int nanos, long otherSeconds, int otherNanos, long expectedSeconds, int expectedNanoOfSecond) {
+       Duration t = Duration.ofSeconds(seconds, nanos).minus(Duration.ofSeconds(otherSeconds, otherNanos));
+       assertEquals(t.getSeconds(), expectedSeconds);
+       assertEquals(t.getNano(), expectedNanoOfSecond);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void minusOverflowTooSmall() {
+       Duration t = Duration.ofSeconds(Long.MIN_VALUE);
+       t.minus(Duration.ofSeconds(0, 1));
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void minusOverflowTooBig() {
+       Duration t = Duration.ofSeconds(Long.MAX_VALUE, 999999999);
+       t.minus(Duration.ofSeconds(-1, 999999999));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void minus_longTemporalUnit_seconds() {
+        Duration t = Duration.ofSeconds(1);
+        t = t.minus(1, SECONDS);
+        assertEquals(0, t.getSeconds());
+        assertEquals(0, t.getNano());
+     }
+
+    @Test(groups={"tck"})
+    public void minus_longTemporalUnit_millis() {
+        Duration t = Duration.ofSeconds(1);
+        t = t.minus(1, MILLIS);
+        assertEquals(0, t.getSeconds());
+        assertEquals(999000000, t.getNano());
+     }
+
+    @Test(groups={"tck"})
+    public void minus_longTemporalUnit_micros() {
+        Duration t = Duration.ofSeconds(1);
+        t = t.minus(1, MICROS);
+        assertEquals(0, t.getSeconds());
+        assertEquals(999999000, t.getNano());
+     }
+
+    @Test(groups={"tck"})
+    public void minus_longTemporalUnit_nanos() {
+        Duration t = Duration.ofSeconds(1);
+        t = t.minus(1, NANOS);
+        assertEquals(0, t.getSeconds());
+        assertEquals(999999999, t.getNano());
+     }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void minus_longTemporalUnit_null() {
+       Duration t = Duration.ofSeconds(1);
+       t.minus(1, (TemporalUnit) null);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="MinusSeconds")
+    Object[][] provider_minusSeconds_long() {
+        return new Object[][] {
+            {0, 0, 0, 0, 0},
+            {0, 0, 1, -1, 0},
+            {0, 0, -1, 1, 0},
+            {0, 0, Long.MAX_VALUE, -Long.MAX_VALUE, 0},
+            {0, 0, Long.MIN_VALUE + 1, Long.MAX_VALUE, 0},
+            {1, 0, 0, 1, 0},
+            {1, 0, 1, 0, 0},
+            {1, 0, -1, 2, 0},
+            {1, 0, Long.MAX_VALUE - 1, -Long.MAX_VALUE + 2, 0},
+            {1, 0, Long.MIN_VALUE + 2, Long.MAX_VALUE, 0},
+            {1, 1, 0, 1, 1},
+            {1, 1, 1, 0, 1},
+            {1, 1, -1, 2, 1},
+            {1, 1, Long.MAX_VALUE, -Long.MAX_VALUE + 1, 1},
+            {1, 1, Long.MIN_VALUE + 2, Long.MAX_VALUE, 1},
+            {-1, 1, 0, -1, 1},
+            {-1, 1, 1, -2, 1},
+            {-1, 1, -1, 0, 1},
+            {-1, 1, Long.MAX_VALUE, Long.MIN_VALUE, 1},
+            {-1, 1, Long.MIN_VALUE + 1, Long.MAX_VALUE - 1, 1},
+        };
+    }
+
+    @Test(dataProvider="MinusSeconds", groups={"tck"})
+    public void minusSeconds_long(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) {
+        Duration t = Duration.ofSeconds(seconds, nanos);
+        t = t.minusSeconds(amount);
+        assertEquals(t.getSeconds(), expectedSeconds);
+        assertEquals(t.getNano(), expectedNanoOfSecond);
+    }
+
+    @Test(expectedExceptions = {ArithmeticException.class}, groups={"tck"})
+    public void minusSeconds_long_overflowTooBig() {
+        Duration t = Duration.ofSeconds(1, 0);
+        t.minusSeconds(Long.MIN_VALUE + 1);
+    }
+
+    @Test(expectedExceptions = {ArithmeticException.class}, groups={"tck"})
+    public void minusSeconds_long_overflowTooSmall() {
+        Duration t = Duration.ofSeconds(-2, 0);
+        t.minusSeconds(Long.MAX_VALUE);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="MinusMillis")
+    Object[][] provider_minusMillis_long() {
+        return new Object[][] {
+            {0, 0, 0,       0, 0},
+            {0, 0, 1,      -1, 999000000},
+            {0, 0, 999,    -1, 1000000},
+            {0, 0, 1000,   -1, 0},
+            {0, 0, 1001,   -2, 999000000},
+            {0, 0, 1999,   -2, 1000000},
+            {0, 0, 2000,   -2, 0},
+            {0, 0, -1,      0, 1000000},
+            {0, 0, -999,    0, 999000000},
+            {0, 0, -1000,   1, 0},
+            {0, 0, -1001,   1, 1000000},
+            {0, 0, -1999,   1, 999000000},
+
+            {0, 1, 0,       0, 1},
+            {0, 1, 1,      -1, 999000001},
+            {0, 1, 998,    -1, 2000001},
+            {0, 1, 999,    -1, 1000001},
+            {0, 1, 1000,   -1, 1},
+            {0, 1, 1998,   -2, 2000001},
+            {0, 1, 1999,   -2, 1000001},
+            {0, 1, 2000,   -2, 1},
+            {0, 1, -1,      0, 1000001},
+            {0, 1, -2,      0, 2000001},
+            {0, 1, -1000,   1, 1},
+            {0, 1, -1001,   1, 1000001},
+
+            {0, 1000000, 0,       0, 1000000},
+            {0, 1000000, 1,       0, 0},
+            {0, 1000000, 998,    -1, 3000000},
+            {0, 1000000, 999,    -1, 2000000},
+            {0, 1000000, 1000,   -1, 1000000},
+            {0, 1000000, 1998,   -2, 3000000},
+            {0, 1000000, 1999,   -2, 2000000},
+            {0, 1000000, 2000,   -2, 1000000},
+            {0, 1000000, -1,      0, 2000000},
+            {0, 1000000, -2,      0, 3000000},
+            {0, 1000000, -999,    1, 0},
+            {0, 1000000, -1000,   1, 1000000},
+            {0, 1000000, -1001,   1, 2000000},
+            {0, 1000000, -1002,   1, 3000000},
+
+            {0, 999999999, 0,     0, 999999999},
+            {0, 999999999, 1,     0, 998999999},
+            {0, 999999999, 999,   0, 999999},
+            {0, 999999999, 1000, -1, 999999999},
+            {0, 999999999, 1001, -1, 998999999},
+            {0, 999999999, -1,    1, 999999},
+            {0, 999999999, -1000, 1, 999999999},
+            {0, 999999999, -1001, 2, 999999},
+        };
+    }
+
+    @Test(dataProvider="MinusMillis", groups={"tck"})
+    public void minusMillis_long(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) {
+        Duration t = Duration.ofSeconds(seconds, nanos);
+        t = t.minusMillis(amount);
+        assertEquals(t.getSeconds(), expectedSeconds);
+        assertEquals(t.getNano(), expectedNanoOfSecond);
+    }
+    @Test(dataProvider="MinusMillis", groups={"tck"})
+    public void minusMillis_long_oneMore(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) {
+        Duration t = Duration.ofSeconds(seconds + 1, nanos);
+        t = t.minusMillis(amount);
+        assertEquals(t.getSeconds(), expectedSeconds + 1);
+        assertEquals(t.getNano(), expectedNanoOfSecond);
+    }
+    @Test(dataProvider="MinusMillis", groups={"tck"})
+    public void minusMillis_long_minusOneLess(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) {
+        Duration t = Duration.ofSeconds(seconds - 1, nanos);
+        t = t.minusMillis(amount);
+        assertEquals(t.getSeconds(), expectedSeconds - 1);
+        assertEquals(t.getNano(), expectedNanoOfSecond);
+    }
+
+    @Test(groups={"tck"})
+    public void minusMillis_long_max() {
+        Duration t = Duration.ofSeconds(Long.MAX_VALUE, 998999999);
+        t = t.minusMillis(-1);
+        assertEquals(t.getSeconds(), Long.MAX_VALUE);
+        assertEquals(t.getNano(), 999999999);
+    }
+
+    @Test(expectedExceptions = {ArithmeticException.class}, groups={"tck"})
+    public void minusMillis_long_overflowTooBig() {
+        Duration t = Duration.ofSeconds(Long.MAX_VALUE, 999000000);
+        t.minusMillis(-1);
+    }
+
+    @Test(groups={"tck"})
+    public void minusMillis_long_min() {
+        Duration t = Duration.ofSeconds(Long.MIN_VALUE, 1000000);
+        t = t.minusMillis(1);
+        assertEquals(t.getSeconds(), Long.MIN_VALUE);
+        assertEquals(t.getNano(), 0);
+    }
+
+    @Test(expectedExceptions = {ArithmeticException.class}, groups={"tck"})
+    public void minusMillis_long_overflowTooSmall() {
+        Duration t = Duration.ofSeconds(Long.MIN_VALUE, 0);
+        t.minusMillis(1);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="MinusNanos")
+    Object[][] provider_minusNanos_long() {
+        return new Object[][] {
+            {0, 0, 0,           0, 0},
+            {0, 0, 1,          -1, 999999999},
+            {0, 0, 999999999,  -1, 1},
+            {0, 0, 1000000000, -1, 0},
+            {0, 0, 1000000001, -2, 999999999},
+            {0, 0, 1999999999, -2, 1},
+            {0, 0, 2000000000, -2, 0},
+            {0, 0, -1,          0, 1},
+            {0, 0, -999999999,  0, 999999999},
+            {0, 0, -1000000000, 1, 0},
+            {0, 0, -1000000001, 1, 1},
+            {0, 0, -1999999999, 1, 999999999},
+
+            {1, 0, 0,            1, 0},
+            {1, 0, 1,            0, 999999999},
+            {1, 0, 999999999,    0, 1},
+            {1, 0, 1000000000,   0, 0},
+            {1, 0, 1000000001,  -1, 999999999},
+            {1, 0, 1999999999,  -1, 1},
+            {1, 0, 2000000000,  -1, 0},
+            {1, 0, -1,           1, 1},
+            {1, 0, -999999999,   1, 999999999},
+            {1, 0, -1000000000,  2, 0},
+            {1, 0, -1000000001,  2, 1},
+            {1, 0, -1999999999,  2, 999999999},
+
+            {-1, 0, 0,           -1, 0},
+            {-1, 0, 1,           -2, 999999999},
+            {-1, 0, 999999999,   -2, 1},
+            {-1, 0, 1000000000,  -2, 0},
+            {-1, 0, 1000000001,  -3, 999999999},
+            {-1, 0, 1999999999,  -3, 1},
+            {-1, 0, 2000000000,  -3, 0},
+            {-1, 0, -1,          -1, 1},
+            {-1, 0, -999999999,  -1, 999999999},
+            {-1, 0, -1000000000,  0, 0},
+            {-1, 0, -1000000001,  0, 1},
+            {-1, 0, -1999999999,  0, 999999999},
+
+            {1, 1, 0,           1, 1},
+            {1, 1, 1,           1, 0},
+            {1, 1, 999999998,   0, 3},
+            {1, 1, 999999999,   0, 2},
+            {1, 1, 1000000000,  0, 1},
+            {1, 1, 1999999998, -1, 3},
+            {1, 1, 1999999999, -1, 2},
+            {1, 1, 2000000000, -1, 1},
+            {1, 1, -1,          1, 2},
+            {1, 1, -2,          1, 3},
+            {1, 1, -1000000000, 2, 1},
+            {1, 1, -1000000001, 2, 2},
+            {1, 1, -1000000002, 2, 3},
+            {1, 1, -2000000000, 3, 1},
+
+            {1, 999999999, 0,           1, 999999999},
+            {1, 999999999, 1,           1, 999999998},
+            {1, 999999999, 999999999,   1, 0},
+            {1, 999999999, 1000000000,  0, 999999999},
+            {1, 999999999, 1000000001,  0, 999999998},
+            {1, 999999999, -1,          2, 0},
+            {1, 999999999, -1000000000, 2, 999999999},
+            {1, 999999999, -1000000001, 3, 0},
+            {1, 999999999, -1999999999, 3, 999999998},
+            {1, 999999999, -2000000000, 3, 999999999},
+
+            {Long.MAX_VALUE, 0, -999999999, Long.MAX_VALUE, 999999999},
+            {Long.MAX_VALUE - 1, 0, -1999999999, Long.MAX_VALUE, 999999999},
+            {Long.MIN_VALUE, 1, 1, Long.MIN_VALUE, 0},
+            {Long.MIN_VALUE + 1, 1, 1000000001, Long.MIN_VALUE, 0},
+        };
+    }
+
+    @Test(dataProvider="MinusNanos", groups={"tck"})
+    public void minusNanos_long(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) {
+        Duration t = Duration.ofSeconds(seconds, nanos);
+        t = t.minusNanos(amount);
+        assertEquals(t.getSeconds(), expectedSeconds);
+        assertEquals(t.getNano(), expectedNanoOfSecond);
+    }
+
+    @Test(expectedExceptions = {ArithmeticException.class}, groups={"tck"})
+    public void minusNanos_long_overflowTooBig() {
+        Duration t = Duration.ofSeconds(Long.MAX_VALUE, 999999999);
+        t.minusNanos(-1);
+    }
+
+    @Test(expectedExceptions = {ArithmeticException.class}, groups={"tck"})
+    public void minusNanos_long_overflowTooSmall() {
+        Duration t = Duration.ofSeconds(Long.MIN_VALUE, 0);
+        t.minusNanos(1);
+    }
+
+    //-----------------------------------------------------------------------
+    // multipliedBy()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="MultipliedBy")
+    Object[][] provider_multipliedBy() {
+       return new Object[][] {
+          {-4, 666666667, -3,   9, 999999999},
+          {-4, 666666667, -2,   6, 666666666},
+          {-4, 666666667, -1,   3, 333333333},
+          {-4, 666666667,  0,   0,         0},
+          {-4, 666666667,  1,  -4, 666666667},
+          {-4, 666666667,  2,  -7, 333333334},
+          {-4, 666666667,  3, -10, 000000001},
+
+          {-3, 0, -3,  9, 0},
+          {-3, 0, -2,  6, 0},
+          {-3, 0, -1,  3, 0},
+          {-3, 0,  0,  0, 0},
+          {-3, 0,  1, -3, 0},
+          {-3, 0,  2, -6, 0},
+          {-3, 0,  3, -9, 0},
+
+          {-2, 0, -3,  6, 0},
+          {-2, 0, -2,  4, 0},
+          {-2, 0, -1,  2, 0},
+          {-2, 0,  0,  0, 0},
+          {-2, 0,  1, -2, 0},
+          {-2, 0,  2, -4, 0},
+          {-2, 0,  3, -6, 0},
+
+          {-1, 0, -3,  3, 0},
+          {-1, 0, -2,  2, 0},
+          {-1, 0, -1,  1, 0},
+          {-1, 0,  0,  0, 0},
+          {-1, 0,  1, -1, 0},
+          {-1, 0,  2, -2, 0},
+          {-1, 0,  3, -3, 0},
+
+          {-1, 500000000, -3,  1, 500000000},
+          {-1, 500000000, -2,  1,         0},
+          {-1, 500000000, -1,  0, 500000000},
+          {-1, 500000000,  0,  0,         0},
+          {-1, 500000000,  1, -1, 500000000},
+          {-1, 500000000,  2, -1,         0},
+          {-1, 500000000,  3, -2, 500000000},
+
+          {0, 0, -3, 0, 0},
+          {0, 0, -2, 0, 0},
+          {0, 0, -1, 0, 0},
+          {0, 0,  0, 0, 0},
+          {0, 0,  1, 0, 0},
+          {0, 0,  2, 0, 0},
+          {0, 0,  3, 0, 0},
+
+          {0, 500000000, -3, -2, 500000000},
+          {0, 500000000, -2, -1,         0},
+          {0, 500000000, -1, -1, 500000000},
+          {0, 500000000,  0,  0,         0},
+          {0, 500000000,  1,  0, 500000000},
+          {0, 500000000,  2,  1,         0},
+          {0, 500000000,  3,  1, 500000000},
+
+          {1, 0, -3, -3, 0},
+          {1, 0, -2, -2, 0},
+          {1, 0, -1, -1, 0},
+          {1, 0,  0,  0, 0},
+          {1, 0,  1,  1, 0},
+          {1, 0,  2,  2, 0},
+          {1, 0,  3,  3, 0},
+
+          {2, 0, -3, -6, 0},
+          {2, 0, -2, -4, 0},
+          {2, 0, -1, -2, 0},
+          {2, 0,  0,  0, 0},
+          {2, 0,  1,  2, 0},
+          {2, 0,  2,  4, 0},
+          {2, 0,  3,  6, 0},
+
+          {3, 0, -3, -9, 0},
+          {3, 0, -2, -6, 0},
+          {3, 0, -1, -3, 0},
+          {3, 0,  0,  0, 0},
+          {3, 0,  1,  3, 0},
+          {3, 0,  2,  6, 0},
+          {3, 0,  3,  9, 0},
+
+          {3, 333333333, -3, -10, 000000001},
+          {3, 333333333, -2,  -7, 333333334},
+          {3, 333333333, -1,  -4, 666666667},
+          {3, 333333333,  0,   0,         0},
+          {3, 333333333,  1,   3, 333333333},
+          {3, 333333333,  2,   6, 666666666},
+          {3, 333333333,  3,   9, 999999999},
+       };
+    }
+
+    @Test(dataProvider="MultipliedBy", groups={"tck"})
+    public void multipliedBy(long seconds, int nanos, int multiplicand, long expectedSeconds, int expectedNanos) {
+        Duration t = Duration.ofSeconds(seconds, nanos);
+        t = t.multipliedBy(multiplicand);
+        assertEquals(t.getSeconds(), expectedSeconds);
+        assertEquals(t.getNano(), expectedNanos);
+    }
+
+    @Test(groups={"tck"})
+    public void multipliedBy_max() {
+        Duration test = Duration.ofSeconds(1);
+        assertEquals(test.multipliedBy(Long.MAX_VALUE), Duration.ofSeconds(Long.MAX_VALUE));
+    }
+
+    @Test(groups={"tck"})
+    public void multipliedBy_min() {
+        Duration test = Duration.ofSeconds(1);
+        assertEquals(test.multipliedBy(Long.MIN_VALUE), Duration.ofSeconds(Long.MIN_VALUE));
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void multipliedBy_tooBig() {
+        Duration test = Duration.ofSeconds(1, 1);
+        test.multipliedBy(Long.MAX_VALUE);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void multipliedBy_tooBig_negative() {
+        Duration test = Duration.ofSeconds(1, 1);
+        test.multipliedBy(Long.MIN_VALUE);
+    }
+
+    //-----------------------------------------------------------------------
+    // dividedBy()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="DividedBy")
+    Object[][] provider_dividedBy() {
+       return new Object[][] {
+          {-4, 666666667, -3,  1, 111111111},
+          {-4, 666666667, -2,  1, 666666666},
+          {-4, 666666667, -1,  3, 333333333},
+          {-4, 666666667,  1, -4, 666666667},
+          {-4, 666666667,  2, -2, 333333334},
+          {-4, 666666667,  3, -2, 888888889},
+
+          {-3, 0, -3,  1, 0},
+          {-3, 0, -2,  1, 500000000},
+          {-3, 0, -1,  3, 0},
+          {-3, 0,  1, -3, 0},
+          {-3, 0,  2, -2, 500000000},
+          {-3, 0,  3, -1, 0},
+
+          {-2, 0, -3,  0, 666666666},
+          {-2, 0, -2,  1,         0},
+          {-2, 0, -1,  2,         0},
+          {-2, 0,  1, -2,         0},
+          {-2, 0,  2, -1,         0},
+          {-2, 0,  3, -1, 333333334},
+
+          {-1, 0, -3,  0, 333333333},
+          {-1, 0, -2,  0, 500000000},
+          {-1, 0, -1,  1,         0},
+          {-1, 0,  1, -1,         0},
+          {-1, 0,  2, -1, 500000000},
+          {-1, 0,  3, -1, 666666667},
+
+          {-1, 500000000, -3,  0, 166666666},
+          {-1, 500000000, -2,  0, 250000000},
+          {-1, 500000000, -1,  0, 500000000},
+          {-1, 500000000,  1, -1, 500000000},
+          {-1, 500000000,  2, -1, 750000000},
+          {-1, 500000000,  3, -1, 833333334},
+
+          {0, 0, -3, 0, 0},
+          {0, 0, -2, 0, 0},
+          {0, 0, -1, 0, 0},
+          {0, 0,  1, 0, 0},
+          {0, 0,  2, 0, 0},
+          {0, 0,  3, 0, 0},
+
+          {0, 500000000, -3, -1, 833333334},
+          {0, 500000000, -2, -1, 750000000},
+          {0, 500000000, -1, -1, 500000000},
+          {0, 500000000,  1,  0, 500000000},
+          {0, 500000000,  2,  0, 250000000},
+          {0, 500000000,  3,  0, 166666666},
+
+          {1, 0, -3, -1, 666666667},
+          {1, 0, -2, -1, 500000000},
+          {1, 0, -1, -1,         0},
+          {1, 0,  1,  1,         0},
+          {1, 0,  2,  0, 500000000},
+          {1, 0,  3,  0, 333333333},
+
+          {2, 0, -3, -1, 333333334},
+          {2, 0, -2, -1,         0},
+          {2, 0, -1, -2,         0},
+          {2, 0,  1,  2,         0},
+          {2, 0,  2,  1,         0},
+          {2, 0,  3,  0, 666666666},
+
+          {3, 0, -3, -1,         0},
+          {3, 0, -2, -2, 500000000},
+          {3, 0, -1, -3,         0},
+          {3, 0,  1,  3,         0},
+          {3, 0,  2,  1, 500000000},
+          {3, 0,  3,  1,         0},
+
+          {3, 333333333, -3, -2, 888888889},
+          {3, 333333333, -2, -2, 333333334},
+          {3, 333333333, -1, -4, 666666667},
+          {3, 333333333,  1,  3, 333333333},
+          {3, 333333333,  2,  1, 666666666},
+          {3, 333333333,  3,  1, 111111111},
+       };
+    }
+
+    @Test(dataProvider="DividedBy", groups={"tck"})
+    public void dividedBy(long seconds, int nanos, int divisor, long expectedSeconds, int expectedNanos) {
+        Duration t = Duration.ofSeconds(seconds, nanos);
+        t = t.dividedBy(divisor);
+        assertEquals(t.getSeconds(), expectedSeconds);
+        assertEquals(t.getNano(), expectedNanos);
+    }
+
+    @Test(dataProvider="DividedBy", expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void dividedByZero(long seconds, int nanos, int divisor, long expectedSeconds, int expectedNanos) {
+       Duration t = Duration.ofSeconds(seconds, nanos);
+       t.dividedBy(0);
+       fail(t + " divided by zero did not throw ArithmeticException");
+    }
+
+    @Test(groups={"tck"})
+    public void dividedBy_max() {
+        Duration test = Duration.ofSeconds(Long.MAX_VALUE);
+        assertEquals(test.dividedBy(Long.MAX_VALUE), Duration.ofSeconds(1));
+    }
+
+    //-----------------------------------------------------------------------
+    // negated()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_negated() {
+        assertEquals(Duration.ofSeconds(0).negated(), Duration.ofSeconds(0));
+        assertEquals(Duration.ofSeconds(12).negated(), Duration.ofSeconds(-12));
+        assertEquals(Duration.ofSeconds(-12).negated(), Duration.ofSeconds(12));
+        assertEquals(Duration.ofSeconds(12, 20).negated(), Duration.ofSeconds(-12, -20));
+        assertEquals(Duration.ofSeconds(12, -20).negated(), Duration.ofSeconds(-12, 20));
+        assertEquals(Duration.ofSeconds(-12, -20).negated(), Duration.ofSeconds(12, 20));
+        assertEquals(Duration.ofSeconds(-12, 20).negated(), Duration.ofSeconds(12, -20));
+        assertEquals(Duration.ofSeconds(Long.MAX_VALUE).negated(), Duration.ofSeconds(-Long.MAX_VALUE));
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void test_negated_overflow() {
+        Duration.ofSeconds(Long.MIN_VALUE).negated();
+    }
+
+    //-----------------------------------------------------------------------
+    // abs()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_abs() {
+        assertEquals(Duration.ofSeconds(0).abs(), Duration.ofSeconds(0));
+        assertEquals(Duration.ofSeconds(12).abs(), Duration.ofSeconds(12));
+        assertEquals(Duration.ofSeconds(-12).abs(), Duration.ofSeconds(12));
+        assertEquals(Duration.ofSeconds(12, 20).abs(), Duration.ofSeconds(12, 20));
+        assertEquals(Duration.ofSeconds(12, -20).abs(), Duration.ofSeconds(12, -20));
+        assertEquals(Duration.ofSeconds(-12, -20).abs(), Duration.ofSeconds(12, 20));
+        assertEquals(Duration.ofSeconds(-12, 20).abs(), Duration.ofSeconds(12, -20));
+        assertEquals(Duration.ofSeconds(Long.MAX_VALUE).abs(), Duration.ofSeconds(Long.MAX_VALUE));
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void test_abs_overflow() {
+        Duration.ofSeconds(Long.MIN_VALUE).abs();
+    }
+
+    //-----------------------------------------------------------------------
+    // toNanos()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_toNanos() {
+        Duration test = Duration.ofSeconds(321, 123456789);
+        assertEquals(test.toNanos(), 321123456789L);
+    }
+
+    @Test(groups={"tck"})
+    public void test_toNanos_max() {
+        Duration test = Duration.ofSeconds(0, Long.MAX_VALUE);
+        assertEquals(test.toNanos(), Long.MAX_VALUE);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void test_toNanos_tooBig() {
+        Duration test = Duration.ofSeconds(0, Long.MAX_VALUE).plusNanos(1);
+        test.toNanos();
+    }
+
+    //-----------------------------------------------------------------------
+    // toMillis()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_toMillis() {
+        Duration test = Duration.ofSeconds(321, 123456789);
+        assertEquals(test.toMillis(), 321000 + 123);
+    }
+
+    @Test(groups={"tck"})
+    public void test_toMillis_max() {
+        Duration test = Duration.ofSeconds(Long.MAX_VALUE / 1000, (Long.MAX_VALUE % 1000) * 1000000);
+        assertEquals(test.toMillis(), Long.MAX_VALUE);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void test_toMillis_tooBig() {
+        Duration test = Duration.ofSeconds(Long.MAX_VALUE / 1000, ((Long.MAX_VALUE % 1000) + 1) * 1000000);
+        test.toMillis();
+    }
+
+    //-----------------------------------------------------------------------
+    // compareTo()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_comparisons() {
+        doTest_comparisons_Duration(
+            Duration.ofSeconds(-2L, 0),
+            Duration.ofSeconds(-2L, 999999998),
+            Duration.ofSeconds(-2L, 999999999),
+            Duration.ofSeconds(-1L, 0),
+            Duration.ofSeconds(-1L, 1),
+            Duration.ofSeconds(-1L, 999999998),
+            Duration.ofSeconds(-1L, 999999999),
+            Duration.ofSeconds(0L, 0),
+            Duration.ofSeconds(0L, 1),
+            Duration.ofSeconds(0L, 2),
+            Duration.ofSeconds(0L, 999999999),
+            Duration.ofSeconds(1L, 0),
+            Duration.ofSeconds(2L, 0)
+        );
+    }
+
+    void doTest_comparisons_Duration(Duration... durations) {
+        for (int i = 0; i < durations.length; i++) {
+            Duration a = durations[i];
+            for (int j = 0; j < durations.length; j++) {
+                Duration b = durations[j];
+                if (i < j) {
+                    assertEquals(a.compareTo(b)< 0, true, a + " <=> " + b);
+                    assertEquals(a.isLessThan(b), true, a + " <=> " + b);
+                    assertEquals(a.isGreaterThan(b), false, a + " <=> " + b);
+                    assertEquals(a.equals(b), false, a + " <=> " + b);
+                } else if (i > j) {
+                    assertEquals(a.compareTo(b) > 0, true, a + " <=> " + b);
+                    assertEquals(a.isLessThan(b), false, a + " <=> " + b);
+                    assertEquals(a.isGreaterThan(b), true, a + " <=> " + b);
+                    assertEquals(a.equals(b), false, a + " <=> " + b);
+                } else {
+                    assertEquals(a.compareTo(b), 0, a + " <=> " + b);
+                    assertEquals(a.isLessThan(b), false, a + " <=> " + b);
+                    assertEquals(a.isGreaterThan(b), false, a + " <=> " + b);
+                    assertEquals(a.equals(b), true, a + " <=> " + b);
+                }
+            }
+        }
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_compareTo_ObjectNull() {
+        Duration a = Duration.ofSeconds(0L, 0);
+        a.compareTo(null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_isLessThan_ObjectNull() {
+        Duration a = Duration.ofSeconds(0L, 0);
+        a.isLessThan(null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_isGreaterThan_ObjectNull() {
+        Duration a = Duration.ofSeconds(0L, 0);
+        a.isGreaterThan(null);
+    }
+
+    @Test(expectedExceptions=ClassCastException.class, groups={"tck"})
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public void compareToNonDuration() {
+       Comparable c = Duration.ofSeconds(0L);
+       c.compareTo(new Object());
+    }
+
+    //-----------------------------------------------------------------------
+    // equals()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_equals() {
+        Duration test5a = Duration.ofSeconds(5L, 20);
+        Duration test5b = Duration.ofSeconds(5L, 20);
+        Duration test5n = Duration.ofSeconds(5L, 30);
+        Duration test6 = Duration.ofSeconds(6L, 20);
+
+        assertEquals(test5a.equals(test5a), true);
+        assertEquals(test5a.equals(test5b), true);
+        assertEquals(test5a.equals(test5n), false);
+        assertEquals(test5a.equals(test6), false);
+
+        assertEquals(test5b.equals(test5a), true);
+        assertEquals(test5b.equals(test5b), true);
+        assertEquals(test5b.equals(test5n), false);
+        assertEquals(test5b.equals(test6), false);
+
+        assertEquals(test5n.equals(test5a), false);
+        assertEquals(test5n.equals(test5b), false);
+        assertEquals(test5n.equals(test5n), true);
+        assertEquals(test5n.equals(test6), false);
+
+        assertEquals(test6.equals(test5a), false);
+        assertEquals(test6.equals(test5b), false);
+        assertEquals(test6.equals(test5n), false);
+        assertEquals(test6.equals(test6), true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_null() {
+        Duration test5 = Duration.ofSeconds(5L, 20);
+        assertEquals(test5.equals(null), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_otherClass() {
+        Duration test5 = Duration.ofSeconds(5L, 20);
+        assertEquals(test5.equals(""), false);
+    }
+
+    //-----------------------------------------------------------------------
+    // hashCode()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_hashCode() {
+        Duration test5a = Duration.ofSeconds(5L, 20);
+        Duration test5b = Duration.ofSeconds(5L, 20);
+        Duration test5n = Duration.ofSeconds(5L, 30);
+        Duration test6 = Duration.ofSeconds(6L, 20);
+
+        assertEquals(test5a.hashCode() == test5a.hashCode(), true);
+        assertEquals(test5a.hashCode() == test5b.hashCode(), true);
+        assertEquals(test5b.hashCode() == test5b.hashCode(), true);
+
+        assertEquals(test5a.hashCode() == test5n.hashCode(), false);
+        assertEquals(test5a.hashCode() == test6.hashCode(), false);
+    }
+
+    //-----------------------------------------------------------------------
+    // toString()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="ToString")
+    Object[][] provider_toString() {
+        return new Object[][] {
+            {0, 0, "PT0S"},
+            {0, 1, "PT0.000000001S"},
+            {0, 10, "PT0.00000001S"},
+            {0, 100, "PT0.0000001S"},
+            {0, 1000, "PT0.000001S"},
+            {0, 10000, "PT0.00001S"},
+            {0, 100000, "PT0.0001S"},
+            {0, 1000000, "PT0.001S"},
+            {0, 10000000, "PT0.01S"},
+            {0, 100000000, "PT0.1S"},
+            {0, 120000000, "PT0.12S"},
+            {0, 123000000, "PT0.123S"},
+            {0, 123400000, "PT0.1234S"},
+            {0, 123450000, "PT0.12345S"},
+            {0, 123456000, "PT0.123456S"},
+            {0, 123456700, "PT0.1234567S"},
+            {0, 123456780, "PT0.12345678S"},
+            {0, 123456789, "PT0.123456789S"},
+            {1, 0, "PT1S"},
+            {-1, 0, "PT-1S"},
+            {-1, 1000, "PT-0.999999S"},
+            {-1, 900000000, "PT-0.1S"},
+            {Long.MAX_VALUE, 0, "PT9223372036854775807S"},
+            {Long.MIN_VALUE, 0, "PT-9223372036854775808S"},
+        };
+    }
+
+    @Test(dataProvider="ToString", groups={"tck"})
+    public void test_toString(long seconds, int nanos, String expected) {
+        Duration t = Duration.ofSeconds(seconds, nanos);
+        assertEquals(t.toString(), expected);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/TCKInstant.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,1680 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time;
+
+import static java.time.temporal.ChronoField.INSTANT_SECONDS;
+import static java.time.temporal.ChronoField.MICRO_OF_SECOND;
+import static java.time.temporal.ChronoField.MILLI_OF_SECOND;
+import static java.time.temporal.ChronoField.NANO_OF_SECOND;
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.NANOS;
+import static java.time.temporal.ChronoUnit.SECONDS;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.JulianFields;
+import java.time.temporal.Queries;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalField;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test Instant.
+ */
+@Test
+public class TCKInstant extends AbstractDateTimeTest {
+
+    private static final long MIN_SECOND = Instant.MIN.getEpochSecond();
+    private static final long MAX_SECOND = Instant.MAX.getEpochSecond();
+
+    private Instant TEST_12345_123456789;
+
+    @BeforeMethod
+    public void setUp() {
+        TEST_12345_123456789 = Instant.ofEpochSecond(12345, 123456789);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    protected List<TemporalAccessor> samples() {
+        TemporalAccessor[] array = {TEST_12345_123456789, Instant.MIN, Instant.MAX, Instant.EPOCH};
+        return Arrays.asList(array);
+    }
+
+    @Override
+    protected List<TemporalField> validFields() {
+        TemporalField[] array = {
+            NANO_OF_SECOND,
+            MICRO_OF_SECOND,
+            MILLI_OF_SECOND,
+            INSTANT_SECONDS,
+        };
+        return Arrays.asList(array);
+    }
+
+    @Override
+    protected List<TemporalField> invalidFields() {
+        List<TemporalField> list = new ArrayList<>(Arrays.<TemporalField>asList(ChronoField.values()));
+        list.removeAll(validFields());
+        list.add(JulianFields.JULIAN_DAY);
+        list.add(JulianFields.MODIFIED_JULIAN_DAY);
+        list.add(JulianFields.RATA_DIE);
+        return list;
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_serialization() throws Exception {
+        assertSerializable(Instant.ofEpochMilli(134l));
+    }
+
+    @Test
+    public void test_serialization_format() throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try (DataOutputStream dos = new DataOutputStream(baos) ) {
+            dos.writeByte(2);
+            dos.writeLong(654321);
+            dos.writeInt(123456789);
+        }
+        byte[] bytes = baos.toByteArray();
+        assertSerializedBySer(Instant.ofEpochSecond(654321, 123456789), bytes);
+    }
+
+    //-----------------------------------------------------------------------
+    private void check(Instant instant, long epochSecs, int nos) {
+        assertEquals(instant.getEpochSecond(), epochSecs);
+        assertEquals(instant.getNano(), nos);
+        assertEquals(instant, instant);
+        assertEquals(instant.hashCode(), instant.hashCode());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void constant_EPOCH() {
+        check(Instant.EPOCH, 0, 0);
+    }
+
+    @Test
+    public void constant_MIN() {
+        check(Instant.MIN, -31557014167219200L, 0);
+    }
+
+    @Test
+    public void constant_MAX() {
+        check(Instant.MAX, 31556889864403199L, 999_999_999);
+    }
+
+    //-----------------------------------------------------------------------
+    // now()
+    //-----------------------------------------------------------------------
+    @Test
+    public void now() {
+        Instant expected = Instant.now(Clock.systemUTC());
+        Instant test = Instant.now();
+        long diff = Math.abs(test.toEpochMilli() - expected.toEpochMilli());
+        assertTrue(diff < 100);  // less than 0.1 secs
+    }
+
+    //-----------------------------------------------------------------------
+    // now(Clock)
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=NullPointerException.class)
+    public void now_Clock_nullClock() {
+        Instant.now(null);
+    }
+
+    @Test
+    public void now_Clock_allSecsInDay_utc() {
+        for (int i = 0; i < (2 * 24 * 60 * 60); i++) {
+            Instant expected = Instant.ofEpochSecond(i).plusNanos(123456789L);
+            Clock clock = Clock.fixed(expected, ZoneOffset.UTC);
+            Instant test = Instant.now(clock);
+            assertEquals(test, expected);
+        }
+    }
+
+    @Test
+    public void now_Clock_allSecsInDay_beforeEpoch() {
+        for (int i =-1; i >= -(24 * 60 * 60); i--) {
+            Instant expected = Instant.ofEpochSecond(i).plusNanos(123456789L);
+            Clock clock = Clock.fixed(expected, ZoneOffset.UTC);
+            Instant test = Instant.now(clock);
+            assertEquals(test, expected);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // ofEpochSecond(long)
+    //-----------------------------------------------------------------------
+    @Test
+    public void factory_seconds_long() {
+        for (long i = -2; i <= 2; i++) {
+            Instant t = Instant.ofEpochSecond(i);
+            assertEquals(t.getEpochSecond(), i);
+            assertEquals(t.getNano(), 0);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // ofEpochSecond(long,long)
+    //-----------------------------------------------------------------------
+    @Test
+    public void factory_seconds_long_long() {
+        for (long i = -2; i <= 2; i++) {
+            for (int j = 0; j < 10; j++) {
+                Instant t = Instant.ofEpochSecond(i, j);
+                assertEquals(t.getEpochSecond(), i);
+                assertEquals(t.getNano(), j);
+            }
+            for (int j = -10; j < 0; j++) {
+                Instant t = Instant.ofEpochSecond(i, j);
+                assertEquals(t.getEpochSecond(), i - 1);
+                assertEquals(t.getNano(), j + 1000000000);
+            }
+            for (int j = 999999990; j < 1000000000; j++) {
+                Instant t = Instant.ofEpochSecond(i, j);
+                assertEquals(t.getEpochSecond(), i);
+                assertEquals(t.getNano(), j);
+            }
+        }
+    }
+
+    @Test
+    public void factory_seconds_long_long_nanosNegativeAdjusted() {
+        Instant test = Instant.ofEpochSecond(2L, -1);
+        assertEquals(test.getEpochSecond(), 1);
+        assertEquals(test.getNano(), 999999999);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class)
+    public void factory_seconds_long_long_tooBig() {
+        Instant.ofEpochSecond(MAX_SECOND, 1000000000);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void factory_seconds_long_long_tooBigBig() {
+        Instant.ofEpochSecond(Long.MAX_VALUE, Long.MAX_VALUE);
+    }
+
+    //-----------------------------------------------------------------------
+    // ofEpochMilli(long)
+    //-----------------------------------------------------------------------
+    @DataProvider(name="MillisInstantNoNanos")
+    Object[][] provider_factory_millis_long() {
+        return new Object[][] {
+                {0, 0, 0},
+                {1, 0, 1000000},
+                {2, 0, 2000000},
+                {999, 0, 999000000},
+                {1000, 1, 0},
+                {1001, 1, 1000000},
+                {-1, -1, 999000000},
+                {-2, -1, 998000000},
+                {-999, -1, 1000000},
+                {-1000, -1, 0},
+                {-1001, -2, 999000000},
+        };
+    }
+
+    @Test(dataProvider="MillisInstantNoNanos")
+    public void factory_millis_long(long millis, long expectedSeconds, int expectedNanoOfSecond) {
+        Instant t = Instant.ofEpochMilli(millis);
+        assertEquals(t.getEpochSecond(), expectedSeconds);
+        assertEquals(t.getNano(), expectedNanoOfSecond);
+    }
+
+    //-----------------------------------------------------------------------
+    // parse(String)
+    //-----------------------------------------------------------------------
+    // see also parse tests under toString()
+    @DataProvider(name="Parse")
+    Object[][] provider_factory_parse() {
+        return new Object[][] {
+                {"1970-01-01T00:00:00Z", 0, 0},
+                {"1970-01-01t00:00:00Z", 0, 0},
+                {"1970-01-01T00:00:00z", 0, 0},
+                {"1970-01-01T00:00:00.0Z", 0, 0},
+                {"1970-01-01T00:00:00.000000000Z", 0, 0},
+
+                {"1970-01-01T00:00:00.000000001Z", 0, 1},
+                {"1970-01-01T00:00:00.100000000Z", 0, 100000000},
+                {"1970-01-01T00:00:01Z", 1, 0},
+                {"1970-01-01T00:01:00Z", 60, 0},
+                {"1970-01-01T00:01:01Z", 61, 0},
+                {"1970-01-01T00:01:01.000000001Z", 61, 1},
+                {"1970-01-01T01:00:00.000000000Z", 3600, 0},
+                {"1970-01-01T01:01:01.000000001Z", 3661, 1},
+                {"1970-01-02T01:01:01.100000000Z", 90061, 100000000},
+        };
+    }
+
+    @Test(dataProvider="Parse")
+    public void factory_parse(String text, long expectedEpochSeconds, int expectedNanoOfSecond) {
+        Instant t = Instant.parse(text);
+        assertEquals(t.getEpochSecond(), expectedEpochSeconds);
+        assertEquals(t.getNano(), expectedNanoOfSecond);
+    }
+
+    @Test(dataProvider="Parse")
+    public void factory_parseLowercase(String text, long expectedEpochSeconds, int expectedNanoOfSecond) {
+        Instant t = Instant.parse(text.toLowerCase(Locale.ENGLISH));
+        assertEquals(t.getEpochSecond(), expectedEpochSeconds);
+        assertEquals(t.getNano(), expectedNanoOfSecond);
+    }
+
+// TODO: should comma be accepted?
+//    @Test(dataProvider="Parse")
+//    public void factory_parse_comma(String text, long expectedEpochSeconds, int expectedNanoOfSecond) {
+//        text = text.replace('.', ',');
+//        Instant t = Instant.parse(text);
+//        assertEquals(t.getEpochSecond(), expectedEpochSeconds);
+//        assertEquals(t.getNano(), expectedNanoOfSecond);
+//    }
+
+    @DataProvider(name="ParseFailures")
+    Object[][] provider_factory_parseFailures() {
+        return new Object[][] {
+                {""},
+                {"Z"},
+                {"1970-01-01T00:00:00"},
+                {"1970-01-01T00:00:0Z"},
+                {"1970-01-01T00:00:00.0000000000Z"},
+        };
+    }
+
+    @Test(dataProvider="ParseFailures", expectedExceptions=DateTimeParseException.class)
+    public void factory_parseFailures(String text) {
+        Instant.parse(text);
+    }
+
+    @Test(dataProvider="ParseFailures", expectedExceptions=DateTimeParseException.class)
+    public void factory_parseFailures_comma(String text) {
+        text = text.replace('.', ',');
+        Instant.parse(text);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void factory_parse_nullText() {
+        Instant.parse(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // get(TemporalField)
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_get_TemporalField() {
+        Instant test = TEST_12345_123456789;
+        assertEquals(test.get(ChronoField.NANO_OF_SECOND), 123456789);
+        assertEquals(test.get(ChronoField.MICRO_OF_SECOND), 123456);
+        assertEquals(test.get(ChronoField.MILLI_OF_SECOND), 123);
+    }
+
+    @Test
+    public void test_getLong_TemporalField() {
+        Instant test = TEST_12345_123456789;
+        assertEquals(test.getLong(ChronoField.NANO_OF_SECOND), 123456789);
+        assertEquals(test.getLong(ChronoField.MICRO_OF_SECOND), 123456);
+        assertEquals(test.getLong(ChronoField.MILLI_OF_SECOND), 123);
+        assertEquals(test.getLong(ChronoField.INSTANT_SECONDS), 12345);
+    }
+
+    //-----------------------------------------------------------------------
+    // query(TemporalQuery)
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_query_chrono() {
+        assertEquals(TEST_12345_123456789.query(Queries.chrono()), null);
+        assertEquals(Queries.chrono().queryFrom(TEST_12345_123456789), null);
+    }
+
+    @Test
+    public void test_query_zoneId() {
+        assertEquals(TEST_12345_123456789.query(Queries.zoneId()), null);
+        assertEquals(Queries.zoneId().queryFrom(TEST_12345_123456789), null);
+    }
+
+    @Test
+    public void test_query_precision() {
+        assertEquals(TEST_12345_123456789.query(Queries.precision()), NANOS);
+        assertEquals(Queries.precision().queryFrom(TEST_12345_123456789), NANOS);
+    }
+
+    @Test
+    public void test_query_offset() {
+        assertEquals(TEST_12345_123456789.query(Queries.offset()), null);
+        assertEquals(Queries.offset().queryFrom(TEST_12345_123456789), null);
+    }
+
+    @Test
+    public void test_query_zone() {
+        assertEquals(TEST_12345_123456789.query(Queries.zone()), null);
+        assertEquals(Queries.zone().queryFrom(TEST_12345_123456789), null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_query_null() {
+        TEST_12345_123456789.query(null);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="Plus")
+    Object[][] provider_plus() {
+        return new Object[][] {
+                {MIN_SECOND, 0, -MIN_SECOND, 0, 0, 0},
+
+                {MIN_SECOND, 0, 1, 0, MIN_SECOND + 1, 0},
+                {MIN_SECOND, 0, 0, 500, MIN_SECOND, 500},
+                {MIN_SECOND, 0, 0, 1000000000, MIN_SECOND + 1, 0},
+
+                {MIN_SECOND + 1, 0, -1, 0, MIN_SECOND, 0},
+                {MIN_SECOND + 1, 0, 0, -500, MIN_SECOND, 999999500},
+                {MIN_SECOND + 1, 0, 0, -1000000000, MIN_SECOND, 0},
+
+                {-4, 666666667, -4, 666666667, -7, 333333334},
+                {-4, 666666667, -3,         0, -7, 666666667},
+                {-4, 666666667, -2,         0, -6, 666666667},
+                {-4, 666666667, -1,         0, -5, 666666667},
+                {-4, 666666667, -1, 333333334, -4,         1},
+                {-4, 666666667, -1, 666666667, -4, 333333334},
+                {-4, 666666667, -1, 999999999, -4, 666666666},
+                {-4, 666666667,  0,         0, -4, 666666667},
+                {-4, 666666667,  0,         1, -4, 666666668},
+                {-4, 666666667,  0, 333333333, -3,         0},
+                {-4, 666666667,  0, 666666666, -3, 333333333},
+                {-4, 666666667,  1,         0, -3, 666666667},
+                {-4, 666666667,  2,         0, -2, 666666667},
+                {-4, 666666667,  3,         0, -1, 666666667},
+                {-4, 666666667,  3, 333333333,  0,         0},
+
+                {-3, 0, -4, 666666667, -7, 666666667},
+                {-3, 0, -3,         0, -6,         0},
+                {-3, 0, -2,         0, -5,         0},
+                {-3, 0, -1,         0, -4,         0},
+                {-3, 0, -1, 333333334, -4, 333333334},
+                {-3, 0, -1, 666666667, -4, 666666667},
+                {-3, 0, -1, 999999999, -4, 999999999},
+                {-3, 0,  0,         0, -3,         0},
+                {-3, 0,  0,         1, -3,         1},
+                {-3, 0,  0, 333333333, -3, 333333333},
+                {-3, 0,  0, 666666666, -3, 666666666},
+                {-3, 0,  1,         0, -2,         0},
+                {-3, 0,  2,         0, -1,         0},
+                {-3, 0,  3,         0,  0,         0},
+                {-3, 0,  3, 333333333,  0, 333333333},
+
+                {-2, 0, -4, 666666667, -6, 666666667},
+                {-2, 0, -3,         0, -5,         0},
+                {-2, 0, -2,         0, -4,         0},
+                {-2, 0, -1,         0, -3,         0},
+                {-2, 0, -1, 333333334, -3, 333333334},
+                {-2, 0, -1, 666666667, -3, 666666667},
+                {-2, 0, -1, 999999999, -3, 999999999},
+                {-2, 0,  0,         0, -2,         0},
+                {-2, 0,  0,         1, -2,         1},
+                {-2, 0,  0, 333333333, -2, 333333333},
+                {-2, 0,  0, 666666666, -2, 666666666},
+                {-2, 0,  1,         0, -1,         0},
+                {-2, 0,  2,         0,  0,         0},
+                {-2, 0,  3,         0,  1,         0},
+                {-2, 0,  3, 333333333,  1, 333333333},
+
+                {-1, 0, -4, 666666667, -5, 666666667},
+                {-1, 0, -3,         0, -4,         0},
+                {-1, 0, -2,         0, -3,         0},
+                {-1, 0, -1,         0, -2,         0},
+                {-1, 0, -1, 333333334, -2, 333333334},
+                {-1, 0, -1, 666666667, -2, 666666667},
+                {-1, 0, -1, 999999999, -2, 999999999},
+                {-1, 0,  0,         0, -1,         0},
+                {-1, 0,  0,         1, -1,         1},
+                {-1, 0,  0, 333333333, -1, 333333333},
+                {-1, 0,  0, 666666666, -1, 666666666},
+                {-1, 0,  1,         0,  0,         0},
+                {-1, 0,  2,         0,  1,         0},
+                {-1, 0,  3,         0,  2,         0},
+                {-1, 0,  3, 333333333,  2, 333333333},
+
+                {-1, 666666667, -4, 666666667, -4, 333333334},
+                {-1, 666666667, -3,         0, -4, 666666667},
+                {-1, 666666667, -2,         0, -3, 666666667},
+                {-1, 666666667, -1,         0, -2, 666666667},
+                {-1, 666666667, -1, 333333334, -1,         1},
+                {-1, 666666667, -1, 666666667, -1, 333333334},
+                {-1, 666666667, -1, 999999999, -1, 666666666},
+                {-1, 666666667,  0,         0, -1, 666666667},
+                {-1, 666666667,  0,         1, -1, 666666668},
+                {-1, 666666667,  0, 333333333,  0,         0},
+                {-1, 666666667,  0, 666666666,  0, 333333333},
+                {-1, 666666667,  1,         0,  0, 666666667},
+                {-1, 666666667,  2,         0,  1, 666666667},
+                {-1, 666666667,  3,         0,  2, 666666667},
+                {-1, 666666667,  3, 333333333,  3,         0},
+
+                {0, 0, -4, 666666667, -4, 666666667},
+                {0, 0, -3,         0, -3,         0},
+                {0, 0, -2,         0, -2,         0},
+                {0, 0, -1,         0, -1,         0},
+                {0, 0, -1, 333333334, -1, 333333334},
+                {0, 0, -1, 666666667, -1, 666666667},
+                {0, 0, -1, 999999999, -1, 999999999},
+                {0, 0,  0,         0,  0,         0},
+                {0, 0,  0,         1,  0,         1},
+                {0, 0,  0, 333333333,  0, 333333333},
+                {0, 0,  0, 666666666,  0, 666666666},
+                {0, 0,  1,         0,  1,         0},
+                {0, 0,  2,         0,  2,         0},
+                {0, 0,  3,         0,  3,         0},
+                {0, 0,  3, 333333333,  3, 333333333},
+
+                {0, 333333333, -4, 666666667, -3,         0},
+                {0, 333333333, -3,         0, -3, 333333333},
+                {0, 333333333, -2,         0, -2, 333333333},
+                {0, 333333333, -1,         0, -1, 333333333},
+                {0, 333333333, -1, 333333334, -1, 666666667},
+                {0, 333333333, -1, 666666667,  0,         0},
+                {0, 333333333, -1, 999999999,  0, 333333332},
+                {0, 333333333,  0,         0,  0, 333333333},
+                {0, 333333333,  0,         1,  0, 333333334},
+                {0, 333333333,  0, 333333333,  0, 666666666},
+                {0, 333333333,  0, 666666666,  0, 999999999},
+                {0, 333333333,  1,         0,  1, 333333333},
+                {0, 333333333,  2,         0,  2, 333333333},
+                {0, 333333333,  3,         0,  3, 333333333},
+                {0, 333333333,  3, 333333333,  3, 666666666},
+
+                {1, 0, -4, 666666667, -3, 666666667},
+                {1, 0, -3,         0, -2,         0},
+                {1, 0, -2,         0, -1,         0},
+                {1, 0, -1,         0,  0,         0},
+                {1, 0, -1, 333333334,  0, 333333334},
+                {1, 0, -1, 666666667,  0, 666666667},
+                {1, 0, -1, 999999999,  0, 999999999},
+                {1, 0,  0,         0,  1,         0},
+                {1, 0,  0,         1,  1,         1},
+                {1, 0,  0, 333333333,  1, 333333333},
+                {1, 0,  0, 666666666,  1, 666666666},
+                {1, 0,  1,         0,  2,         0},
+                {1, 0,  2,         0,  3,         0},
+                {1, 0,  3,         0,  4,         0},
+                {1, 0,  3, 333333333,  4, 333333333},
+
+                {2, 0, -4, 666666667, -2, 666666667},
+                {2, 0, -3,         0, -1,         0},
+                {2, 0, -2,         0,  0,         0},
+                {2, 0, -1,         0,  1,         0},
+                {2, 0, -1, 333333334,  1, 333333334},
+                {2, 0, -1, 666666667,  1, 666666667},
+                {2, 0, -1, 999999999,  1, 999999999},
+                {2, 0,  0,         0,  2,         0},
+                {2, 0,  0,         1,  2,         1},
+                {2, 0,  0, 333333333,  2, 333333333},
+                {2, 0,  0, 666666666,  2, 666666666},
+                {2, 0,  1,         0,  3,         0},
+                {2, 0,  2,         0,  4,         0},
+                {2, 0,  3,         0,  5,         0},
+                {2, 0,  3, 333333333,  5, 333333333},
+
+                {3, 0, -4, 666666667, -1, 666666667},
+                {3, 0, -3,         0,  0,         0},
+                {3, 0, -2,         0,  1,         0},
+                {3, 0, -1,         0,  2,         0},
+                {3, 0, -1, 333333334,  2, 333333334},
+                {3, 0, -1, 666666667,  2, 666666667},
+                {3, 0, -1, 999999999,  2, 999999999},
+                {3, 0,  0,         0,  3,         0},
+                {3, 0,  0,         1,  3,         1},
+                {3, 0,  0, 333333333,  3, 333333333},
+                {3, 0,  0, 666666666,  3, 666666666},
+                {3, 0,  1,         0,  4,         0},
+                {3, 0,  2,         0,  5,         0},
+                {3, 0,  3,         0,  6,         0},
+                {3, 0,  3, 333333333,  6, 333333333},
+
+                {3, 333333333, -4, 666666667,  0,         0},
+                {3, 333333333, -3,         0,  0, 333333333},
+                {3, 333333333, -2,         0,  1, 333333333},
+                {3, 333333333, -1,         0,  2, 333333333},
+                {3, 333333333, -1, 333333334,  2, 666666667},
+                {3, 333333333, -1, 666666667,  3,         0},
+                {3, 333333333, -1, 999999999,  3, 333333332},
+                {3, 333333333,  0,         0,  3, 333333333},
+                {3, 333333333,  0,         1,  3, 333333334},
+                {3, 333333333,  0, 333333333,  3, 666666666},
+                {3, 333333333,  0, 666666666,  3, 999999999},
+                {3, 333333333,  1,         0,  4, 333333333},
+                {3, 333333333,  2,         0,  5, 333333333},
+                {3, 333333333,  3,         0,  6, 333333333},
+                {3, 333333333,  3, 333333333,  6, 666666666},
+
+                {MAX_SECOND - 1, 0, 1, 0, MAX_SECOND, 0},
+                {MAX_SECOND - 1, 0, 0, 500, MAX_SECOND - 1, 500},
+                {MAX_SECOND - 1, 0, 0, 1000000000, MAX_SECOND, 0},
+
+                {MAX_SECOND, 0, -1, 0, MAX_SECOND - 1, 0},
+                {MAX_SECOND, 0, 0, -500, MAX_SECOND - 1, 999999500},
+                {MAX_SECOND, 0, 0, -1000000000, MAX_SECOND - 1, 0},
+
+                {MAX_SECOND, 0, -MAX_SECOND, 0, 0, 0},
+        };
+    }
+
+    @Test(dataProvider="Plus")
+    public void plus_Duration(long seconds, int nanos, long otherSeconds, int otherNanos, long expectedSeconds, int expectedNanoOfSecond) {
+        Instant i = Instant.ofEpochSecond(seconds, nanos).plus(Duration.ofSeconds(otherSeconds, otherNanos));
+        assertEquals(i.getEpochSecond(), expectedSeconds);
+        assertEquals(i.getNano(), expectedNanoOfSecond);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class)
+    public void plus_Duration_overflowTooBig() {
+        Instant i = Instant.ofEpochSecond(MAX_SECOND, 999999999);
+        i.plus(Duration.ofSeconds(0, 1));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class)
+    public void plus_Duration_overflowTooSmall() {
+        Instant i = Instant.ofEpochSecond(MIN_SECOND);
+        i.plus(Duration.ofSeconds(-1, 999999999));
+    }
+
+    //-----------------------------------------------------------------------a
+    @Test(dataProvider="Plus")
+    public void plus_longTemporalUnit(long seconds, int nanos, long otherSeconds, int otherNanos, long expectedSeconds, int expectedNanoOfSecond) {
+        Instant i = Instant.ofEpochSecond(seconds, nanos).plus(otherSeconds, SECONDS).plus(otherNanos, NANOS);
+        assertEquals(i.getEpochSecond(), expectedSeconds);
+        assertEquals(i.getNano(), expectedNanoOfSecond);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class)
+    public void plus_longTemporalUnit_overflowTooBig() {
+        Instant i = Instant.ofEpochSecond(MAX_SECOND, 999999999);
+        i.plus(1, NANOS);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class)
+    public void plus_longTemporalUnit_overflowTooSmall() {
+        Instant i = Instant.ofEpochSecond(MIN_SECOND);
+        i.plus(999999999, NANOS);
+        i.plus(-1, SECONDS);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="PlusSeconds")
+    Object[][] provider_plusSeconds_long() {
+        return new Object[][] {
+                {0, 0, 0, 0, 0},
+                {0, 0, 1, 1, 0},
+                {0, 0, -1, -1, 0},
+                {0, 0, MAX_SECOND, MAX_SECOND, 0},
+                {0, 0, MIN_SECOND, MIN_SECOND, 0},
+                {1, 0, 0, 1, 0},
+                {1, 0, 1, 2, 0},
+                {1, 0, -1, 0, 0},
+                {1, 0, MAX_SECOND - 1, MAX_SECOND, 0},
+                {1, 0, MIN_SECOND, MIN_SECOND + 1, 0},
+                {1, 1, 0, 1, 1},
+                {1, 1, 1, 2, 1},
+                {1, 1, -1, 0, 1},
+                {1, 1, MAX_SECOND - 1, MAX_SECOND, 1},
+                {1, 1, MIN_SECOND, MIN_SECOND + 1, 1},
+                {-1, 1, 0, -1, 1},
+                {-1, 1, 1, 0, 1},
+                {-1, 1, -1, -2, 1},
+                {-1, 1, MAX_SECOND, MAX_SECOND - 1, 1},
+                {-1, 1, MIN_SECOND + 1, MIN_SECOND, 1},
+
+                {MAX_SECOND, 2, -MAX_SECOND, 0, 2},
+                {MIN_SECOND, 2, -MIN_SECOND, 0, 2},
+        };
+    }
+
+    @Test(dataProvider="PlusSeconds")
+    public void plusSeconds_long(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) {
+        Instant t = Instant.ofEpochSecond(seconds, nanos);
+        t = t.plusSeconds(amount);
+        assertEquals(t.getEpochSecond(), expectedSeconds);
+        assertEquals(t.getNano(), expectedNanoOfSecond);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void plusSeconds_long_overflowTooBig() {
+        Instant t = Instant.ofEpochSecond(1, 0);
+        t.plusSeconds(Long.MAX_VALUE);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void plusSeconds_long_overflowTooSmall() {
+        Instant t = Instant.ofEpochSecond(-1, 0);
+        t.plusSeconds(Long.MIN_VALUE);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="PlusMillis")
+    Object[][] provider_plusMillis_long() {
+        return new Object[][] {
+                {0, 0, 0,       0, 0},
+                {0, 0, 1,       0, 1000000},
+                {0, 0, 999,     0, 999000000},
+                {0, 0, 1000,    1, 0},
+                {0, 0, 1001,    1, 1000000},
+                {0, 0, 1999,    1, 999000000},
+                {0, 0, 2000,    2, 0},
+                {0, 0, -1,      -1, 999000000},
+                {0, 0, -999,    -1, 1000000},
+                {0, 0, -1000,   -1, 0},
+                {0, 0, -1001,   -2, 999000000},
+                {0, 0, -1999,   -2, 1000000},
+
+                {0, 1, 0,       0, 1},
+                {0, 1, 1,       0, 1000001},
+                {0, 1, 998,     0, 998000001},
+                {0, 1, 999,     0, 999000001},
+                {0, 1, 1000,    1, 1},
+                {0, 1, 1998,    1, 998000001},
+                {0, 1, 1999,    1, 999000001},
+                {0, 1, 2000,    2, 1},
+                {0, 1, -1,      -1, 999000001},
+                {0, 1, -2,      -1, 998000001},
+                {0, 1, -1000,   -1, 1},
+                {0, 1, -1001,   -2, 999000001},
+
+                {0, 1000000, 0,       0, 1000000},
+                {0, 1000000, 1,       0, 2000000},
+                {0, 1000000, 998,     0, 999000000},
+                {0, 1000000, 999,     1, 0},
+                {0, 1000000, 1000,    1, 1000000},
+                {0, 1000000, 1998,    1, 999000000},
+                {0, 1000000, 1999,    2, 0},
+                {0, 1000000, 2000,    2, 1000000},
+                {0, 1000000, -1,      0, 0},
+                {0, 1000000, -2,      -1, 999000000},
+                {0, 1000000, -999,    -1, 2000000},
+                {0, 1000000, -1000,   -1, 1000000},
+                {0, 1000000, -1001,   -1, 0},
+                {0, 1000000, -1002,   -2, 999000000},
+
+                {0, 999999999, 0,     0, 999999999},
+                {0, 999999999, 1,     1, 999999},
+                {0, 999999999, 999,   1, 998999999},
+                {0, 999999999, 1000,  1, 999999999},
+                {0, 999999999, 1001,  2, 999999},
+                {0, 999999999, -1,    0, 998999999},
+                {0, 999999999, -1000, -1, 999999999},
+                {0, 999999999, -1001, -1, 998999999},
+
+                {0, 0, Long.MAX_VALUE, Long.MAX_VALUE / 1000, (int) (Long.MAX_VALUE % 1000) * 1000000},
+                {0, 0, Long.MIN_VALUE, Long.MIN_VALUE / 1000 - 1, (int) (Long.MIN_VALUE % 1000) * 1000000 + 1000000000},
+        };
+    }
+
+    @Test(dataProvider="PlusMillis")
+    public void plusMillis_long(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) {
+        Instant t = Instant.ofEpochSecond(seconds, nanos);
+        t = t.plusMillis(amount);
+        assertEquals(t.getEpochSecond(), expectedSeconds);
+        assertEquals(t.getNano(), expectedNanoOfSecond);
+    }
+    @Test(dataProvider="PlusMillis")
+    public void plusMillis_long_oneMore(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) {
+        Instant t = Instant.ofEpochSecond(seconds + 1, nanos);
+        t = t.plusMillis(amount);
+        assertEquals(t.getEpochSecond(), expectedSeconds + 1);
+        assertEquals(t.getNano(), expectedNanoOfSecond);
+    }
+    @Test(dataProvider="PlusMillis")
+    public void plusMillis_long_minusOneLess(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) {
+        Instant t = Instant.ofEpochSecond(seconds - 1, nanos);
+        t = t.plusMillis(amount);
+        assertEquals(t.getEpochSecond(), expectedSeconds - 1);
+        assertEquals(t.getNano(), expectedNanoOfSecond);
+    }
+
+    @Test
+    public void plusMillis_long_max() {
+        Instant t = Instant.ofEpochSecond(MAX_SECOND, 998999999);
+        t = t.plusMillis(1);
+        assertEquals(t.getEpochSecond(), MAX_SECOND);
+        assertEquals(t.getNano(), 999999999);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class)
+    public void plusMillis_long_overflowTooBig() {
+        Instant t = Instant.ofEpochSecond(MAX_SECOND, 999000000);
+        t.plusMillis(1);
+    }
+
+    @Test
+    public void plusMillis_long_min() {
+        Instant t = Instant.ofEpochSecond(MIN_SECOND, 1000000);
+        t = t.plusMillis(-1);
+        assertEquals(t.getEpochSecond(), MIN_SECOND);
+        assertEquals(t.getNano(), 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class)
+    public void plusMillis_long_overflowTooSmall() {
+        Instant t = Instant.ofEpochSecond(MIN_SECOND, 0);
+        t.plusMillis(-1);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="PlusNanos")
+    Object[][] provider_plusNanos_long() {
+        return new Object[][] {
+                {0, 0, 0,           0, 0},
+                {0, 0, 1,           0, 1},
+                {0, 0, 999999999,   0, 999999999},
+                {0, 0, 1000000000,  1, 0},
+                {0, 0, 1000000001,  1, 1},
+                {0, 0, 1999999999,  1, 999999999},
+                {0, 0, 2000000000,  2, 0},
+                {0, 0, -1,          -1, 999999999},
+                {0, 0, -999999999,  -1, 1},
+                {0, 0, -1000000000, -1, 0},
+                {0, 0, -1000000001, -2, 999999999},
+                {0, 0, -1999999999, -2, 1},
+
+                {1, 0, 0,           1, 0},
+                {1, 0, 1,           1, 1},
+                {1, 0, 999999999,   1, 999999999},
+                {1, 0, 1000000000,  2, 0},
+                {1, 0, 1000000001,  2, 1},
+                {1, 0, 1999999999,  2, 999999999},
+                {1, 0, 2000000000,  3, 0},
+                {1, 0, -1,          0, 999999999},
+                {1, 0, -999999999,  0, 1},
+                {1, 0, -1000000000, 0, 0},
+                {1, 0, -1000000001, -1, 999999999},
+                {1, 0, -1999999999, -1, 1},
+
+                {-1, 0, 0,           -1, 0},
+                {-1, 0, 1,           -1, 1},
+                {-1, 0, 999999999,   -1, 999999999},
+                {-1, 0, 1000000000,  0, 0},
+                {-1, 0, 1000000001,  0, 1},
+                {-1, 0, 1999999999,  0, 999999999},
+                {-1, 0, 2000000000,  1, 0},
+                {-1, 0, -1,          -2, 999999999},
+                {-1, 0, -999999999,  -2, 1},
+                {-1, 0, -1000000000, -2, 0},
+                {-1, 0, -1000000001, -3, 999999999},
+                {-1, 0, -1999999999, -3, 1},
+
+                {1, 1, 0,           1, 1},
+                {1, 1, 1,           1, 2},
+                {1, 1, 999999998,   1, 999999999},
+                {1, 1, 999999999,   2, 0},
+                {1, 1, 1000000000,  2, 1},
+                {1, 1, 1999999998,  2, 999999999},
+                {1, 1, 1999999999,  3, 0},
+                {1, 1, 2000000000,  3, 1},
+                {1, 1, -1,          1, 0},
+                {1, 1, -2,          0, 999999999},
+                {1, 1, -1000000000, 0, 1},
+                {1, 1, -1000000001, 0, 0},
+                {1, 1, -1000000002, -1, 999999999},
+                {1, 1, -2000000000, -1, 1},
+
+                {1, 999999999, 0,           1, 999999999},
+                {1, 999999999, 1,           2, 0},
+                {1, 999999999, 999999999,   2, 999999998},
+                {1, 999999999, 1000000000,  2, 999999999},
+                {1, 999999999, 1000000001,  3, 0},
+                {1, 999999999, -1,          1, 999999998},
+                {1, 999999999, -1000000000, 0, 999999999},
+                {1, 999999999, -1000000001, 0, 999999998},
+                {1, 999999999, -1999999999, 0, 0},
+                {1, 999999999, -2000000000, -1, 999999999},
+
+                {MAX_SECOND, 0, 999999999, MAX_SECOND, 999999999},
+                {MAX_SECOND - 1, 0, 1999999999, MAX_SECOND, 999999999},
+                {MIN_SECOND, 1, -1, MIN_SECOND, 0},
+                {MIN_SECOND + 1, 1, -1000000001, MIN_SECOND, 0},
+
+                {0, 0, MAX_SECOND, MAX_SECOND / 1000000000, (int) (MAX_SECOND % 1000000000)},
+                {0, 0, MIN_SECOND, MIN_SECOND / 1000000000 - 1, (int) (MIN_SECOND % 1000000000) + 1000000000},
+        };
+    }
+
+    @Test(dataProvider="PlusNanos")
+    public void plusNanos_long(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) {
+        Instant t = Instant.ofEpochSecond(seconds, nanos);
+        t = t.plusNanos(amount);
+        assertEquals(t.getEpochSecond(), expectedSeconds);
+        assertEquals(t.getNano(), expectedNanoOfSecond);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class)
+    public void plusNanos_long_overflowTooBig() {
+        Instant t = Instant.ofEpochSecond(MAX_SECOND, 999999999);
+        t.plusNanos(1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class)
+    public void plusNanos_long_overflowTooSmall() {
+        Instant t = Instant.ofEpochSecond(MIN_SECOND, 0);
+        t.plusNanos(-1);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="Minus")
+    Object[][] provider_minus() {
+        return new Object[][] {
+                {MIN_SECOND, 0, MIN_SECOND, 0, 0, 0},
+
+                {MIN_SECOND, 0, -1, 0, MIN_SECOND + 1, 0},
+                {MIN_SECOND, 0, 0, -500, MIN_SECOND, 500},
+                {MIN_SECOND, 0, 0, -1000000000, MIN_SECOND + 1, 0},
+
+                {MIN_SECOND + 1, 0, 1, 0, MIN_SECOND, 0},
+                {MIN_SECOND + 1, 0, 0, 500, MIN_SECOND, 999999500},
+                {MIN_SECOND + 1, 0, 0, 1000000000, MIN_SECOND, 0},
+
+                {-4, 666666667, -4, 666666667,  0,         0},
+                {-4, 666666667, -3,         0, -1, 666666667},
+                {-4, 666666667, -2,         0, -2, 666666667},
+                {-4, 666666667, -1,         0, -3, 666666667},
+                {-4, 666666667, -1, 333333334, -3, 333333333},
+                {-4, 666666667, -1, 666666667, -3,         0},
+                {-4, 666666667, -1, 999999999, -4, 666666668},
+                {-4, 666666667,  0,         0, -4, 666666667},
+                {-4, 666666667,  0,         1, -4, 666666666},
+                {-4, 666666667,  0, 333333333, -4, 333333334},
+                {-4, 666666667,  0, 666666666, -4,         1},
+                {-4, 666666667,  1,         0, -5, 666666667},
+                {-4, 666666667,  2,         0, -6, 666666667},
+                {-4, 666666667,  3,         0, -7, 666666667},
+                {-4, 666666667,  3, 333333333, -7, 333333334},
+
+                {-3, 0, -4, 666666667,  0, 333333333},
+                {-3, 0, -3,         0,  0,         0},
+                {-3, 0, -2,         0, -1,         0},
+                {-3, 0, -1,         0, -2,         0},
+                {-3, 0, -1, 333333334, -3, 666666666},
+                {-3, 0, -1, 666666667, -3, 333333333},
+                {-3, 0, -1, 999999999, -3,         1},
+                {-3, 0,  0,         0, -3,         0},
+                {-3, 0,  0,         1, -4, 999999999},
+                {-3, 0,  0, 333333333, -4, 666666667},
+                {-3, 0,  0, 666666666, -4, 333333334},
+                {-3, 0,  1,         0, -4,         0},
+                {-3, 0,  2,         0, -5,         0},
+                {-3, 0,  3,         0, -6,         0},
+                {-3, 0,  3, 333333333, -7, 666666667},
+
+                {-2, 0, -4, 666666667,  1, 333333333},
+                {-2, 0, -3,         0,  1,         0},
+                {-2, 0, -2,         0,  0,         0},
+                {-2, 0, -1,         0, -1,         0},
+                {-2, 0, -1, 333333334, -2, 666666666},
+                {-2, 0, -1, 666666667, -2, 333333333},
+                {-2, 0, -1, 999999999, -2,         1},
+                {-2, 0,  0,         0, -2,         0},
+                {-2, 0,  0,         1, -3, 999999999},
+                {-2, 0,  0, 333333333, -3, 666666667},
+                {-2, 0,  0, 666666666, -3, 333333334},
+                {-2, 0,  1,         0, -3,         0},
+                {-2, 0,  2,         0, -4,         0},
+                {-2, 0,  3,         0, -5,         0},
+                {-2, 0,  3, 333333333, -6, 666666667},
+
+                {-1, 0, -4, 666666667,  2, 333333333},
+                {-1, 0, -3,         0,  2,         0},
+                {-1, 0, -2,         0,  1,         0},
+                {-1, 0, -1,         0,  0,         0},
+                {-1, 0, -1, 333333334, -1, 666666666},
+                {-1, 0, -1, 666666667, -1, 333333333},
+                {-1, 0, -1, 999999999, -1,         1},
+                {-1, 0,  0,         0, -1,         0},
+                {-1, 0,  0,         1, -2, 999999999},
+                {-1, 0,  0, 333333333, -2, 666666667},
+                {-1, 0,  0, 666666666, -2, 333333334},
+                {-1, 0,  1,         0, -2,         0},
+                {-1, 0,  2,         0, -3,         0},
+                {-1, 0,  3,         0, -4,         0},
+                {-1, 0,  3, 333333333, -5, 666666667},
+
+                {-1, 666666667, -4, 666666667,  3,         0},
+                {-1, 666666667, -3,         0,  2, 666666667},
+                {-1, 666666667, -2,         0,  1, 666666667},
+                {-1, 666666667, -1,         0,  0, 666666667},
+                {-1, 666666667, -1, 333333334,  0, 333333333},
+                {-1, 666666667, -1, 666666667,  0,         0},
+                {-1, 666666667, -1, 999999999, -1, 666666668},
+                {-1, 666666667,  0,         0, -1, 666666667},
+                {-1, 666666667,  0,         1, -1, 666666666},
+                {-1, 666666667,  0, 333333333, -1, 333333334},
+                {-1, 666666667,  0, 666666666, -1,         1},
+                {-1, 666666667,  1,         0, -2, 666666667},
+                {-1, 666666667,  2,         0, -3, 666666667},
+                {-1, 666666667,  3,         0, -4, 666666667},
+                {-1, 666666667,  3, 333333333, -4, 333333334},
+
+                {0, 0, -4, 666666667,  3, 333333333},
+                {0, 0, -3,         0,  3,         0},
+                {0, 0, -2,         0,  2,         0},
+                {0, 0, -1,         0,  1,         0},
+                {0, 0, -1, 333333334,  0, 666666666},
+                {0, 0, -1, 666666667,  0, 333333333},
+                {0, 0, -1, 999999999,  0,         1},
+                {0, 0,  0,         0,  0,         0},
+                {0, 0,  0,         1, -1, 999999999},
+                {0, 0,  0, 333333333, -1, 666666667},
+                {0, 0,  0, 666666666, -1, 333333334},
+                {0, 0,  1,         0, -1,         0},
+                {0, 0,  2,         0, -2,         0},
+                {0, 0,  3,         0, -3,         0},
+                {0, 0,  3, 333333333, -4, 666666667},
+
+                {0, 333333333, -4, 666666667,  3, 666666666},
+                {0, 333333333, -3,         0,  3, 333333333},
+                {0, 333333333, -2,         0,  2, 333333333},
+                {0, 333333333, -1,         0,  1, 333333333},
+                {0, 333333333, -1, 333333334,  0, 999999999},
+                {0, 333333333, -1, 666666667,  0, 666666666},
+                {0, 333333333, -1, 999999999,  0, 333333334},
+                {0, 333333333,  0,         0,  0, 333333333},
+                {0, 333333333,  0,         1,  0, 333333332},
+                {0, 333333333,  0, 333333333,  0,         0},
+                {0, 333333333,  0, 666666666, -1, 666666667},
+                {0, 333333333,  1,         0, -1, 333333333},
+                {0, 333333333,  2,         0, -2, 333333333},
+                {0, 333333333,  3,         0, -3, 333333333},
+                {0, 333333333,  3, 333333333, -3,         0},
+
+                {1, 0, -4, 666666667,  4, 333333333},
+                {1, 0, -3,         0,  4,         0},
+                {1, 0, -2,         0,  3,         0},
+                {1, 0, -1,         0,  2,         0},
+                {1, 0, -1, 333333334,  1, 666666666},
+                {1, 0, -1, 666666667,  1, 333333333},
+                {1, 0, -1, 999999999,  1,         1},
+                {1, 0,  0,         0,  1,         0},
+                {1, 0,  0,         1,  0, 999999999},
+                {1, 0,  0, 333333333,  0, 666666667},
+                {1, 0,  0, 666666666,  0, 333333334},
+                {1, 0,  1,         0,  0,         0},
+                {1, 0,  2,         0, -1,         0},
+                {1, 0,  3,         0, -2,         0},
+                {1, 0,  3, 333333333, -3, 666666667},
+
+                {2, 0, -4, 666666667,  5, 333333333},
+                {2, 0, -3,         0,  5,         0},
+                {2, 0, -2,         0,  4,         0},
+                {2, 0, -1,         0,  3,         0},
+                {2, 0, -1, 333333334,  2, 666666666},
+                {2, 0, -1, 666666667,  2, 333333333},
+                {2, 0, -1, 999999999,  2,         1},
+                {2, 0,  0,         0,  2,         0},
+                {2, 0,  0,         1,  1, 999999999},
+                {2, 0,  0, 333333333,  1, 666666667},
+                {2, 0,  0, 666666666,  1, 333333334},
+                {2, 0,  1,         0,  1,         0},
+                {2, 0,  2,         0,  0,         0},
+                {2, 0,  3,         0, -1,         0},
+                {2, 0,  3, 333333333, -2, 666666667},
+
+                {3, 0, -4, 666666667,  6, 333333333},
+                {3, 0, -3,         0,  6,         0},
+                {3, 0, -2,         0,  5,         0},
+                {3, 0, -1,         0,  4,         0},
+                {3, 0, -1, 333333334,  3, 666666666},
+                {3, 0, -1, 666666667,  3, 333333333},
+                {3, 0, -1, 999999999,  3,         1},
+                {3, 0,  0,         0,  3,         0},
+                {3, 0,  0,         1,  2, 999999999},
+                {3, 0,  0, 333333333,  2, 666666667},
+                {3, 0,  0, 666666666,  2, 333333334},
+                {3, 0,  1,         0,  2,         0},
+                {3, 0,  2,         0,  1,         0},
+                {3, 0,  3,         0,  0,         0},
+                {3, 0,  3, 333333333, -1, 666666667},
+
+                {3, 333333333, -4, 666666667,  6, 666666666},
+                {3, 333333333, -3,         0,  6, 333333333},
+                {3, 333333333, -2,         0,  5, 333333333},
+                {3, 333333333, -1,         0,  4, 333333333},
+                {3, 333333333, -1, 333333334,  3, 999999999},
+                {3, 333333333, -1, 666666667,  3, 666666666},
+                {3, 333333333, -1, 999999999,  3, 333333334},
+                {3, 333333333,  0,         0,  3, 333333333},
+                {3, 333333333,  0,         1,  3, 333333332},
+                {3, 333333333,  0, 333333333,  3,         0},
+                {3, 333333333,  0, 666666666,  2, 666666667},
+                {3, 333333333,  1,         0,  2, 333333333},
+                {3, 333333333,  2,         0,  1, 333333333},
+                {3, 333333333,  3,         0,  0, 333333333},
+                {3, 333333333,  3, 333333333,  0,         0},
+
+                {MAX_SECOND - 1, 0, -1, 0, MAX_SECOND, 0},
+                {MAX_SECOND - 1, 0, 0, -500, MAX_SECOND - 1, 500},
+                {MAX_SECOND - 1, 0, 0, -1000000000, MAX_SECOND, 0},
+
+                {MAX_SECOND, 0, 1, 0, MAX_SECOND - 1, 0},
+                {MAX_SECOND, 0, 0, 500, MAX_SECOND - 1, 999999500},
+                {MAX_SECOND, 0, 0, 1000000000, MAX_SECOND - 1, 0},
+
+                {MAX_SECOND, 0, MAX_SECOND, 0, 0, 0},
+        };
+    }
+
+    @Test(dataProvider="Minus")
+    public void minus_Duration(long seconds, int nanos, long otherSeconds, int otherNanos, long expectedSeconds, int expectedNanoOfSecond) {
+        Instant i = Instant.ofEpochSecond(seconds, nanos).minus(Duration.ofSeconds(otherSeconds, otherNanos));
+        assertEquals(i.getEpochSecond(), expectedSeconds);
+        assertEquals(i.getNano(), expectedNanoOfSecond);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class)
+    public void minus_Duration_overflowTooSmall() {
+        Instant i = Instant.ofEpochSecond(MIN_SECOND);
+        i.minus(Duration.ofSeconds(0, 1));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class)
+    public void minus_Duration_overflowTooBig() {
+        Instant i = Instant.ofEpochSecond(MAX_SECOND, 999999999);
+        i.minus(Duration.ofSeconds(-1, 999999999));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="Minus")
+    public void minus_longTemporalUnit(long seconds, int nanos, long otherSeconds, int otherNanos, long expectedSeconds, int expectedNanoOfSecond) {
+        Instant i = Instant.ofEpochSecond(seconds, nanos).minus(otherSeconds, SECONDS).minus(otherNanos, NANOS);
+        assertEquals(i.getEpochSecond(), expectedSeconds);
+        assertEquals(i.getNano(), expectedNanoOfSecond);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class)
+    public void minus_longTemporalUnit_overflowTooSmall() {
+        Instant i = Instant.ofEpochSecond(MIN_SECOND);
+        i.minus(1, NANOS);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class)
+    public void minus_longTemporalUnit_overflowTooBig() {
+        Instant i = Instant.ofEpochSecond(MAX_SECOND, 999999999);
+        i.minus(999999999, NANOS);
+        i.minus(-1, SECONDS);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="MinusSeconds")
+    Object[][] provider_minusSeconds_long() {
+        return new Object[][] {
+                {0, 0, 0, 0, 0},
+                {0, 0, 1, -1, 0},
+                {0, 0, -1, 1, 0},
+                {0, 0, -MIN_SECOND, MIN_SECOND, 0},
+                {1, 0, 0, 1, 0},
+                {1, 0, 1, 0, 0},
+                {1, 0, -1, 2, 0},
+                {1, 0, -MIN_SECOND + 1, MIN_SECOND, 0},
+                {1, 1, 0, 1, 1},
+                {1, 1, 1, 0, 1},
+                {1, 1, -1, 2, 1},
+                {1, 1, -MIN_SECOND, MIN_SECOND + 1, 1},
+                {1, 1, -MIN_SECOND + 1, MIN_SECOND, 1},
+                {-1, 1, 0, -1, 1},
+                {-1, 1, 1, -2, 1},
+                {-1, 1, -1, 0, 1},
+                {-1, 1, -MAX_SECOND, MAX_SECOND - 1, 1},
+                {-1, 1, -(MAX_SECOND + 1), MAX_SECOND, 1},
+
+                {MIN_SECOND, 2, MIN_SECOND, 0, 2},
+                {MIN_SECOND + 1, 2, MIN_SECOND, 1, 2},
+                {MAX_SECOND - 1, 2, MAX_SECOND, -1, 2},
+                {MAX_SECOND, 2, MAX_SECOND, 0, 2},
+        };
+    }
+
+    @Test(dataProvider="MinusSeconds")
+    public void minusSeconds_long(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) {
+        Instant i = Instant.ofEpochSecond(seconds, nanos);
+        i = i.minusSeconds(amount);
+        assertEquals(i.getEpochSecond(), expectedSeconds);
+        assertEquals(i.getNano(), expectedNanoOfSecond);
+    }
+
+    @Test(expectedExceptions = {ArithmeticException.class})
+    public void minusSeconds_long_overflowTooBig() {
+        Instant i = Instant.ofEpochSecond(1, 0);
+        i.minusSeconds(Long.MIN_VALUE + 1);
+    }
+
+    @Test(expectedExceptions = {ArithmeticException.class})
+    public void minusSeconds_long_overflowTooSmall() {
+        Instant i = Instant.ofEpochSecond(-2, 0);
+        i.minusSeconds(Long.MAX_VALUE);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="MinusMillis")
+    Object[][] provider_minusMillis_long() {
+        return new Object[][] {
+                {0, 0, 0,       0, 0},
+                {0, 0, 1,      -1, 999000000},
+                {0, 0, 999,    -1, 1000000},
+                {0, 0, 1000,   -1, 0},
+                {0, 0, 1001,   -2, 999000000},
+                {0, 0, 1999,   -2, 1000000},
+                {0, 0, 2000,   -2, 0},
+                {0, 0, -1,      0, 1000000},
+                {0, 0, -999,    0, 999000000},
+                {0, 0, -1000,   1, 0},
+                {0, 0, -1001,   1, 1000000},
+                {0, 0, -1999,   1, 999000000},
+
+                {0, 1, 0,       0, 1},
+                {0, 1, 1,      -1, 999000001},
+                {0, 1, 998,    -1, 2000001},
+                {0, 1, 999,    -1, 1000001},
+                {0, 1, 1000,   -1, 1},
+                {0, 1, 1998,   -2, 2000001},
+                {0, 1, 1999,   -2, 1000001},
+                {0, 1, 2000,   -2, 1},
+                {0, 1, -1,      0, 1000001},
+                {0, 1, -2,      0, 2000001},
+                {0, 1, -1000,   1, 1},
+                {0, 1, -1001,   1, 1000001},
+
+                {0, 1000000, 0,       0, 1000000},
+                {0, 1000000, 1,       0, 0},
+                {0, 1000000, 998,    -1, 3000000},
+                {0, 1000000, 999,    -1, 2000000},
+                {0, 1000000, 1000,   -1, 1000000},
+                {0, 1000000, 1998,   -2, 3000000},
+                {0, 1000000, 1999,   -2, 2000000},
+                {0, 1000000, 2000,   -2, 1000000},
+                {0, 1000000, -1,      0, 2000000},
+                {0, 1000000, -2,      0, 3000000},
+                {0, 1000000, -999,    1, 0},
+                {0, 1000000, -1000,   1, 1000000},
+                {0, 1000000, -1001,   1, 2000000},
+                {0, 1000000, -1002,   1, 3000000},
+
+                {0, 999999999, 0,     0, 999999999},
+                {0, 999999999, 1,     0, 998999999},
+                {0, 999999999, 999,   0, 999999},
+                {0, 999999999, 1000, -1, 999999999},
+                {0, 999999999, 1001, -1, 998999999},
+                {0, 999999999, -1,    1, 999999},
+                {0, 999999999, -1000, 1, 999999999},
+                {0, 999999999, -1001, 2, 999999},
+
+                {0, 0, Long.MAX_VALUE, -(Long.MAX_VALUE / 1000) - 1, (int) -(Long.MAX_VALUE % 1000) * 1000000 + 1000000000},
+                {0, 0, Long.MIN_VALUE, -(Long.MIN_VALUE / 1000), (int) -(Long.MIN_VALUE % 1000) * 1000000},
+        };
+    }
+
+    @Test(dataProvider="MinusMillis")
+    public void minusMillis_long(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) {
+        Instant i = Instant.ofEpochSecond(seconds, nanos);
+        i = i.minusMillis(amount);
+        assertEquals(i.getEpochSecond(), expectedSeconds);
+        assertEquals(i.getNano(), expectedNanoOfSecond);
+    }
+
+    @Test(dataProvider="MinusMillis")
+    public void minusMillis_long_oneMore(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) {
+        Instant i = Instant.ofEpochSecond(seconds + 1, nanos);
+        i = i.minusMillis(amount);
+        assertEquals(i.getEpochSecond(), expectedSeconds + 1);
+        assertEquals(i.getNano(), expectedNanoOfSecond);
+    }
+
+    @Test(dataProvider="MinusMillis")
+    public void minusMillis_long_minusOneLess(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) {
+        Instant i = Instant.ofEpochSecond(seconds - 1, nanos);
+        i = i.minusMillis(amount);
+        assertEquals(i.getEpochSecond(), expectedSeconds - 1);
+        assertEquals(i.getNano(), expectedNanoOfSecond);
+    }
+
+    @Test
+    public void minusMillis_long_max() {
+        Instant i = Instant.ofEpochSecond(MAX_SECOND, 998999999);
+        i = i.minusMillis(-1);
+        assertEquals(i.getEpochSecond(), MAX_SECOND);
+        assertEquals(i.getNano(), 999999999);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class)
+    public void minusMillis_long_overflowTooBig() {
+        Instant i = Instant.ofEpochSecond(MAX_SECOND, 999000000);
+        i.minusMillis(-1);
+    }
+
+    @Test
+    public void minusMillis_long_min() {
+        Instant i = Instant.ofEpochSecond(MIN_SECOND, 1000000);
+        i = i.minusMillis(1);
+        assertEquals(i.getEpochSecond(), MIN_SECOND);
+        assertEquals(i.getNano(), 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class)
+    public void minusMillis_long_overflowTooSmall() {
+        Instant i = Instant.ofEpochSecond(MIN_SECOND, 0);
+        i.minusMillis(1);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="MinusNanos")
+    Object[][] provider_minusNanos_long() {
+        return new Object[][] {
+                {0, 0, 0,           0, 0},
+                {0, 0, 1,          -1, 999999999},
+                {0, 0, 999999999,  -1, 1},
+                {0, 0, 1000000000, -1, 0},
+                {0, 0, 1000000001, -2, 999999999},
+                {0, 0, 1999999999, -2, 1},
+                {0, 0, 2000000000, -2, 0},
+                {0, 0, -1,          0, 1},
+                {0, 0, -999999999,  0, 999999999},
+                {0, 0, -1000000000, 1, 0},
+                {0, 0, -1000000001, 1, 1},
+                {0, 0, -1999999999, 1, 999999999},
+
+                {1, 0, 0,            1, 0},
+                {1, 0, 1,            0, 999999999},
+                {1, 0, 999999999,    0, 1},
+                {1, 0, 1000000000,   0, 0},
+                {1, 0, 1000000001,  -1, 999999999},
+                {1, 0, 1999999999,  -1, 1},
+                {1, 0, 2000000000,  -1, 0},
+                {1, 0, -1,           1, 1},
+                {1, 0, -999999999,   1, 999999999},
+                {1, 0, -1000000000,  2, 0},
+                {1, 0, -1000000001,  2, 1},
+                {1, 0, -1999999999,  2, 999999999},
+
+                {-1, 0, 0,           -1, 0},
+                {-1, 0, 1,           -2, 999999999},
+                {-1, 0, 999999999,   -2, 1},
+                {-1, 0, 1000000000,  -2, 0},
+                {-1, 0, 1000000001,  -3, 999999999},
+                {-1, 0, 1999999999,  -3, 1},
+                {-1, 0, 2000000000,  -3, 0},
+                {-1, 0, -1,          -1, 1},
+                {-1, 0, -999999999,  -1, 999999999},
+                {-1, 0, -1000000000,  0, 0},
+                {-1, 0, -1000000001,  0, 1},
+                {-1, 0, -1999999999,  0, 999999999},
+
+                {1, 1, 0,           1, 1},
+                {1, 1, 1,           1, 0},
+                {1, 1, 999999998,   0, 3},
+                {1, 1, 999999999,   0, 2},
+                {1, 1, 1000000000,  0, 1},
+                {1, 1, 1999999998, -1, 3},
+                {1, 1, 1999999999, -1, 2},
+                {1, 1, 2000000000, -1, 1},
+                {1, 1, -1,          1, 2},
+                {1, 1, -2,          1, 3},
+                {1, 1, -1000000000, 2, 1},
+                {1, 1, -1000000001, 2, 2},
+                {1, 1, -1000000002, 2, 3},
+                {1, 1, -2000000000, 3, 1},
+
+                {1, 999999999, 0,           1, 999999999},
+                {1, 999999999, 1,           1, 999999998},
+                {1, 999999999, 999999999,   1, 0},
+                {1, 999999999, 1000000000,  0, 999999999},
+                {1, 999999999, 1000000001,  0, 999999998},
+                {1, 999999999, -1,          2, 0},
+                {1, 999999999, -1000000000, 2, 999999999},
+                {1, 999999999, -1000000001, 3, 0},
+                {1, 999999999, -1999999999, 3, 999999998},
+                {1, 999999999, -2000000000, 3, 999999999},
+
+                {MAX_SECOND, 0, -999999999, MAX_SECOND, 999999999},
+                {MAX_SECOND - 1, 0, -1999999999, MAX_SECOND, 999999999},
+                {MIN_SECOND, 1, 1, MIN_SECOND, 0},
+                {MIN_SECOND + 1, 1, 1000000001, MIN_SECOND, 0},
+
+                {0, 0, Long.MAX_VALUE, -(Long.MAX_VALUE / 1000000000) - 1, (int) -(Long.MAX_VALUE % 1000000000) + 1000000000},
+                {0, 0, Long.MIN_VALUE, -(Long.MIN_VALUE / 1000000000), (int) -(Long.MIN_VALUE % 1000000000)},
+        };
+    }
+
+    @Test(dataProvider="MinusNanos")
+    public void minusNanos_long(long seconds, int nanos, long amount, long expectedSeconds, int expectedNanoOfSecond) {
+        Instant i = Instant.ofEpochSecond(seconds, nanos);
+        i = i.minusNanos(amount);
+        assertEquals(i.getEpochSecond(), expectedSeconds);
+        assertEquals(i.getNano(), expectedNanoOfSecond);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class)
+    public void minusNanos_long_overflowTooBig() {
+        Instant i = Instant.ofEpochSecond(MAX_SECOND, 999999999);
+        i.minusNanos(-1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class)
+    public void minusNanos_long_overflowTooSmall() {
+        Instant i = Instant.ofEpochSecond(MIN_SECOND, 0);
+        i.minusNanos(1);
+    }
+
+    //-----------------------------------------------------------------------
+    // toEpochMilli()
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_toEpochMilli() {
+        assertEquals(Instant.ofEpochSecond(1L, 1000000).toEpochMilli(), 1001L);
+        assertEquals(Instant.ofEpochSecond(1L, 2000000).toEpochMilli(), 1002L);
+        assertEquals(Instant.ofEpochSecond(1L, 567).toEpochMilli(), 1000L);
+        assertEquals(Instant.ofEpochSecond(Long.MAX_VALUE / 1000).toEpochMilli(), (Long.MAX_VALUE / 1000) * 1000);
+        assertEquals(Instant.ofEpochSecond(Long.MIN_VALUE / 1000).toEpochMilli(), (Long.MIN_VALUE / 1000) * 1000);
+        assertEquals(Instant.ofEpochSecond(0L, -1000000).toEpochMilli(), -1L);
+        assertEquals(Instant.ofEpochSecond(0L, 1000000).toEpochMilli(), 1);
+        assertEquals(Instant.ofEpochSecond(0L, 999999).toEpochMilli(), 0);
+        assertEquals(Instant.ofEpochSecond(0L, 1).toEpochMilli(), 0);
+        assertEquals(Instant.ofEpochSecond(0L, 0).toEpochMilli(), 0);
+        assertEquals(Instant.ofEpochSecond(0L, -1).toEpochMilli(), -1L);
+        assertEquals(Instant.ofEpochSecond(0L, -999999).toEpochMilli(), -1L);
+        assertEquals(Instant.ofEpochSecond(0L, -1000000).toEpochMilli(), -1L);
+        assertEquals(Instant.ofEpochSecond(0L, -1000001).toEpochMilli(), -2L);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_toEpochMilli_tooBig() {
+        Instant.ofEpochSecond(Long.MAX_VALUE / 1000 + 1).toEpochMilli();
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_toEpochMilli_tooSmall() {
+        Instant.ofEpochSecond(Long.MIN_VALUE / 1000 - 1).toEpochMilli();
+    }
+
+    //-----------------------------------------------------------------------
+    // compareTo()
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_comparisons() {
+        doTest_comparisons_Instant(
+                Instant.ofEpochSecond(-2L, 0),
+                Instant.ofEpochSecond(-2L, 999999998),
+                Instant.ofEpochSecond(-2L, 999999999),
+                Instant.ofEpochSecond(-1L, 0),
+                Instant.ofEpochSecond(-1L, 1),
+                Instant.ofEpochSecond(-1L, 999999998),
+                Instant.ofEpochSecond(-1L, 999999999),
+                Instant.ofEpochSecond(0L, 0),
+                Instant.ofEpochSecond(0L, 1),
+                Instant.ofEpochSecond(0L, 2),
+                Instant.ofEpochSecond(0L, 999999999),
+                Instant.ofEpochSecond(1L, 0),
+                Instant.ofEpochSecond(2L, 0)
+        );
+    }
+
+    void doTest_comparisons_Instant(Instant... instants) {
+        for (int i = 0; i < instants.length; i++) {
+            Instant a = instants[i];
+            for (int j = 0; j < instants.length; j++) {
+                Instant b = instants[j];
+                if (i < j) {
+                    assertEquals(a.compareTo(b) < 0, true, a + " <=> " + b);
+                    assertEquals(a.isBefore(b), true, a + " <=> " + b);
+                    assertEquals(a.isAfter(b), false, a + " <=> " + b);
+                    assertEquals(a.equals(b), false, a + " <=> " + b);
+                } else if (i > j) {
+                    assertEquals(a.compareTo(b) > 0, true, a + " <=> " + b);
+                    assertEquals(a.isBefore(b), false, a + " <=> " + b);
+                    assertEquals(a.isAfter(b), true, a + " <=> " + b);
+                    assertEquals(a.equals(b), false, a + " <=> " + b);
+                } else {
+                    assertEquals(a.compareTo(b), 0, a + " <=> " + b);
+                    assertEquals(a.isBefore(b), false, a + " <=> " + b);
+                    assertEquals(a.isAfter(b), false, a + " <=> " + b);
+                    assertEquals(a.equals(b), true, a + " <=> " + b);
+                }
+            }
+        }
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_compareTo_ObjectNull() {
+        Instant a = Instant.ofEpochSecond(0L, 0);
+        a.compareTo(null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_isBefore_ObjectNull() {
+        Instant a = Instant.ofEpochSecond(0L, 0);
+        a.isBefore(null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_isAfter_ObjectNull() {
+        Instant a = Instant.ofEpochSecond(0L, 0);
+        a.isAfter(null);
+    }
+
+    @Test(expectedExceptions=ClassCastException.class)
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public void compareToNonInstant() {
+        Comparable c = Instant.ofEpochSecond(0L);
+        c.compareTo(new Object());
+    }
+
+    //-----------------------------------------------------------------------
+    // equals()
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_equals() {
+        Instant test5a = Instant.ofEpochSecond(5L, 20);
+        Instant test5b = Instant.ofEpochSecond(5L, 20);
+        Instant test5n = Instant.ofEpochSecond(5L, 30);
+        Instant test6 = Instant.ofEpochSecond(6L, 20);
+
+        assertEquals(test5a.equals(test5a), true);
+        assertEquals(test5a.equals(test5b), true);
+        assertEquals(test5a.equals(test5n), false);
+        assertEquals(test5a.equals(test6), false);
+
+        assertEquals(test5b.equals(test5a), true);
+        assertEquals(test5b.equals(test5b), true);
+        assertEquals(test5b.equals(test5n), false);
+        assertEquals(test5b.equals(test6), false);
+
+        assertEquals(test5n.equals(test5a), false);
+        assertEquals(test5n.equals(test5b), false);
+        assertEquals(test5n.equals(test5n), true);
+        assertEquals(test5n.equals(test6), false);
+
+        assertEquals(test6.equals(test5a), false);
+        assertEquals(test6.equals(test5b), false);
+        assertEquals(test6.equals(test5n), false);
+        assertEquals(test6.equals(test6), true);
+    }
+
+    @Test
+    public void test_equals_null() {
+        Instant test5 = Instant.ofEpochSecond(5L, 20);
+        assertEquals(test5.equals(null), false);
+    }
+
+    @Test
+    public void test_equals_otherClass() {
+        Instant test5 = Instant.ofEpochSecond(5L, 20);
+        assertEquals(test5.equals(""), false);
+    }
+
+    //-----------------------------------------------------------------------
+    // hashCode()
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_hashCode() {
+        Instant test5a = Instant.ofEpochSecond(5L, 20);
+        Instant test5b = Instant.ofEpochSecond(5L, 20);
+        Instant test5n = Instant.ofEpochSecond(5L, 30);
+        Instant test6 = Instant.ofEpochSecond(6L, 20);
+
+        assertEquals(test5a.hashCode() == test5a.hashCode(), true);
+        assertEquals(test5a.hashCode() == test5b.hashCode(), true);
+        assertEquals(test5b.hashCode() == test5b.hashCode(), true);
+
+        assertEquals(test5a.hashCode() == test5n.hashCode(), false);
+        assertEquals(test5a.hashCode() == test6.hashCode(), false);
+    }
+
+    //-----------------------------------------------------------------------
+    // toString()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="toStringParse")
+    Object[][] data_toString() {
+        return new Object[][] {
+                {Instant.ofEpochSecond(65L, 567), "1970-01-01T00:01:05.000000567Z"},
+                {Instant.ofEpochSecond(1, 0), "1970-01-01T00:00:01Z"},
+                {Instant.ofEpochSecond(60, 0), "1970-01-01T00:01Z"},
+                {Instant.ofEpochSecond(3600, 0), "1970-01-01T01:00Z"},
+                {Instant.ofEpochSecond(-1, 0), "1969-12-31T23:59:59Z"},
+
+                {LocalDateTime.of(0, 1, 2, 0, 0).toInstant(ZoneOffset.UTC), "0000-01-02T00:00Z"},
+                {LocalDateTime.of(0, 1, 1, 12, 30).toInstant(ZoneOffset.UTC), "0000-01-01T12:30Z"},
+                {LocalDateTime.of(0, 1, 1, 0, 0, 0, 1).toInstant(ZoneOffset.UTC), "0000-01-01T00:00:00.000000001Z"},
+                {LocalDateTime.of(0, 1, 1, 0, 0).toInstant(ZoneOffset.UTC), "0000-01-01T00:00Z"},
+
+                {LocalDateTime.of(-1, 12, 31, 23, 59, 59, 999_999_999).toInstant(ZoneOffset.UTC), "-0001-12-31T23:59:59.999999999Z"},
+                {LocalDateTime.of(-1, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "-0001-12-31T12:30Z"},
+                {LocalDateTime.of(-1, 12, 30, 12, 30).toInstant(ZoneOffset.UTC), "-0001-12-30T12:30Z"},
+
+                {LocalDateTime.of(-9999, 1, 2, 12, 30).toInstant(ZoneOffset.UTC), "-9999-01-02T12:30Z"},
+                {LocalDateTime.of(-9999, 1, 1, 12, 30).toInstant(ZoneOffset.UTC), "-9999-01-01T12:30Z"},
+                {LocalDateTime.of(-9999, 1, 1, 0, 0).toInstant(ZoneOffset.UTC), "-9999-01-01T00:00Z"},
+
+                {LocalDateTime.of(-10000, 12, 31, 23, 59, 59, 999_999_999).toInstant(ZoneOffset.UTC), "-10000-12-31T23:59:59.999999999Z"},
+                {LocalDateTime.of(-10000, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "-10000-12-31T12:30Z"},
+                {LocalDateTime.of(-10000, 12, 30, 12, 30).toInstant(ZoneOffset.UTC), "-10000-12-30T12:30Z"},
+                {LocalDateTime.of(-15000, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "-15000-12-31T12:30Z"},
+
+                {LocalDateTime.of(-19999, 1, 2, 12, 30).toInstant(ZoneOffset.UTC), "-19999-01-02T12:30Z"},
+                {LocalDateTime.of(-19999, 1, 1, 12, 30).toInstant(ZoneOffset.UTC), "-19999-01-01T12:30Z"},
+                {LocalDateTime.of(-19999, 1, 1, 0, 0).toInstant(ZoneOffset.UTC), "-19999-01-01T00:00Z"},
+
+                {LocalDateTime.of(-20000, 12, 31, 23, 59, 59, 999_999_999).toInstant(ZoneOffset.UTC), "-20000-12-31T23:59:59.999999999Z"},
+                {LocalDateTime.of(-20000, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "-20000-12-31T12:30Z"},
+                {LocalDateTime.of(-20000, 12, 30, 12, 30).toInstant(ZoneOffset.UTC), "-20000-12-30T12:30Z"},
+                {LocalDateTime.of(-25000, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "-25000-12-31T12:30Z"},
+
+                {LocalDateTime.of(9999, 12, 30, 12, 30).toInstant(ZoneOffset.UTC), "9999-12-30T12:30Z"},
+                {LocalDateTime.of(9999, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "9999-12-31T12:30Z"},
+                {LocalDateTime.of(9999, 12, 31, 23, 59, 59, 999_999_999).toInstant(ZoneOffset.UTC), "9999-12-31T23:59:59.999999999Z"},
+
+                {LocalDateTime.of(10000, 1, 1, 0, 0).toInstant(ZoneOffset.UTC), "+10000-01-01T00:00Z"},
+                {LocalDateTime.of(10000, 1, 1, 12, 30).toInstant(ZoneOffset.UTC), "+10000-01-01T12:30Z"},
+                {LocalDateTime.of(10000, 1, 2, 12, 30).toInstant(ZoneOffset.UTC), "+10000-01-02T12:30Z"},
+                {LocalDateTime.of(15000, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "+15000-12-31T12:30Z"},
+
+                {LocalDateTime.of(19999, 12, 30, 12, 30).toInstant(ZoneOffset.UTC), "+19999-12-30T12:30Z"},
+                {LocalDateTime.of(19999, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "+19999-12-31T12:30Z"},
+                {LocalDateTime.of(19999, 12, 31, 23, 59, 59, 999_999_999).toInstant(ZoneOffset.UTC), "+19999-12-31T23:59:59.999999999Z"},
+
+                {LocalDateTime.of(20000, 1, 1, 0, 0).toInstant(ZoneOffset.UTC), "+20000-01-01T00:00Z"},
+                {LocalDateTime.of(20000, 1, 1, 12, 30).toInstant(ZoneOffset.UTC), "+20000-01-01T12:30Z"},
+                {LocalDateTime.of(20000, 1, 2, 12, 30).toInstant(ZoneOffset.UTC), "+20000-01-02T12:30Z"},
+                {LocalDateTime.of(25000, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "+25000-12-31T12:30Z"},
+
+                {LocalDateTime.of(-999_999_999, 1, 1, 12, 30).toInstant(ZoneOffset.UTC).minus(1, DAYS), "-1000000000-12-31T12:30Z"},
+                {LocalDateTime.of(999_999_999, 12, 31, 12, 30).toInstant(ZoneOffset.UTC).plus(1, DAYS), "+1000000000-01-01T12:30Z"},
+
+                {Instant.MIN, "-1000000000-01-01T00:00Z"},
+                {Instant.MAX, "+1000000000-12-31T23:59:59.999999999Z"},
+        };
+    }
+
+    @Test(dataProvider="toStringParse")
+    public void test_toString(Instant instant, String expected) {
+        assertEquals(instant.toString(), expected);
+    }
+
+    @Test(dataProvider="toStringParse")
+    public void test_parse(Instant instant, String text) {
+        assertEquals(Instant.parse(text), instant);
+    }
+
+    @Test(dataProvider="toStringParse")
+    public void test_parseLowercase(Instant instant, String text) {
+        assertEquals(Instant.parse(text.toLowerCase(Locale.ENGLISH)), instant);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/TCKLocalDate.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,2018 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time;
+
+import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH;
+import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR;
+import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH;
+import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR;
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.DAY_OF_WEEK;
+import static java.time.temporal.ChronoField.DAY_OF_YEAR;
+import static java.time.temporal.ChronoField.EPOCH_DAY;
+import static java.time.temporal.ChronoField.EPOCH_MONTH;
+import static java.time.temporal.ChronoField.ERA;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.YEAR;
+import static java.time.temporal.ChronoField.YEAR_OF_ERA;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.DayOfWeek;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.Month;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatters;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.ISOChrono;
+import java.time.temporal.JulianFields;
+import java.time.temporal.OffsetDate;
+import java.time.temporal.Queries;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.Year;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import test.java.time.MockSimplePeriod;
+import test.java.time.temporal.MockFieldNoValue;
+
+/**
+ * Test LocalDate.
+ */
+@Test
+public class TCKLocalDate extends AbstractDateTimeTest {
+
+    private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1);
+    private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2);
+    private static final ZoneId ZONE_PARIS = ZoneId.of("Europe/Paris");
+    private static final ZoneId ZONE_GAZA = ZoneId.of("Asia/Gaza");
+
+    private LocalDate TEST_2007_07_15;
+    private long MAX_VALID_EPOCHDAYS;
+    private long MIN_VALID_EPOCHDAYS;
+    private LocalDate MAX_DATE;
+    private LocalDate MIN_DATE;
+    private Instant MAX_INSTANT;
+    private Instant MIN_INSTANT;
+
+    @BeforeMethod(groups={"tck", "implementation"})
+    public void setUp() {
+        TEST_2007_07_15 = LocalDate.of(2007, 7, 15);
+
+        LocalDate max = LocalDate.MAX;
+        LocalDate min = LocalDate.MIN;
+        MAX_VALID_EPOCHDAYS = max.toEpochDay();
+        MIN_VALID_EPOCHDAYS = min.toEpochDay();
+        MAX_DATE = max;
+        MIN_DATE = min;
+        MAX_INSTANT = max.atStartOfDay(ZoneOffset.UTC).toInstant();
+        MIN_INSTANT = min.atStartOfDay(ZoneOffset.UTC).toInstant();
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    protected List<TemporalAccessor> samples() {
+        TemporalAccessor[] array = {TEST_2007_07_15, LocalDate.MAX, LocalDate.MIN, };
+        return Arrays.asList(array);
+    }
+
+    @Override
+    protected List<TemporalField> validFields() {
+        TemporalField[] array = {
+            DAY_OF_WEEK,
+            ALIGNED_DAY_OF_WEEK_IN_MONTH,
+            ALIGNED_DAY_OF_WEEK_IN_YEAR,
+            DAY_OF_MONTH,
+            DAY_OF_YEAR,
+            EPOCH_DAY,
+            ALIGNED_WEEK_OF_MONTH,
+            ALIGNED_WEEK_OF_YEAR,
+            MONTH_OF_YEAR,
+            EPOCH_MONTH,
+            YEAR_OF_ERA,
+            YEAR,
+            ERA,
+            JulianFields.JULIAN_DAY,
+            JulianFields.MODIFIED_JULIAN_DAY,
+            JulianFields.RATA_DIE,
+        };
+        return Arrays.asList(array);
+    }
+
+    @Override
+    protected List<TemporalField> invalidFields() {
+        List<TemporalField> list = new ArrayList<>(Arrays.<TemporalField>asList(ChronoField.values()));
+        list.removeAll(validFields());
+        return list;
+    }
+
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_serialization() throws Exception {
+        assertSerializable(TEST_2007_07_15);
+        assertSerializable(LocalDate.MIN);
+        assertSerializable(LocalDate.MAX);
+    }
+
+    @Test
+    public void test_serialization_format() throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try (DataOutputStream dos = new DataOutputStream(baos) ) {
+            dos.writeByte(3);
+            dos.writeInt(2012);
+            dos.writeByte(9);
+            dos.writeByte(16);
+        }
+        byte[] bytes = baos.toByteArray();
+        assertSerializedBySer(LocalDate.of(2012, 9, 16), bytes);
+    }
+
+    //-----------------------------------------------------------------------
+    private void check(LocalDate test, int y, int m, int d) {
+        assertEquals(test.getYear(), y);
+        assertEquals(test.getMonth().getValue(), m);
+        assertEquals(test.getDayOfMonth(), d);
+        assertEquals(test, test);
+        assertEquals(test.hashCode(), test.hashCode());
+        assertEquals(LocalDate.of(y, m, d), test);
+    }
+
+    //-----------------------------------------------------------------------
+    // constants
+    //-----------------------------------------------------------------------
+    @Test
+    public void constant_MIN() {
+        check(LocalDate.MIN, Year.MIN_VALUE, 1, 1);
+    }
+
+    @Test
+    public void constant_MAX() {
+        check(LocalDate.MAX, Year.MAX_VALUE, 12, 31);
+    }
+
+    //-----------------------------------------------------------------------
+    // now()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void now() {
+        LocalDate expected = LocalDate.now(Clock.systemDefaultZone());
+        LocalDate test = LocalDate.now();
+        for (int i = 0; i < 100; i++) {
+            if (expected.equals(test)) {
+                return;
+            }
+            expected = LocalDate.now(Clock.systemDefaultZone());
+            test = LocalDate.now();
+        }
+        assertEquals(test, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // now(ZoneId)
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void now_ZoneId_nullZoneId() {
+        LocalDate.now((ZoneId) null);
+    }
+
+    @Test(groups={"tck"})
+    public void now_ZoneId() {
+        ZoneId zone = ZoneId.of("UTC+01:02:03");
+        LocalDate expected = LocalDate.now(Clock.system(zone));
+        LocalDate test = LocalDate.now(zone);
+        for (int i = 0; i < 100; i++) {
+            if (expected.equals(test)) {
+                return;
+            }
+            expected = LocalDate.now(Clock.system(zone));
+            test = LocalDate.now(zone);
+        }
+        assertEquals(test, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // now(Clock)
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void now_Clock_nullClock() {
+        LocalDate.now((Clock) null);
+    }
+
+    @Test(groups={"tck"})
+    public void now_Clock_allSecsInDay_utc() {
+        for (int i = 0; i < (2 * 24 * 60 * 60); i++) {
+            Instant instant = Instant.ofEpochSecond(i);
+            Clock clock = Clock.fixed(instant, ZoneOffset.UTC);
+            LocalDate test = LocalDate.now(clock);
+            assertEquals(test.getYear(), 1970);
+            assertEquals(test.getMonth(), Month.JANUARY);
+            assertEquals(test.getDayOfMonth(), (i < 24 * 60 * 60 ? 1 : 2));
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void now_Clock_allSecsInDay_offset() {
+        for (int i = 0; i < (2 * 24 * 60 * 60); i++) {
+            Instant instant = Instant.ofEpochSecond(i);
+            Clock clock = Clock.fixed(instant.minusSeconds(OFFSET_PONE.getTotalSeconds()), OFFSET_PONE);
+            LocalDate test = LocalDate.now(clock);
+            assertEquals(test.getYear(), 1970);
+            assertEquals(test.getMonth(), Month.JANUARY);
+            assertEquals(test.getDayOfMonth(), (i < 24 * 60 * 60) ? 1 : 2);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void now_Clock_allSecsInDay_beforeEpoch() {
+        for (int i =-1; i >= -(2 * 24 * 60 * 60); i--) {
+            Instant instant = Instant.ofEpochSecond(i);
+            Clock clock = Clock.fixed(instant, ZoneOffset.UTC);
+            LocalDate test = LocalDate.now(clock);
+            assertEquals(test.getYear(), 1969);
+            assertEquals(test.getMonth(), Month.DECEMBER);
+            assertEquals(test.getDayOfMonth(), (i >= -24 * 60 * 60 ? 31 : 30));
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void now_Clock_maxYear() {
+        Clock clock = Clock.fixed(MAX_INSTANT, ZoneOffset.UTC);
+        LocalDate test = LocalDate.now(clock);
+        assertEquals(test, MAX_DATE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void now_Clock_tooBig() {
+        Clock clock = Clock.fixed(MAX_INSTANT.plusSeconds(24 * 60 * 60), ZoneOffset.UTC);
+        LocalDate.now(clock);
+    }
+
+    @Test(groups={"tck"})
+    public void now_Clock_minYear() {
+        Clock clock = Clock.fixed(MIN_INSTANT, ZoneOffset.UTC);
+        LocalDate test = LocalDate.now(clock);
+        assertEquals(test, MIN_DATE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void now_Clock_tooLow() {
+        Clock clock = Clock.fixed(MIN_INSTANT.minusNanos(1), ZoneOffset.UTC);
+        LocalDate.now(clock);
+    }
+
+    //-----------------------------------------------------------------------
+    // of() factories
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_of_intsMonth() {
+        assertEquals(TEST_2007_07_15, LocalDate.of(2007, Month.JULY, 15));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_intsMonth_29febNonLeap() {
+        LocalDate.of(2007, Month.FEBRUARY, 29);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_intsMonth_31apr() {
+        LocalDate.of(2007, Month.APRIL, 31);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_intsMonth_dayTooLow() {
+        LocalDate.of(2007, Month.JANUARY, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_intsMonth_dayTooHigh() {
+        LocalDate.of(2007, Month.JANUARY, 32);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_of_intsMonth_nullMonth() {
+        LocalDate.of(2007, null, 30);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_intsMonth_yearTooLow() {
+        LocalDate.of(Integer.MIN_VALUE, Month.JANUARY, 1);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_of_ints() {
+        check(TEST_2007_07_15, 2007, 7, 15);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_ints_29febNonLeap() {
+        LocalDate.of(2007, 2, 29);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_ints_31apr() {
+        LocalDate.of(2007, 4, 31);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_ints_dayTooLow() {
+        LocalDate.of(2007, 1, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_ints_dayTooHigh() {
+        LocalDate.of(2007, 1, 32);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_ints_monthTooLow() {
+        LocalDate.of(2007, 0, 1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_ints_monthTooHigh() {
+        LocalDate.of(2007, 13, 1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_ints_yearTooLow() {
+        LocalDate.of(Integer.MIN_VALUE, 1, 1);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_ofYearDay_ints_nonLeap() {
+        LocalDate date = LocalDate.of(2007, 1, 1);
+        for (int i = 1; i < 365; i++) {
+            assertEquals(LocalDate.ofYearDay(2007, i), date);
+            date = next(date);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void factory_ofYearDay_ints_leap() {
+        LocalDate date = LocalDate.of(2008, 1, 1);
+        for (int i = 1; i < 366; i++) {
+            assertEquals(LocalDate.ofYearDay(2008, i), date);
+            date = next(date);
+        }
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_ofYearDay_ints_366nonLeap() {
+        LocalDate.ofYearDay(2007, 366);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_ofYearDay_ints_dayTooLow() {
+        LocalDate.ofYearDay(2007, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_ofYearDay_ints_dayTooHigh() {
+        LocalDate.ofYearDay(2007, 367);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_ofYearDay_ints_yearTooLow() {
+        LocalDate.ofYearDay(Integer.MIN_VALUE, 1);
+    }
+
+    //-----------------------------------------------------------------------
+    // Since plusDays/minusDays actually depends on MJDays, it cannot be used for testing
+    private LocalDate next(LocalDate date) {
+        int newDayOfMonth = date.getDayOfMonth() + 1;
+        if (newDayOfMonth <= date.getMonth().length(isIsoLeap(date.getYear()))) {
+            return date.withDayOfMonth(newDayOfMonth);
+        }
+        date = date.withDayOfMonth(1);
+        if (date.getMonth() == Month.DECEMBER) {
+            date = date.withYear(date.getYear() + 1);
+        }
+        return date.with(date.getMonth().plus(1));
+    }
+
+    private LocalDate previous(LocalDate date) {
+        int newDayOfMonth = date.getDayOfMonth() - 1;
+        if (newDayOfMonth > 0) {
+            return date.withDayOfMonth(newDayOfMonth);
+        }
+        date = date.with(date.getMonth().minus(1));
+        if (date.getMonth() == Month.DECEMBER) {
+            date = date.withYear(date.getYear() - 1);
+        }
+        return date.withDayOfMonth(date.getMonth().length(isIsoLeap(date.getYear())));
+    }
+
+    //-----------------------------------------------------------------------
+    // ofEpochDay()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_ofEpochDay() {
+        long date_0000_01_01 = -678941 - 40587;
+        assertEquals(LocalDate.ofEpochDay(0), LocalDate.of(1970, 1, 1));
+        assertEquals(LocalDate.ofEpochDay(date_0000_01_01), LocalDate.of(0, 1, 1));
+        assertEquals(LocalDate.ofEpochDay(date_0000_01_01 - 1), LocalDate.of(-1, 12, 31));
+        assertEquals(LocalDate.ofEpochDay(MAX_VALID_EPOCHDAYS), LocalDate.of(Year.MAX_VALUE, 12, 31));
+        assertEquals(LocalDate.ofEpochDay(MIN_VALID_EPOCHDAYS), LocalDate.of(Year.MIN_VALUE, 1, 1));
+
+        LocalDate test = LocalDate.of(0, 1, 1);
+        for (long i = date_0000_01_01; i < 700000; i++) {
+            assertEquals(LocalDate.ofEpochDay(i), test);
+            test = next(test);
+        }
+        test = LocalDate.of(0, 1, 1);
+        for (long i = date_0000_01_01; i > -2000000; i--) {
+            assertEquals(LocalDate.ofEpochDay(i), test);
+            test = previous(test);
+        }
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_ofEpochDay_aboveMax() {
+        LocalDate.ofEpochDay(MAX_VALID_EPOCHDAYS + 1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_ofEpochDay_belowMin() {
+        LocalDate.ofEpochDay(MIN_VALID_EPOCHDAYS - 1);
+    }
+
+    //-----------------------------------------------------------------------
+    // from()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_from_TemporalAccessor() {
+        assertEquals(LocalDate.from(LocalDate.of(2007, 7, 15)), LocalDate.of(2007, 7, 15));
+        assertEquals(LocalDate.from(LocalDateTime.of(2007, 7, 15, 12, 30)), LocalDate.of(2007, 7, 15));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_from_TemporalAccessor_invalid_noDerive() {
+        LocalDate.from(LocalTime.of(12, 30));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_from_TemporalAccessor_null() {
+        LocalDate.from((TemporalAccessor) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // parse()
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="sampleToString", groups={"tck"})
+    public void factory_parse_validText(int y, int m, int d, String parsable) {
+        LocalDate t = LocalDate.parse(parsable);
+        assertNotNull(t, parsable);
+        assertEquals(t.getYear(), y, parsable);
+        assertEquals(t.getMonth().getValue(), m, parsable);
+        assertEquals(t.getDayOfMonth(), d, parsable);
+    }
+
+    @DataProvider(name="sampleBadParse")
+    Object[][] provider_sampleBadParse() {
+        return new Object[][]{
+                {"2008/07/05"},
+                {"10000-01-01"},
+                {"2008-1-1"},
+                {"2008--01"},
+                {"ABCD-02-01"},
+                {"2008-AB-01"},
+                {"2008-02-AB"},
+                {"-0000-02-01"},
+                {"2008-02-01Z"},
+                {"2008-02-01+01:00"},
+                {"2008-02-01+01:00[Europe/Paris]"},
+        };
+    }
+
+    @Test(dataProvider="sampleBadParse", expectedExceptions={DateTimeParseException.class}, groups={"tck"})
+    public void factory_parse_invalidText(String unparsable) {
+        LocalDate.parse(unparsable);
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"})
+    public void factory_parse_illegalValue() {
+        LocalDate.parse("2008-06-32");
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"})
+    public void factory_parse_invalidValue() {
+        LocalDate.parse("2008-06-31");
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_parse_nullText() {
+        LocalDate.parse((String) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // parse(DateTimeFormatter)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_parse_formatter() {
+        DateTimeFormatter f = DateTimeFormatters.pattern("y M d");
+        LocalDate test = LocalDate.parse("2010 12 3", f);
+        assertEquals(test, LocalDate.of(2010, 12, 3));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_parse_formatter_nullText() {
+        DateTimeFormatter f = DateTimeFormatters.pattern("y M d");
+        LocalDate.parse((String) null, f);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_parse_formatter_nullFormatter() {
+        LocalDate.parse("ANY", null);
+    }
+
+    //-----------------------------------------------------------------------
+    // get(TemporalField)
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_get_TemporalField() {
+        LocalDate test = LocalDate.of(2008, 6, 30);
+        assertEquals(test.get(ChronoField.YEAR), 2008);
+        assertEquals(test.get(ChronoField.MONTH_OF_YEAR), 6);
+        assertEquals(test.get(ChronoField.DAY_OF_MONTH), 30);
+        assertEquals(test.get(ChronoField.DAY_OF_WEEK), 1);
+        assertEquals(test.get(ChronoField.DAY_OF_YEAR), 182);
+    }
+
+    @Test
+    public void test_getLong_TemporalField() {
+        LocalDate test = LocalDate.of(2008, 6, 30);
+        assertEquals(test.getLong(ChronoField.YEAR), 2008);
+        assertEquals(test.getLong(ChronoField.MONTH_OF_YEAR), 6);
+        assertEquals(test.getLong(ChronoField.DAY_OF_MONTH), 30);
+        assertEquals(test.getLong(ChronoField.DAY_OF_WEEK), 1);
+        assertEquals(test.getLong(ChronoField.DAY_OF_YEAR), 182);
+    }
+
+    //-----------------------------------------------------------------------
+    // query(TemporalQuery)
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_query_chrono() {
+        assertEquals(TEST_2007_07_15.query(Queries.chrono()), ISOChrono.INSTANCE);
+        assertEquals(Queries.chrono().queryFrom(TEST_2007_07_15), ISOChrono.INSTANCE);
+    }
+
+    @Test
+    public void test_query_zoneId() {
+        assertEquals(TEST_2007_07_15.query(Queries.zoneId()), null);
+        assertEquals(Queries.zoneId().queryFrom(TEST_2007_07_15), null);
+    }
+
+    @Test
+    public void test_query_precision() {
+        assertEquals(TEST_2007_07_15.query(Queries.precision()), ChronoUnit.DAYS);
+        assertEquals(Queries.precision().queryFrom(TEST_2007_07_15), ChronoUnit.DAYS);
+    }
+
+    @Test
+    public void test_query_offset() {
+        assertEquals(TEST_2007_07_15.query(Queries.offset()), null);
+        assertEquals(Queries.offset().queryFrom(TEST_2007_07_15), null);
+    }
+
+    @Test
+    public void test_query_zone() {
+        assertEquals(TEST_2007_07_15.query(Queries.zone()), null);
+        assertEquals(Queries.zone().queryFrom(TEST_2007_07_15), null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_query_null() {
+        TEST_2007_07_15.query(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // get*()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sampleDates")
+    Object[][] provider_sampleDates() {
+        return new Object[][] {
+            {2008, 7, 5},
+            {2007, 7, 5},
+            {2006, 7, 5},
+            {2005, 7, 5},
+            {2004, 1, 1},
+            {-1, 1, 2},
+        };
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="sampleDates", groups={"tck"})
+    public void test_get(int y, int m, int d) {
+        LocalDate a = LocalDate.of(y, m, d);
+        assertEquals(a.getYear(), y);
+        assertEquals(a.getMonth(), Month.of(m));
+        assertEquals(a.getDayOfMonth(), d);
+    }
+
+    @Test(dataProvider="sampleDates", groups={"tck"})
+    public void test_getDOY(int y, int m, int d) {
+        LocalDate a = LocalDate.of(y, m, d);
+        int total = 0;
+        for (int i = 1; i < m; i++) {
+            total += Month.of(i).length(isIsoLeap(y));
+        }
+        int doy = total + d;
+        assertEquals(a.getDayOfYear(), doy);
+    }
+
+    @Test(groups={"tck"})
+    public void test_getDayOfWeek() {
+        DayOfWeek dow = DayOfWeek.MONDAY;
+        for (Month month : Month.values()) {
+            int length = month.length(false);
+            for (int i = 1; i <= length; i++) {
+                LocalDate d = LocalDate.of(2007, month, i);
+                assertSame(d.getDayOfWeek(), dow);
+                dow = dow.plus(1);
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // isLeapYear()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_isLeapYear() {
+        assertEquals(LocalDate.of(1999, 1, 1).isLeapYear(), false);
+        assertEquals(LocalDate.of(2000, 1, 1).isLeapYear(), true);
+        assertEquals(LocalDate.of(2001, 1, 1).isLeapYear(), false);
+        assertEquals(LocalDate.of(2002, 1, 1).isLeapYear(), false);
+        assertEquals(LocalDate.of(2003, 1, 1).isLeapYear(), false);
+        assertEquals(LocalDate.of(2004, 1, 1).isLeapYear(), true);
+        assertEquals(LocalDate.of(2005, 1, 1).isLeapYear(), false);
+
+        assertEquals(LocalDate.of(1500, 1, 1).isLeapYear(), false);
+        assertEquals(LocalDate.of(1600, 1, 1).isLeapYear(), true);
+        assertEquals(LocalDate.of(1700, 1, 1).isLeapYear(), false);
+        assertEquals(LocalDate.of(1800, 1, 1).isLeapYear(), false);
+        assertEquals(LocalDate.of(1900, 1, 1).isLeapYear(), false);
+    }
+
+    //-----------------------------------------------------------------------
+    // lengthOfMonth()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_lengthOfMonth_notLeapYear() {
+        assertEquals(LocalDate.of(2007, 1, 1).lengthOfMonth(), 31);
+        assertEquals(LocalDate.of(2007, 2, 1).lengthOfMonth(), 28);
+        assertEquals(LocalDate.of(2007, 3, 1).lengthOfMonth(), 31);
+        assertEquals(LocalDate.of(2007, 4, 1).lengthOfMonth(), 30);
+        assertEquals(LocalDate.of(2007, 5, 1).lengthOfMonth(), 31);
+        assertEquals(LocalDate.of(2007, 6, 1).lengthOfMonth(), 30);
+        assertEquals(LocalDate.of(2007, 7, 1).lengthOfMonth(), 31);
+        assertEquals(LocalDate.of(2007, 8, 1).lengthOfMonth(), 31);
+        assertEquals(LocalDate.of(2007, 9, 1).lengthOfMonth(), 30);
+        assertEquals(LocalDate.of(2007, 10, 1).lengthOfMonth(), 31);
+        assertEquals(LocalDate.of(2007, 11, 1).lengthOfMonth(), 30);
+        assertEquals(LocalDate.of(2007, 12, 1).lengthOfMonth(), 31);
+    }
+
+    @Test(groups={"tck"})
+    public void test_lengthOfMonth_leapYear() {
+        assertEquals(LocalDate.of(2008, 1, 1).lengthOfMonth(), 31);
+        assertEquals(LocalDate.of(2008, 2, 1).lengthOfMonth(), 29);
+        assertEquals(LocalDate.of(2008, 3, 1).lengthOfMonth(), 31);
+        assertEquals(LocalDate.of(2008, 4, 1).lengthOfMonth(), 30);
+        assertEquals(LocalDate.of(2008, 5, 1).lengthOfMonth(), 31);
+        assertEquals(LocalDate.of(2008, 6, 1).lengthOfMonth(), 30);
+        assertEquals(LocalDate.of(2008, 7, 1).lengthOfMonth(), 31);
+        assertEquals(LocalDate.of(2008, 8, 1).lengthOfMonth(), 31);
+        assertEquals(LocalDate.of(2008, 9, 1).lengthOfMonth(), 30);
+        assertEquals(LocalDate.of(2008, 10, 1).lengthOfMonth(), 31);
+        assertEquals(LocalDate.of(2008, 11, 1).lengthOfMonth(), 30);
+        assertEquals(LocalDate.of(2008, 12, 1).lengthOfMonth(), 31);
+    }
+
+    //-----------------------------------------------------------------------
+    // lengthOfYear()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_lengthOfYear() {
+        assertEquals(LocalDate.of(2007, 1, 1).lengthOfYear(), 365);
+        assertEquals(LocalDate.of(2008, 1, 1).lengthOfYear(), 366);
+    }
+
+    //-----------------------------------------------------------------------
+    // with()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_with_adjustment() {
+        final LocalDate sample = LocalDate.of(2012, 3, 4);
+        TemporalAdjuster adjuster = new TemporalAdjuster() {
+            @Override
+            public Temporal adjustInto(Temporal dateTime) {
+                return sample;
+            }
+        };
+        assertEquals(TEST_2007_07_15.with(adjuster), sample);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_with_adjustment_null() {
+        TEST_2007_07_15.with((TemporalAdjuster) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // with(TemporalField,long)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_with_TemporalField_long_normal() {
+        LocalDate t = TEST_2007_07_15.with(YEAR, 2008);
+        assertEquals(t, LocalDate.of(2008, 7, 15));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"} )
+    public void test_with_TemporalField_long_null() {
+        TEST_2007_07_15.with((TemporalField) null, 1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"} )
+    public void test_with_TemporalField_long_invalidField() {
+        TEST_2007_07_15.with(MockFieldNoValue.INSTANCE, 1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"} )
+    public void test_with_TemporalField_long_timeField() {
+        TEST_2007_07_15.with(ChronoField.AMPM_OF_DAY, 1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"} )
+    public void test_with_TemporalField_long_invalidValue() {
+        TEST_2007_07_15.with(ChronoField.DAY_OF_WEEK, -1);
+    }
+
+    //-----------------------------------------------------------------------
+    // withYear()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withYear_int_normal() {
+        LocalDate t = TEST_2007_07_15.withYear(2008);
+        assertEquals(t, LocalDate.of(2008, 7, 15));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withYear_int_invalid() {
+        TEST_2007_07_15.withYear(Year.MIN_VALUE - 1);
+    }
+
+    @Test(groups={"tck"})
+    public void test_withYear_int_adjustDay() {
+        LocalDate t = LocalDate.of(2008, 2, 29).withYear(2007);
+        LocalDate expected = LocalDate.of(2007, 2, 28);
+        assertEquals(t, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // withMonth()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withMonth_int_normal() {
+        LocalDate t = TEST_2007_07_15.withMonth(1);
+        assertEquals(t, LocalDate.of(2007, 1, 15));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withMonth_int_invalid() {
+        TEST_2007_07_15.withMonth(13);
+    }
+
+    @Test(groups={"tck"})
+    public void test_withMonth_int_adjustDay() {
+        LocalDate t = LocalDate.of(2007, 12, 31).withMonth(11);
+        LocalDate expected = LocalDate.of(2007, 11, 30);
+        assertEquals(t, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // withDayOfMonth()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withDayOfMonth_normal() {
+        LocalDate t = TEST_2007_07_15.withDayOfMonth(1);
+        assertEquals(t, LocalDate.of(2007, 7, 1));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withDayOfMonth_illegal() {
+        TEST_2007_07_15.withDayOfMonth(32);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withDayOfMonth_invalid() {
+        LocalDate.of(2007, 11, 30).withDayOfMonth(31);
+    }
+
+    //-----------------------------------------------------------------------
+    // withDayOfYear(int)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withDayOfYear_normal() {
+        LocalDate t = TEST_2007_07_15.withDayOfYear(33);
+        assertEquals(t, LocalDate.of(2007, 2, 2));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withDayOfYear_illegal() {
+        TEST_2007_07_15.withDayOfYear(367);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withDayOfYear_invalid() {
+        TEST_2007_07_15.withDayOfYear(366);
+    }
+
+    //-----------------------------------------------------------------------
+    // plus(Period)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plus_Period_positiveMonths() {
+        MockSimplePeriod period = MockSimplePeriod.of(7, ChronoUnit.MONTHS);
+        LocalDate t = TEST_2007_07_15.plus(period);
+        assertEquals(t, LocalDate.of(2008, 2, 15));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plus_Period_negativeDays() {
+        MockSimplePeriod period = MockSimplePeriod.of(-25, ChronoUnit.DAYS);
+        LocalDate t = TEST_2007_07_15.plus(period);
+        assertEquals(t, LocalDate.of(2007, 6, 20));
+    }
+
+    @Test(groups={"tck"}, expectedExceptions=DateTimeException.class)
+    public void test_plus_Period_timeNotAllowed() {
+        MockSimplePeriod period = MockSimplePeriod.of(7, ChronoUnit.HOURS);
+        TEST_2007_07_15.plus(period);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_plus_Period_null() {
+        TEST_2007_07_15.plus((MockSimplePeriod) null);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plus_Period_invalidTooLarge() {
+        MockSimplePeriod period = MockSimplePeriod.of(1, ChronoUnit.YEARS);
+        LocalDate.of(Year.MAX_VALUE, 1, 1).plus(period);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plus_Period_invalidTooSmall() {
+        MockSimplePeriod period = MockSimplePeriod.of(-1, ChronoUnit.YEARS);
+        LocalDate.of(Year.MIN_VALUE, 1, 1).plus(period);
+    }
+
+    //-----------------------------------------------------------------------
+    // plus(long,TemporalUnit)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plus_longTemporalUnit_positiveMonths() {
+        LocalDate t = TEST_2007_07_15.plus(7, ChronoUnit.MONTHS);
+        assertEquals(t, LocalDate.of(2008, 2, 15));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plus_longTemporalUnit_negativeDays() {
+        LocalDate t = TEST_2007_07_15.plus(-25, ChronoUnit.DAYS);
+        assertEquals(t, LocalDate.of(2007, 6, 20));
+    }
+
+    @Test(groups={"tck"}, expectedExceptions=DateTimeException.class)
+    public void test_plus_longTemporalUnit_timeNotAllowed() {
+        TEST_2007_07_15.plus(7, ChronoUnit.HOURS);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_plus_longTemporalUnit_null() {
+        TEST_2007_07_15.plus(1, (TemporalUnit) null);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plus_longTemporalUnit_invalidTooLarge() {
+        LocalDate.of(Year.MAX_VALUE, 1, 1).plus(1, ChronoUnit.YEARS);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plus_longTemporalUnit_invalidTooSmall() {
+        LocalDate.of(Year.MIN_VALUE, 1, 1).plus(-1, ChronoUnit.YEARS);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusYears()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusYears_long_normal() {
+        LocalDate t = TEST_2007_07_15.plusYears(1);
+        assertEquals(t, LocalDate.of(2008, 7, 15));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusYears_long_negative() {
+        LocalDate t = TEST_2007_07_15.plusYears(-1);
+        assertEquals(t, LocalDate.of(2006, 7, 15));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusYears_long_adjustDay() {
+        LocalDate t = LocalDate.of(2008, 2, 29).plusYears(1);
+        LocalDate expected = LocalDate.of(2009, 2, 28);
+        assertEquals(t, expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusYears_long_big() {
+        long years = 20L + Year.MAX_VALUE;
+        LocalDate test = LocalDate.of(-40, 6, 1).plusYears(years);
+        assertEquals(test, LocalDate.of((int) (-40L + years), 6, 1));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusYears_long_invalidTooLarge() {
+        LocalDate test = LocalDate.of(Year.MAX_VALUE, 6, 1);
+        test.plusYears(1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusYears_long_invalidTooLargeMaxAddMax() {
+        LocalDate test = LocalDate.of(Year.MAX_VALUE, 12, 1);
+        test.plusYears(Long.MAX_VALUE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusYears_long_invalidTooLargeMaxAddMin() {
+        LocalDate test = LocalDate.of(Year.MAX_VALUE, 12, 1);
+        test.plusYears(Long.MIN_VALUE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusYears_long_invalidTooSmall_validInt() {
+        LocalDate.of(Year.MIN_VALUE, 1, 1).plusYears(-1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusYears_long_invalidTooSmall_invalidInt() {
+        LocalDate.of(Year.MIN_VALUE, 1, 1).plusYears(-10);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusMonths()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusMonths_long_normal() {
+        LocalDate t = TEST_2007_07_15.plusMonths(1);
+        assertEquals(t, LocalDate.of(2007, 8, 15));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMonths_long_overYears() {
+        LocalDate t = TEST_2007_07_15.plusMonths(25);
+        assertEquals(t, LocalDate.of(2009, 8, 15));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMonths_long_negative() {
+        LocalDate t = TEST_2007_07_15.plusMonths(-1);
+        assertEquals(t, LocalDate.of(2007, 6, 15));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMonths_long_negativeAcrossYear() {
+        LocalDate t = TEST_2007_07_15.plusMonths(-7);
+        assertEquals(t, LocalDate.of(2006, 12, 15));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMonths_long_negativeOverYears() {
+        LocalDate t = TEST_2007_07_15.plusMonths(-31);
+        assertEquals(t, LocalDate.of(2004, 12, 15));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMonths_long_adjustDayFromLeapYear() {
+        LocalDate t = LocalDate.of(2008, 2, 29).plusMonths(12);
+        LocalDate expected = LocalDate.of(2009, 2, 28);
+        assertEquals(t, expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMonths_long_adjustDayFromMonthLength() {
+        LocalDate t = LocalDate.of(2007, 3, 31).plusMonths(1);
+        LocalDate expected = LocalDate.of(2007, 4, 30);
+        assertEquals(t, expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMonths_long_big() {
+        long months = 20L + Integer.MAX_VALUE;
+        LocalDate test = LocalDate.of(-40, 6, 1).plusMonths(months);
+        assertEquals(test, LocalDate.of((int) (-40L + months / 12), 6 + (int) (months % 12), 1));
+    }
+
+    @Test(expectedExceptions={DateTimeException.class}, groups={"tck"})
+    public void test_plusMonths_long_invalidTooLarge() {
+        LocalDate.of(Year.MAX_VALUE, 12, 1).plusMonths(1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusMonths_long_invalidTooLargeMaxAddMax() {
+        LocalDate test = LocalDate.of(Year.MAX_VALUE, 12, 1);
+        test.plusMonths(Long.MAX_VALUE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusMonths_long_invalidTooLargeMaxAddMin() {
+        LocalDate test = LocalDate.of(Year.MAX_VALUE, 12, 1);
+        test.plusMonths(Long.MIN_VALUE);
+    }
+
+    @Test(expectedExceptions={DateTimeException.class}, groups={"tck"})
+    public void test_plusMonths_long_invalidTooSmall() {
+        LocalDate.of(Year.MIN_VALUE, 1, 1).plusMonths(-1);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusWeeks_normal() {
+        LocalDate t = TEST_2007_07_15.plusWeeks(1);
+        assertEquals(t, LocalDate.of(2007, 7, 22));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusWeeks_overMonths() {
+        LocalDate t = TEST_2007_07_15.plusWeeks(9);
+        assertEquals(t, LocalDate.of(2007, 9, 16));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusWeeks_overYears() {
+        LocalDate t = LocalDate.of(2006, 7, 16).plusWeeks(52);
+        assertEquals(t, TEST_2007_07_15);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusWeeks_overLeapYears() {
+        LocalDate t = TEST_2007_07_15.plusYears(-1).plusWeeks(104);
+        assertEquals(t, LocalDate.of(2008, 7, 12));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusWeeks_negative() {
+        LocalDate t = TEST_2007_07_15.plusWeeks(-1);
+        assertEquals(t, LocalDate.of(2007, 7, 8));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusWeeks_negativeAcrossYear() {
+        LocalDate t = TEST_2007_07_15.plusWeeks(-28);
+        assertEquals(t, LocalDate.of(2006, 12, 31));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusWeeks_negativeOverYears() {
+        LocalDate t = TEST_2007_07_15.plusWeeks(-104);
+        assertEquals(t, LocalDate.of(2005, 7, 17));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusWeeks_maximum() {
+        LocalDate t = LocalDate.of(Year.MAX_VALUE, 12, 24).plusWeeks(1);
+        LocalDate expected = LocalDate.of(Year.MAX_VALUE, 12, 31);
+        assertEquals(t, expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusWeeks_minimum() {
+        LocalDate t = LocalDate.of(Year.MIN_VALUE, 1, 8).plusWeeks(-1);
+        LocalDate expected = LocalDate.of(Year.MIN_VALUE, 1, 1);
+        assertEquals(t, expected);
+    }
+
+    @Test(expectedExceptions={DateTimeException.class}, groups={"tck"})
+    public void test_plusWeeks_invalidTooLarge() {
+        LocalDate.of(Year.MAX_VALUE, 12, 25).plusWeeks(1);
+    }
+
+    @Test(expectedExceptions={DateTimeException.class}, groups={"tck"})
+    public void test_plusWeeks_invalidTooSmall() {
+        LocalDate.of(Year.MIN_VALUE, 1, 7).plusWeeks(-1);
+    }
+
+    @Test(expectedExceptions={ArithmeticException.class}, groups={"tck"})
+    public void test_plusWeeks_invalidMaxMinusMax() {
+        LocalDate.of(Year.MAX_VALUE, 12, 25).plusWeeks(Long.MAX_VALUE);
+    }
+
+    @Test(expectedExceptions={ArithmeticException.class}, groups={"tck"})
+    public void test_plusWeeks_invalidMaxMinusMin() {
+        LocalDate.of(Year.MAX_VALUE, 12, 25).plusWeeks(Long.MIN_VALUE);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusDays_normal() {
+        LocalDate t = TEST_2007_07_15.plusDays(1);
+        assertEquals(t, LocalDate.of(2007, 7, 16));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusDays_overMonths() {
+        LocalDate t = TEST_2007_07_15.plusDays(62);
+        assertEquals(t, LocalDate.of(2007, 9, 15));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusDays_overYears() {
+        LocalDate t = LocalDate.of(2006, 7, 14).plusDays(366);
+        assertEquals(t, TEST_2007_07_15);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusDays_overLeapYears() {
+        LocalDate t = TEST_2007_07_15.plusYears(-1).plusDays(365 + 366);
+        assertEquals(t, LocalDate.of(2008, 7, 15));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusDays_negative() {
+        LocalDate t = TEST_2007_07_15.plusDays(-1);
+        assertEquals(t, LocalDate.of(2007, 7, 14));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusDays_negativeAcrossYear() {
+        LocalDate t = TEST_2007_07_15.plusDays(-196);
+        assertEquals(t, LocalDate.of(2006, 12, 31));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusDays_negativeOverYears() {
+        LocalDate t = TEST_2007_07_15.plusDays(-730);
+        assertEquals(t, LocalDate.of(2005, 7, 15));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusDays_maximum() {
+        LocalDate t = LocalDate.of(Year.MAX_VALUE, 12, 30).plusDays(1);
+        LocalDate expected = LocalDate.of(Year.MAX_VALUE, 12, 31);
+        assertEquals(t, expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusDays_minimum() {
+        LocalDate t = LocalDate.of(Year.MIN_VALUE, 1, 2).plusDays(-1);
+        LocalDate expected = LocalDate.of(Year.MIN_VALUE, 1, 1);
+        assertEquals(t, expected);
+    }
+
+    @Test(expectedExceptions={DateTimeException.class}, groups={"tck"})
+    public void test_plusDays_invalidTooLarge() {
+        LocalDate.of(Year.MAX_VALUE, 12, 31).plusDays(1);
+    }
+
+    @Test(expectedExceptions={DateTimeException.class}, groups={"tck"})
+    public void test_plusDays_invalidTooSmall() {
+        LocalDate.of(Year.MIN_VALUE, 1, 1).plusDays(-1);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void test_plusDays_overflowTooLarge() {
+        LocalDate.of(Year.MAX_VALUE, 12, 31).plusDays(Long.MAX_VALUE);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void test_plusDays_overflowTooSmall() {
+        LocalDate.of(Year.MIN_VALUE, 1, 1).plusDays(Long.MIN_VALUE);
+    }
+
+    //-----------------------------------------------------------------------
+    // minus(Period)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minus_Period_positiveMonths() {
+        MockSimplePeriod period = MockSimplePeriod.of(7, ChronoUnit.MONTHS);
+        LocalDate t = TEST_2007_07_15.minus(period);
+        assertEquals(t, LocalDate.of(2006, 12, 15));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minus_Period_negativeDays() {
+        MockSimplePeriod period = MockSimplePeriod.of(-25, ChronoUnit.DAYS);
+        LocalDate t = TEST_2007_07_15.minus(period);
+        assertEquals(t, LocalDate.of(2007, 8, 9));
+    }
+
+    @Test(groups={"tck"}, expectedExceptions=DateTimeException.class)
+    public void test_minus_Period_timeNotAllowed() {
+        MockSimplePeriod period = MockSimplePeriod.of(7, ChronoUnit.HOURS);
+        TEST_2007_07_15.minus(period);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_minus_Period_null() {
+        TEST_2007_07_15.minus((MockSimplePeriod) null);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minus_Period_invalidTooLarge() {
+        MockSimplePeriod period = MockSimplePeriod.of(-1, ChronoUnit.YEARS);
+        LocalDate.of(Year.MAX_VALUE, 1, 1).minus(period);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minus_Period_invalidTooSmall() {
+        MockSimplePeriod period = MockSimplePeriod.of(1, ChronoUnit.YEARS);
+        LocalDate.of(Year.MIN_VALUE, 1, 1).minus(period);
+    }
+
+    //-----------------------------------------------------------------------
+    // minus(long,TemporalUnit)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minus_longTemporalUnit_positiveMonths() {
+        LocalDate t = TEST_2007_07_15.minus(7, ChronoUnit.MONTHS);
+        assertEquals(t, LocalDate.of(2006, 12, 15));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minus_longTemporalUnit_negativeDays() {
+        LocalDate t = TEST_2007_07_15.minus(-25, ChronoUnit.DAYS);
+        assertEquals(t, LocalDate.of(2007, 8, 9));
+    }
+
+    @Test(groups={"tck"}, expectedExceptions=DateTimeException.class)
+    public void test_minus_longTemporalUnit_timeNotAllowed() {
+        TEST_2007_07_15.minus(7, ChronoUnit.HOURS);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_minus_longTemporalUnit_null() {
+        TEST_2007_07_15.minus(1, (TemporalUnit) null);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minus_longTemporalUnit_invalidTooLarge() {
+        LocalDate.of(Year.MAX_VALUE, 1, 1).minus(-1, ChronoUnit.YEARS);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minus_longTemporalUnit_invalidTooSmall() {
+        LocalDate.of(Year.MIN_VALUE, 1, 1).minus(1, ChronoUnit.YEARS);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusYears()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusYears_long_normal() {
+        LocalDate t = TEST_2007_07_15.minusYears(1);
+        assertEquals(t, LocalDate.of(2006, 7, 15));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusYears_long_negative() {
+        LocalDate t = TEST_2007_07_15.minusYears(-1);
+        assertEquals(t, LocalDate.of(2008, 7, 15));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusYears_long_adjustDay() {
+        LocalDate t = LocalDate.of(2008, 2, 29).minusYears(1);
+        LocalDate expected = LocalDate.of(2007, 2, 28);
+        assertEquals(t, expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusYears_long_big() {
+        long years = 20L + Year.MAX_VALUE;
+        LocalDate test = LocalDate.of(40, 6, 1).minusYears(years);
+        assertEquals(test, LocalDate.of((int) (40L - years), 6, 1));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minusYears_long_invalidTooLarge() {
+        LocalDate test = LocalDate.of(Year.MAX_VALUE, 6, 1);
+        test.minusYears(-1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minusYears_long_invalidTooLargeMaxAddMax() {
+        LocalDate test = LocalDate.of(Year.MAX_VALUE, 12, 1);
+        test.minusYears(Long.MAX_VALUE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minusYears_long_invalidTooLargeMaxAddMin() {
+        LocalDate test = LocalDate.of(Year.MAX_VALUE, 12, 1);
+        test.minusYears(Long.MIN_VALUE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minusYears_long_invalidTooSmall() {
+        LocalDate.of(Year.MIN_VALUE, 1, 1).minusYears(1);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusMonths()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusMonths_long_normal() {
+        LocalDate t = TEST_2007_07_15.minusMonths(1);
+        assertEquals(t, LocalDate.of(2007, 6, 15));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMonths_long_overYears() {
+        LocalDate t = TEST_2007_07_15.minusMonths(25);
+        assertEquals(t, LocalDate.of(2005, 6, 15));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMonths_long_negative() {
+        LocalDate t = TEST_2007_07_15.minusMonths(-1);
+        assertEquals(t, LocalDate.of(2007, 8, 15));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMonths_long_negativeAcrossYear() {
+        LocalDate t = TEST_2007_07_15.minusMonths(-7);
+        assertEquals(t, LocalDate.of(2008, 2, 15));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMonths_long_negativeOverYears() {
+        LocalDate t = TEST_2007_07_15.minusMonths(-31);
+        assertEquals(t, LocalDate.of(2010, 2, 15));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMonths_long_adjustDayFromLeapYear() {
+        LocalDate t = LocalDate.of(2008, 2, 29).minusMonths(12);
+        LocalDate expected = LocalDate.of(2007, 2, 28);
+        assertEquals(t, expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMonths_long_adjustDayFromMonthLength() {
+        LocalDate t = LocalDate.of(2007, 3, 31).minusMonths(1);
+        LocalDate expected = LocalDate.of(2007, 2, 28);
+        assertEquals(t, expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMonths_long_big() {
+        long months = 20L + Integer.MAX_VALUE;
+        LocalDate test = LocalDate.of(40, 6, 1).minusMonths(months);
+        assertEquals(test, LocalDate.of((int) (40L - months / 12), 6 - (int) (months % 12), 1));
+    }
+
+    @Test(expectedExceptions={DateTimeException.class}, groups={"tck"})
+    public void test_minusMonths_long_invalidTooLarge() {
+        LocalDate.of(Year.MAX_VALUE, 12, 1).minusMonths(-1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minusMonths_long_invalidTooLargeMaxAddMax() {
+        LocalDate test = LocalDate.of(Year.MAX_VALUE, 12, 1);
+        test.minusMonths(Long.MAX_VALUE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minusMonths_long_invalidTooLargeMaxAddMin() {
+        LocalDate test = LocalDate.of(Year.MAX_VALUE, 12, 1);
+        test.minusMonths(Long.MIN_VALUE);
+    }
+
+    @Test(expectedExceptions={DateTimeException.class}, groups={"tck"})
+    public void test_minusMonths_long_invalidTooSmall() {
+        LocalDate.of(Year.MIN_VALUE, 1, 1).minusMonths(1);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusWeeks_normal() {
+        LocalDate t = TEST_2007_07_15.minusWeeks(1);
+        assertEquals(t, LocalDate.of(2007, 7, 8));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusWeeks_overMonths() {
+        LocalDate t = TEST_2007_07_15.minusWeeks(9);
+        assertEquals(t, LocalDate.of(2007, 5, 13));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusWeeks_overYears() {
+        LocalDate t = LocalDate.of(2008, 7, 13).minusWeeks(52);
+        assertEquals(t, TEST_2007_07_15);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusWeeks_overLeapYears() {
+        LocalDate t = TEST_2007_07_15.minusYears(-1).minusWeeks(104);
+        assertEquals(t, LocalDate.of(2006, 7, 18));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusWeeks_negative() {
+        LocalDate t = TEST_2007_07_15.minusWeeks(-1);
+        assertEquals(t, LocalDate.of(2007, 7, 22));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusWeeks_negativeAcrossYear() {
+        LocalDate t = TEST_2007_07_15.minusWeeks(-28);
+        assertEquals(t, LocalDate.of(2008, 1, 27));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusWeeks_negativeOverYears() {
+        LocalDate t = TEST_2007_07_15.minusWeeks(-104);
+        assertEquals(t, LocalDate.of(2009, 7, 12));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusWeeks_maximum() {
+        LocalDate t = LocalDate.of(Year.MAX_VALUE, 12, 24).minusWeeks(-1);
+        LocalDate expected = LocalDate.of(Year.MAX_VALUE, 12, 31);
+        assertEquals(t, expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusWeeks_minimum() {
+        LocalDate t = LocalDate.of(Year.MIN_VALUE, 1, 8).minusWeeks(1);
+        LocalDate expected = LocalDate.of(Year.MIN_VALUE, 1, 1);
+        assertEquals(t, expected);
+    }
+
+    @Test(expectedExceptions={DateTimeException.class}, groups={"tck"})
+    public void test_minusWeeks_invalidTooLarge() {
+        LocalDate.of(Year.MAX_VALUE, 12, 25).minusWeeks(-1);
+    }
+
+    @Test(expectedExceptions={DateTimeException.class}, groups={"tck"})
+    public void test_minusWeeks_invalidTooSmall() {
+        LocalDate.of(Year.MIN_VALUE, 1, 7).minusWeeks(1);
+    }
+
+    @Test(expectedExceptions={ArithmeticException.class}, groups={"tck"})
+    public void test_minusWeeks_invalidMaxMinusMax() {
+        LocalDate.of(Year.MAX_VALUE, 12, 25).minusWeeks(Long.MAX_VALUE);
+    }
+
+    @Test(expectedExceptions={ArithmeticException.class}, groups={"tck"})
+    public void test_minusWeeks_invalidMaxMinusMin() {
+        LocalDate.of(Year.MAX_VALUE, 12, 25).minusWeeks(Long.MIN_VALUE);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusDays_normal() {
+        LocalDate t = TEST_2007_07_15.minusDays(1);
+        assertEquals(t, LocalDate.of(2007, 7, 14));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusDays_overMonths() {
+        LocalDate t = TEST_2007_07_15.minusDays(62);
+        assertEquals(t, LocalDate.of(2007, 5, 14));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusDays_overYears() {
+        LocalDate t = LocalDate.of(2008, 7, 16).minusDays(367);
+        assertEquals(t, TEST_2007_07_15);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusDays_overLeapYears() {
+        LocalDate t = TEST_2007_07_15.plusYears(2).minusDays(365 + 366);
+        assertEquals(t, TEST_2007_07_15);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusDays_negative() {
+        LocalDate t = TEST_2007_07_15.minusDays(-1);
+        assertEquals(t, LocalDate.of(2007, 7, 16));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusDays_negativeAcrossYear() {
+        LocalDate t = TEST_2007_07_15.minusDays(-169);
+        assertEquals(t, LocalDate.of(2007, 12, 31));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusDays_negativeOverYears() {
+        LocalDate t = TEST_2007_07_15.minusDays(-731);
+        assertEquals(t, LocalDate.of(2009, 7, 15));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusDays_maximum() {
+        LocalDate t = LocalDate.of(Year.MAX_VALUE, 12, 30).minusDays(-1);
+        LocalDate expected = LocalDate.of(Year.MAX_VALUE, 12, 31);
+        assertEquals(t, expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusDays_minimum() {
+        LocalDate t = LocalDate.of(Year.MIN_VALUE, 1, 2).minusDays(1);
+        LocalDate expected = LocalDate.of(Year.MIN_VALUE, 1, 1);
+        assertEquals(t, expected);
+    }
+
+    @Test(expectedExceptions={DateTimeException.class}, groups={"tck"})
+    public void test_minusDays_invalidTooLarge() {
+        LocalDate.of(Year.MAX_VALUE, 12, 31).minusDays(-1);
+    }
+
+    @Test(expectedExceptions={DateTimeException.class}, groups={"tck"})
+    public void test_minusDays_invalidTooSmall() {
+        LocalDate.of(Year.MIN_VALUE, 1, 1).minusDays(1);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void test_minusDays_overflowTooLarge() {
+        LocalDate.of(Year.MAX_VALUE, 12, 31).minusDays(Long.MIN_VALUE);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void test_minusDays_overflowTooSmall() {
+        LocalDate.of(Year.MIN_VALUE, 1, 1).minusDays(Long.MAX_VALUE);
+    }
+
+    //-----------------------------------------------------------------------
+    // atTime()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_atTime_LocalTime() {
+        LocalDate t = LocalDate.of(2008, 6, 30);
+        assertEquals(t.atTime(LocalTime.of(11, 30)), LocalDateTime.of(2008, 6, 30, 11, 30));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_atTime_LocalTime_null() {
+        LocalDate t = LocalDate.of(2008, 6, 30);
+        t.atTime((LocalTime) null);
+    }
+
+    //-------------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_atTime_int_int() {
+        LocalDate t = LocalDate.of(2008, 6, 30);
+        assertEquals(t.atTime(11, 30), LocalDateTime.of(2008, 6, 30, 11, 30));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_atTime_int_int_hourTooSmall() {
+        LocalDate t = LocalDate.of(2008, 6, 30);
+        t.atTime(-1, 30);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_atTime_int_int_hourTooBig() {
+        LocalDate t = LocalDate.of(2008, 6, 30);
+        t.atTime(24, 30);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_atTime_int_int_minuteTooSmall() {
+        LocalDate t = LocalDate.of(2008, 6, 30);
+        t.atTime(11, -1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_atTime_int_int_minuteTooBig() {
+        LocalDate t = LocalDate.of(2008, 6, 30);
+        t.atTime(11, 60);
+    }
+
+    @Test(groups={"tck"})
+    public void test_atTime_int_int_int() {
+        LocalDate t = LocalDate.of(2008, 6, 30);
+        assertEquals(t.atTime(11, 30, 40), LocalDateTime.of(2008, 6, 30, 11, 30, 40));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_atTime_int_int_int_hourTooSmall() {
+        LocalDate t = LocalDate.of(2008, 6, 30);
+        t.atTime(-1, 30, 40);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_atTime_int_int_int_hourTooBig() {
+        LocalDate t = LocalDate.of(2008, 6, 30);
+        t.atTime(24, 30, 40);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_atTime_int_int_int_minuteTooSmall() {
+        LocalDate t = LocalDate.of(2008, 6, 30);
+        t.atTime(11, -1, 40);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_atTime_int_int_int_minuteTooBig() {
+        LocalDate t = LocalDate.of(2008, 6, 30);
+        t.atTime(11, 60, 40);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_atTime_int_int_int_secondTooSmall() {
+        LocalDate t = LocalDate.of(2008, 6, 30);
+        t.atTime(11, 30, -1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_atTime_int_int_int_secondTooBig() {
+        LocalDate t = LocalDate.of(2008, 6, 30);
+        t.atTime(11, 30, 60);
+    }
+
+    @Test(groups={"tck"})
+    public void test_atTime_int_int_int_int() {
+        LocalDate t = LocalDate.of(2008, 6, 30);
+        assertEquals(t.atTime(11, 30, 40, 50), LocalDateTime.of(2008, 6, 30, 11, 30, 40, 50));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_atTime_int_int_int_int_hourTooSmall() {
+        LocalDate t = LocalDate.of(2008, 6, 30);
+        t.atTime(-1, 30, 40, 50);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_atTime_int_int_int_int_hourTooBig() {
+        LocalDate t = LocalDate.of(2008, 6, 30);
+        t.atTime(24, 30, 40, 50);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_atTime_int_int_int_int_minuteTooSmall() {
+        LocalDate t = LocalDate.of(2008, 6, 30);
+        t.atTime(11, -1, 40, 50);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_atTime_int_int_int_int_minuteTooBig() {
+        LocalDate t = LocalDate.of(2008, 6, 30);
+        t.atTime(11, 60, 40, 50);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_atTime_int_int_int_int_secondTooSmall() {
+        LocalDate t = LocalDate.of(2008, 6, 30);
+        t.atTime(11, 30, -1, 50);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_atTime_int_int_int_int_secondTooBig() {
+        LocalDate t = LocalDate.of(2008, 6, 30);
+        t.atTime(11, 30, 60, 50);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_atTime_int_int_int_int_nanoTooSmall() {
+        LocalDate t = LocalDate.of(2008, 6, 30);
+        t.atTime(11, 30, 40, -1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_atTime_int_int_int_int_nanoTooBig() {
+        LocalDate t = LocalDate.of(2008, 6, 30);
+        t.atTime(11, 30, 40, 1000000000);
+    }
+
+    //-----------------------------------------------------------------------
+    // atOffset()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_atOffset() {
+        LocalDate t = LocalDate.of(2008, 6, 30);
+        assertEquals(t.atOffset(OFFSET_PTWO), OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PTWO));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_atOffset_nullZoneOffset() {
+        LocalDate t = LocalDate.of(2008, 6, 30);
+        t.atOffset((ZoneOffset) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // atStartOfDay()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_atStartOfDay() {
+        LocalDate t = LocalDate.of(2008, 6, 30);
+        assertEquals(t.atStartOfDay(ZONE_PARIS),
+                ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 0, 0), ZONE_PARIS));
+    }
+
+    @Test(groups={"tck"})
+    public void test_atStartOfDay_dstGap() {
+        LocalDate t = LocalDate.of(2007, 4, 1);
+        assertEquals(t.atStartOfDay(ZONE_GAZA),
+                ZonedDateTime.of(LocalDateTime.of(2007, 4, 1, 1, 0), ZONE_GAZA));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_atStartOfDay_nullTimeZone() {
+        LocalDate t = LocalDate.of(2008, 6, 30);
+        t.atStartOfDay((ZoneId) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // toEpochDay()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_toEpochDay() {
+        long date_0000_01_01 = -678941 - 40587;
+
+        LocalDate test = LocalDate.of(0, 1, 1);
+        for (long i = date_0000_01_01; i < 700000; i++) {
+            assertEquals(test.toEpochDay(), i);
+            test = next(test);
+        }
+        test = LocalDate.of(0, 1, 1);
+        for (long i = date_0000_01_01; i > -2000000; i--) {
+            assertEquals(test.toEpochDay(), i);
+            test = previous(test);
+        }
+
+        assertEquals(LocalDate.of(1858, 11, 17).toEpochDay(), -40587);
+        assertEquals(LocalDate.of(1, 1, 1).toEpochDay(), -678575 - 40587);
+        assertEquals(LocalDate.of(1995, 9, 27).toEpochDay(), 49987 - 40587);
+        assertEquals(LocalDate.of(1970, 1, 1).toEpochDay(), 0);
+        assertEquals(LocalDate.of(-1, 12, 31).toEpochDay(), -678942 - 40587);
+    }
+
+    //-----------------------------------------------------------------------
+    // compareTo()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_comparisons() {
+        doTest_comparisons_LocalDate(
+            LocalDate.of(Year.MIN_VALUE, 1, 1),
+            LocalDate.of(Year.MIN_VALUE, 12, 31),
+            LocalDate.of(-1, 1, 1),
+            LocalDate.of(-1, 12, 31),
+            LocalDate.of(0, 1, 1),
+            LocalDate.of(0, 12, 31),
+            LocalDate.of(1, 1, 1),
+            LocalDate.of(1, 12, 31),
+            LocalDate.of(2006, 1, 1),
+            LocalDate.of(2006, 12, 31),
+            LocalDate.of(2007, 1, 1),
+            LocalDate.of(2007, 12, 31),
+            LocalDate.of(2008, 1, 1),
+            LocalDate.of(2008, 2, 29),
+            LocalDate.of(2008, 12, 31),
+            LocalDate.of(Year.MAX_VALUE, 1, 1),
+            LocalDate.of(Year.MAX_VALUE, 12, 31)
+        );
+    }
+
+    void doTest_comparisons_LocalDate(LocalDate... localDates) {
+        for (int i = 0; i < localDates.length; i++) {
+            LocalDate a = localDates[i];
+            for (int j = 0; j < localDates.length; j++) {
+                LocalDate b = localDates[j];
+                if (i < j) {
+                    assertTrue(a.compareTo(b) < 0, a + " <=> " + b);
+                    assertEquals(a.isBefore(b), true, a + " <=> " + b);
+                    assertEquals(a.isAfter(b), false, a + " <=> " + b);
+                    assertEquals(a.equals(b), false, a + " <=> " + b);
+                } else if (i > j) {
+                    assertTrue(a.compareTo(b) > 0, a + " <=> " + b);
+                    assertEquals(a.isBefore(b), false, a + " <=> " + b);
+                    assertEquals(a.isAfter(b), true, a + " <=> " + b);
+                    assertEquals(a.equals(b), false, a + " <=> " + b);
+                } else {
+                    assertEquals(a.compareTo(b), 0, a + " <=> " + b);
+                    assertEquals(a.isBefore(b), false, a + " <=> " + b);
+                    assertEquals(a.isAfter(b), false, a + " <=> " + b);
+                    assertEquals(a.equals(b), true, a + " <=> " + b);
+                }
+            }
+        }
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_compareTo_ObjectNull() {
+        TEST_2007_07_15.compareTo(null);
+    }
+
+    @Test(groups={"tck"})
+    public void test_isBefore() {
+        assertTrue(TEST_2007_07_15.isBefore(LocalDate.of(2007, 07, 16)));
+        assertFalse(TEST_2007_07_15.isBefore(LocalDate.of(2007, 07, 14)));
+        assertFalse(TEST_2007_07_15.isBefore(TEST_2007_07_15));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_isBefore_ObjectNull() {
+        TEST_2007_07_15.isBefore(null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_isAfter_ObjectNull() {
+        TEST_2007_07_15.isAfter(null);
+    }
+
+    @Test(groups={"tck"})
+    public void test_isAfter() {
+        assertTrue(TEST_2007_07_15.isAfter(LocalDate.of(2007, 07, 14)));
+        assertFalse(TEST_2007_07_15.isAfter(LocalDate.of(2007, 07, 16)));
+        assertFalse(TEST_2007_07_15.isAfter(TEST_2007_07_15));
+    }
+
+    @Test(expectedExceptions=ClassCastException.class, groups={"tck"})
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public void compareToNonLocalDate() {
+       Comparable c = TEST_2007_07_15;
+       c.compareTo(new Object());
+    }
+
+    //-----------------------------------------------------------------------
+    // equals()
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="sampleDates" , groups={"tck"})
+    public void test_equals_true(int y, int m, int d) {
+        LocalDate a = LocalDate.of(y, m, d);
+        LocalDate b = LocalDate.of(y, m, d);
+        assertEquals(a.equals(b), true);
+    }
+    @Test(dataProvider="sampleDates", groups={"tck"})
+    public void test_equals_false_year_differs(int y, int m, int d) {
+        LocalDate a = LocalDate.of(y, m, d);
+        LocalDate b = LocalDate.of(y + 1, m, d);
+        assertEquals(a.equals(b), false);
+    }
+    @Test(dataProvider="sampleDates", groups={"tck"})
+    public void test_equals_false_month_differs(int y, int m, int d) {
+        LocalDate a = LocalDate.of(y, m, d);
+        LocalDate b = LocalDate.of(y, m + 1, d);
+        assertEquals(a.equals(b), false);
+    }
+    @Test(dataProvider="sampleDates", groups={"tck"})
+    public void test_equals_false_day_differs(int y, int m, int d) {
+        LocalDate a = LocalDate.of(y, m, d);
+        LocalDate b = LocalDate.of(y, m, d + 1);
+        assertEquals(a.equals(b), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_itself_true() {
+        assertEquals(TEST_2007_07_15.equals(TEST_2007_07_15), true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_string_false() {
+        assertEquals(TEST_2007_07_15.equals("2007-07-15"), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_null_false() {
+        assertEquals(TEST_2007_07_15.equals(null), false);
+    }
+
+    //-----------------------------------------------------------------------
+    // hashCode()
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="sampleDates", groups={"tck"})
+    public void test_hashCode(int y, int m, int d) {
+        LocalDate a = LocalDate.of(y, m, d);
+        assertEquals(a.hashCode(), a.hashCode());
+        LocalDate b = LocalDate.of(y, m, d);
+        assertEquals(a.hashCode(), b.hashCode());
+    }
+
+    //-----------------------------------------------------------------------
+    // toString()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sampleToString")
+    Object[][] provider_sampleToString() {
+        return new Object[][] {
+            {2008, 7, 5, "2008-07-05"},
+            {2007, 12, 31, "2007-12-31"},
+            {999, 12, 31, "0999-12-31"},
+            {-1, 1, 2, "-0001-01-02"},
+            {9999, 12, 31, "9999-12-31"},
+            {-9999, 12, 31, "-9999-12-31"},
+            {10000, 1, 1, "+10000-01-01"},
+            {-10000, 1, 1, "-10000-01-01"},
+            {12345678, 1, 1, "+12345678-01-01"},
+            {-12345678, 1, 1, "-12345678-01-01"},
+        };
+    }
+
+    @Test(dataProvider="sampleToString", groups={"tck"})
+    public void test_toString(int y, int m, int d, String expected) {
+        LocalDate t = LocalDate.of(y, m, d);
+        String str = t.toString();
+        assertEquals(str, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // toString(DateTimeFormatter)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_toString_formatter() {
+        DateTimeFormatter f = DateTimeFormatters.pattern("y M d");
+        String t = LocalDate.of(2010, 12, 3).toString(f);
+        assertEquals(t, "2010 12 3");
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_toString_formatter_null() {
+        LocalDate.of(2010, 12, 3).toString(null);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/TCKLocalDateTime.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,3045 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time;
+
+import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH;
+import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR;
+import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH;
+import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR;
+import static java.time.temporal.ChronoField.AMPM_OF_DAY;
+import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_AMPM;
+import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_DAY;
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.DAY_OF_WEEK;
+import static java.time.temporal.ChronoField.DAY_OF_YEAR;
+import static java.time.temporal.ChronoField.EPOCH_DAY;
+import static java.time.temporal.ChronoField.EPOCH_MONTH;
+import static java.time.temporal.ChronoField.ERA;
+import static java.time.temporal.ChronoField.HOUR_OF_AMPM;
+import static java.time.temporal.ChronoField.HOUR_OF_DAY;
+import static java.time.temporal.ChronoField.MICRO_OF_DAY;
+import static java.time.temporal.ChronoField.MICRO_OF_SECOND;
+import static java.time.temporal.ChronoField.MILLI_OF_DAY;
+import static java.time.temporal.ChronoField.MILLI_OF_SECOND;
+import static java.time.temporal.ChronoField.MINUTE_OF_DAY;
+import static java.time.temporal.ChronoField.MINUTE_OF_HOUR;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.NANO_OF_DAY;
+import static java.time.temporal.ChronoField.NANO_OF_SECOND;
+import static java.time.temporal.ChronoField.SECOND_OF_DAY;
+import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
+import static java.time.temporal.ChronoField.YEAR;
+import static java.time.temporal.ChronoField.YEAR_OF_ERA;
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.NANOS;
+import static java.time.temporal.ChronoUnit.SECONDS;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.DayOfWeek;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.Month;
+import java.time.Period;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatters;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.ISOChrono;
+import java.time.temporal.JulianFields;
+import java.time.temporal.OffsetDateTime;
+import java.time.temporal.Queries;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdder;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.TemporalSubtractor;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.Year;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import test.java.time.MockSimplePeriod;
+
+/**
+ * Test LocalDateTime.
+ */
+@Test
+public class TCKLocalDateTime extends AbstractDateTimeTest {
+
+    private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1);
+    private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2);
+    private static final ZoneOffset OFFSET_MTWO = ZoneOffset.ofHours(-2);
+    private static final ZoneId ZONE_PARIS = ZoneId.of("Europe/Paris");
+    private static final ZoneId ZONE_GAZA = ZoneId.of("Asia/Gaza");
+
+    private LocalDateTime TEST_2007_07_15_12_30_40_987654321 = LocalDateTime.of(2007, 7, 15, 12, 30, 40, 987654321);
+    private LocalDateTime MAX_DATE_TIME;
+    private LocalDateTime MIN_DATE_TIME;
+    private Instant MAX_INSTANT;
+    private Instant MIN_INSTANT;
+
+    @BeforeMethod(groups={"implementation","tck"})
+    public void setUp() {
+        MAX_DATE_TIME = LocalDateTime.MAX;
+        MIN_DATE_TIME = LocalDateTime.MIN;
+        MAX_INSTANT = MAX_DATE_TIME.atZone(ZoneOffset.UTC).toInstant();
+        MIN_INSTANT = MIN_DATE_TIME.atZone(ZoneOffset.UTC).toInstant();
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    protected List<TemporalAccessor> samples() {
+        TemporalAccessor[] array = {TEST_2007_07_15_12_30_40_987654321, LocalDateTime.MAX, LocalDateTime.MIN, };
+        return Arrays.asList(array);
+    }
+
+    @Override
+    protected List<TemporalField> validFields() {
+        TemporalField[] array = {
+            NANO_OF_SECOND,
+            NANO_OF_DAY,
+            MICRO_OF_SECOND,
+            MICRO_OF_DAY,
+            MILLI_OF_SECOND,
+            MILLI_OF_DAY,
+            SECOND_OF_MINUTE,
+            SECOND_OF_DAY,
+            MINUTE_OF_HOUR,
+            MINUTE_OF_DAY,
+            CLOCK_HOUR_OF_AMPM,
+            HOUR_OF_AMPM,
+            CLOCK_HOUR_OF_DAY,
+            HOUR_OF_DAY,
+            AMPM_OF_DAY,
+            DAY_OF_WEEK,
+            ALIGNED_DAY_OF_WEEK_IN_MONTH,
+            ALIGNED_DAY_OF_WEEK_IN_YEAR,
+            DAY_OF_MONTH,
+            DAY_OF_YEAR,
+            EPOCH_DAY,
+            ALIGNED_WEEK_OF_MONTH,
+            ALIGNED_WEEK_OF_YEAR,
+            MONTH_OF_YEAR,
+            EPOCH_MONTH,
+            YEAR_OF_ERA,
+            YEAR,
+            ERA,
+            JulianFields.JULIAN_DAY,
+            JulianFields.MODIFIED_JULIAN_DAY,
+            JulianFields.RATA_DIE,
+        };
+        return Arrays.asList(array);
+    }
+
+    @Override
+    protected List<TemporalField> invalidFields() {
+        List<TemporalField> list = new ArrayList<>(Arrays.<TemporalField>asList(ChronoField.values()));
+        list.removeAll(validFields());
+        return list;
+    }
+
+    //-----------------------------------------------------------------------
+    private void check(LocalDateTime test, int y, int m, int d, int h, int mi, int s, int n) {
+        assertEquals(test.getYear(), y);
+        assertEquals(test.getMonth().getValue(), m);
+        assertEquals(test.getDayOfMonth(), d);
+        assertEquals(test.getHour(), h);
+        assertEquals(test.getMinute(), mi);
+        assertEquals(test.getSecond(), s);
+        assertEquals(test.getNano(), n);
+        assertEquals(test, test);
+        assertEquals(test.hashCode(), test.hashCode());
+        assertEquals(LocalDateTime.of(y, m, d, h, mi, s, n), test);
+    }
+
+    private LocalDateTime createDateMidnight(int year, int month, int day) {
+        return LocalDateTime.of(year, month, day, 0, 0);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_serialization() throws Exception {
+        assertSerializable(TEST_2007_07_15_12_30_40_987654321);
+        assertSerializable(LocalDateTime.MIN);
+        assertSerializable(LocalDateTime.MAX);
+    }
+
+    @Test
+    public void test_serialization_format() throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try (DataOutputStream dos = new DataOutputStream(baos) ) {
+            dos.writeByte(5);
+            dos.writeInt(2012);
+            dos.writeByte(9);
+            dos.writeByte(16);
+            dos.writeByte(22);
+            dos.writeByte(17);
+            dos.writeByte(59);
+            dos.writeInt(459_000_000);
+        }
+        byte[] bytes = baos.toByteArray();
+        assertSerializedBySer(LocalDateTime.of(2012, 9, 16, 22, 17, 59, 459_000_000), bytes);
+    }
+
+    //-----------------------------------------------------------------------
+    // constants
+    //-----------------------------------------------------------------------
+    @Test
+    public void constant_MIN() {
+        check(LocalDateTime.MIN, Year.MIN_VALUE, 1, 1, 0, 0, 0, 0);
+    }
+
+    @Test
+    public void constant_MAX() {
+        check(LocalDateTime.MAX, Year.MAX_VALUE, 12, 31, 23, 59, 59, 999999999);
+    }
+
+    //-----------------------------------------------------------------------
+    // now()
+    //-----------------------------------------------------------------------
+    @Test(timeOut=30000, groups={"tck"})  // TODO: remove when time zone loading is faster
+    public void now() {
+        LocalDateTime expected = LocalDateTime.now(Clock.systemDefaultZone());
+        LocalDateTime test = LocalDateTime.now();
+        long diff = Math.abs(test.getTime().toNanoOfDay() - expected.getTime().toNanoOfDay());
+        if (diff >= 100000000) {
+            // may be date change
+            expected = LocalDateTime.now(Clock.systemDefaultZone());
+            test = LocalDateTime.now();
+            diff = Math.abs(test.getTime().toNanoOfDay() - expected.getTime().toNanoOfDay());
+        }
+        assertTrue(diff < 100000000);  // less than 0.1 secs
+    }
+
+    //-----------------------------------------------------------------------
+    // now(ZoneId)
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void now_ZoneId_nullZoneId() {
+        LocalDateTime.now((ZoneId) null);
+    }
+
+    @Test(groups={"tck"})
+    public void now_ZoneId() {
+        ZoneId zone = ZoneId.of("UTC+01:02:03");
+        LocalDateTime expected = LocalDateTime.now(Clock.system(zone));
+        LocalDateTime test = LocalDateTime.now(zone);
+        for (int i = 0; i < 100; i++) {
+            if (expected.equals(test)) {
+                return;
+            }
+            expected = LocalDateTime.now(Clock.system(zone));
+            test = LocalDateTime.now(zone);
+        }
+        assertEquals(test, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // now(Clock)
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void now_Clock_nullClock() {
+        LocalDateTime.now((Clock) null);
+    }
+
+    @Test(groups={"tck"})
+    public void now_Clock_allSecsInDay_utc() {
+        for (int i = 0; i < (2 * 24 * 60 * 60); i++) {
+            Instant instant = Instant.ofEpochSecond(i).plusNanos(123456789L);
+            Clock clock = Clock.fixed(instant, ZoneOffset.UTC);
+            LocalDateTime test = LocalDateTime.now(clock);
+            assertEquals(test.getYear(), 1970);
+            assertEquals(test.getMonth(), Month.JANUARY);
+            assertEquals(test.getDayOfMonth(), (i < 24 * 60 * 60 ? 1 : 2));
+            assertEquals(test.getHour(), (i / (60 * 60)) % 24);
+            assertEquals(test.getMinute(), (i / 60) % 60);
+            assertEquals(test.getSecond(), i % 60);
+            assertEquals(test.getNano(), 123456789);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void now_Clock_allSecsInDay_offset() {
+        for (int i = 0; i < (2 * 24 * 60 * 60); i++) {
+            Instant instant = Instant.ofEpochSecond(i).plusNanos(123456789L);
+            Clock clock = Clock.fixed(instant.minusSeconds(OFFSET_PONE.getTotalSeconds()), OFFSET_PONE);
+            LocalDateTime test = LocalDateTime.now(clock);
+            assertEquals(test.getYear(), 1970);
+            assertEquals(test.getMonth(), Month.JANUARY);
+            assertEquals(test.getDayOfMonth(), (i < 24 * 60 * 60) ? 1 : 2);
+            assertEquals(test.getHour(), (i / (60 * 60)) % 24);
+            assertEquals(test.getMinute(), (i / 60) % 60);
+            assertEquals(test.getSecond(), i % 60);
+            assertEquals(test.getNano(), 123456789);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void now_Clock_allSecsInDay_beforeEpoch() {
+        LocalTime expected = LocalTime.MIDNIGHT.plusNanos(123456789L);
+        for (int i =-1; i >= -(24 * 60 * 60); i--) {
+            Instant instant = Instant.ofEpochSecond(i).plusNanos(123456789L);
+            Clock clock = Clock.fixed(instant, ZoneOffset.UTC);
+            LocalDateTime test = LocalDateTime.now(clock);
+            assertEquals(test.getYear(), 1969);
+            assertEquals(test.getMonth(), Month.DECEMBER);
+            assertEquals(test.getDayOfMonth(), 31);
+            expected = expected.minusSeconds(1);
+            assertEquals(test.getTime(), expected);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void now_Clock_maxYear() {
+        Clock clock = Clock.fixed(MAX_INSTANT, ZoneOffset.UTC);
+        LocalDateTime test = LocalDateTime.now(clock);
+        assertEquals(test, MAX_DATE_TIME);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void now_Clock_tooBig() {
+        Clock clock = Clock.fixed(MAX_INSTANT.plusSeconds(24 * 60 * 60), ZoneOffset.UTC);
+        LocalDateTime.now(clock);
+    }
+
+    @Test(groups={"tck"})
+    public void now_Clock_minYear() {
+        Clock clock = Clock.fixed(MIN_INSTANT, ZoneOffset.UTC);
+        LocalDateTime test = LocalDateTime.now(clock);
+        assertEquals(test, MIN_DATE_TIME);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void now_Clock_tooLow() {
+        Clock clock = Clock.fixed(MIN_INSTANT.minusNanos(1), ZoneOffset.UTC);
+        LocalDateTime.now(clock);
+    }
+
+    //-----------------------------------------------------------------------
+    // of() factories
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_of_4intsMonth() {
+        LocalDateTime dateTime = LocalDateTime.of(2007, Month.JULY, 15, 12, 30);
+        check(dateTime, 2007, 7, 15, 12, 30, 0, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_4intsMonth_yearTooLow() {
+        LocalDateTime.of(Integer.MIN_VALUE, Month.JULY, 15, 12, 30);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_of_4intsMonth_nullMonth() {
+        LocalDateTime.of(2007, null, 15, 12, 30);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_4intsMonth_dayTooLow() {
+        LocalDateTime.of(2007, Month.JULY, -1, 12, 30);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_4intsMonth_dayTooHigh() {
+        LocalDateTime.of(2007, Month.JULY, 32, 12, 30);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_4intsMonth_hourTooLow() {
+        LocalDateTime.of(2007, Month.JULY, 15, -1, 30);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_4intsMonth_hourTooHigh() {
+        LocalDateTime.of(2007, Month.JULY, 15, 24, 30);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_4intsMonth_minuteTooLow() {
+        LocalDateTime.of(2007, Month.JULY, 15, 12, -1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_4intsMonth_minuteTooHigh() {
+        LocalDateTime.of(2007, Month.JULY, 15, 12, 60);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_of_5intsMonth() {
+        LocalDateTime dateTime = LocalDateTime.of(2007, Month.JULY, 15, 12, 30, 40);
+        check(dateTime, 2007, 7, 15, 12, 30, 40, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_5intsMonth_yearTooLow() {
+        LocalDateTime.of(Integer.MIN_VALUE, Month.JULY, 15, 12, 30, 40);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_of_5intsMonth_nullMonth() {
+        LocalDateTime.of(2007, null, 15, 12, 30, 40);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_5intsMonth_dayTooLow() {
+        LocalDateTime.of(2007, Month.JULY, -1, 12, 30, 40);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_5intsMonth_dayTooHigh() {
+        LocalDateTime.of(2007, Month.JULY, 32, 12, 30, 40);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_5intsMonth_hourTooLow() {
+        LocalDateTime.of(2007, Month.JULY, 15, -1, 30, 40);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_5intsMonth_hourTooHigh() {
+        LocalDateTime.of(2007, Month.JULY, 15, 24, 30, 40);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_5intsMonth_minuteTooLow() {
+        LocalDateTime.of(2007, Month.JULY, 15, 12, -1, 40);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_5intsMonth_minuteTooHigh() {
+        LocalDateTime.of(2007, Month.JULY, 15, 12, 60, 40);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_5intsMonth_secondTooLow() {
+        LocalDateTime.of(2007, Month.JULY, 15, 12, 30, -1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_5intsMonth_secondTooHigh() {
+        LocalDateTime.of(2007, Month.JULY, 15, 12, 30, 60);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_of_6intsMonth() {
+        LocalDateTime dateTime = LocalDateTime.of(2007, Month.JULY, 15, 12, 30, 40, 987654321);
+        check(dateTime, 2007, 7, 15, 12, 30, 40, 987654321);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_6intsMonth_yearTooLow() {
+        LocalDateTime.of(Integer.MIN_VALUE, Month.JULY, 15, 12, 30, 40, 987654321);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_of_6intsMonth_nullMonth() {
+        LocalDateTime.of(2007, null, 15, 12, 30, 40, 987654321);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_6intsMonth_dayTooLow() {
+        LocalDateTime.of(2007, Month.JULY, -1, 12, 30, 40, 987654321);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_6intsMonth_dayTooHigh() {
+        LocalDateTime.of(2007, Month.JULY, 32, 12, 30, 40, 987654321);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_6intsMonth_hourTooLow() {
+        LocalDateTime.of(2007, Month.JULY, 15, -1, 30, 40, 987654321);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_6intsMonth_hourTooHigh() {
+        LocalDateTime.of(2007, Month.JULY, 15, 24, 30, 40, 987654321);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_6intsMonth_minuteTooLow() {
+        LocalDateTime.of(2007, Month.JULY, 15, 12, -1, 40, 987654321);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_6intsMonth_minuteTooHigh() {
+        LocalDateTime.of(2007, Month.JULY, 15, 12, 60, 40, 987654321);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_6intsMonth_secondTooLow() {
+        LocalDateTime.of(2007, Month.JULY, 15, 12, 30, -1, 987654321);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_6intsMonth_secondTooHigh() {
+        LocalDateTime.of(2007, Month.JULY, 15, 12, 30, 60, 987654321);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_6intsMonth_nanoTooLow() {
+        LocalDateTime.of(2007, Month.JULY, 15, 12, 30, 40, -1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_6intsMonth_nanoTooHigh() {
+        LocalDateTime.of(2007, Month.JULY, 15, 12, 30, 40, 1000000000);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_of_5ints() {
+        LocalDateTime dateTime = LocalDateTime.of(2007, 7, 15, 12, 30);
+        check(dateTime, 2007, 7, 15, 12, 30, 0, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_5ints_yearTooLow() {
+        LocalDateTime.of(Integer.MIN_VALUE, 7, 15, 12, 30);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_5ints_monthTooLow() {
+        LocalDateTime.of(2007, 0, 15, 12, 30);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_5ints_monthTooHigh() {
+        LocalDateTime.of(2007, 13, 15, 12, 30);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_5ints_dayTooLow() {
+        LocalDateTime.of(2007, 7, -1, 12, 30);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_5ints_dayTooHigh() {
+        LocalDateTime.of(2007, 7, 32, 12, 30);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_5ints_hourTooLow() {
+        LocalDateTime.of(2007, 7, 15, -1, 30);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_5ints_hourTooHigh() {
+        LocalDateTime.of(2007, 7, 15, 24, 30);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_5ints_minuteTooLow() {
+        LocalDateTime.of(2007, 7, 15, 12, -1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_5ints_minuteTooHigh() {
+        LocalDateTime.of(2007, 7, 15, 12, 60);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_of_6ints() {
+        LocalDateTime dateTime = LocalDateTime.of(2007, 7, 15, 12, 30, 40);
+        check(dateTime, 2007, 7, 15, 12, 30, 40, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_6ints_yearTooLow() {
+        LocalDateTime.of(Integer.MIN_VALUE, 7, 15, 12, 30, 40);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_6ints_monthTooLow() {
+        LocalDateTime.of(2007, 0, 15, 12, 30, 40);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_6ints_monthTooHigh() {
+        LocalDateTime.of(2007, 13, 15, 12, 30, 40);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_6ints_dayTooLow() {
+        LocalDateTime.of(2007, 7, -1, 12, 30, 40);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_6ints_dayTooHigh() {
+        LocalDateTime.of(2007, 7, 32, 12, 30, 40);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_6ints_hourTooLow() {
+        LocalDateTime.of(2007, 7, 15, -1, 30, 40);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_6ints_hourTooHigh() {
+        LocalDateTime.of(2007, 7, 15, 24, 30, 40);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_6ints_minuteTooLow() {
+        LocalDateTime.of(2007, 7, 15, 12, -1, 40);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_6ints_minuteTooHigh() {
+        LocalDateTime.of(2007, 7, 15, 12, 60, 40);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_6ints_secondTooLow() {
+        LocalDateTime.of(2007, 7, 15, 12, 30, -1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_6ints_secondTooHigh() {
+        LocalDateTime.of(2007, 7, 15, 12, 30, 60);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_of_7ints() {
+        LocalDateTime dateTime = LocalDateTime.of(2007, 7, 15, 12, 30, 40, 987654321);
+        check(dateTime, 2007, 7, 15, 12, 30, 40, 987654321);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_7ints_yearTooLow() {
+        LocalDateTime.of(Integer.MIN_VALUE, 7, 15, 12, 30, 40, 987654321);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_7ints_monthTooLow() {
+        LocalDateTime.of(2007, 0, 15, 12, 30, 40, 987654321);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_7ints_monthTooHigh() {
+        LocalDateTime.of(2007, 13, 15, 12, 30, 40, 987654321);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_7ints_dayTooLow() {
+        LocalDateTime.of(2007, 7, -1, 12, 30, 40, 987654321);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_7ints_dayTooHigh() {
+        LocalDateTime.of(2007, 7, 32, 12, 30, 40, 987654321);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_7ints_hourTooLow() {
+        LocalDateTime.of(2007, 7, 15, -1, 30, 40, 987654321);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_7ints_hourTooHigh() {
+        LocalDateTime.of(2007, 7, 15, 24, 30, 40, 987654321);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_7ints_minuteTooLow() {
+        LocalDateTime.of(2007, 7, 15, 12, -1, 40, 987654321);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_7ints_minuteTooHigh() {
+        LocalDateTime.of(2007, 7, 15, 12, 60, 40, 987654321);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_7ints_secondTooLow() {
+        LocalDateTime.of(2007, 7, 15, 12, 30, -1, 987654321);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_7ints_secondTooHigh() {
+        LocalDateTime.of(2007, 7, 15, 12, 30, 60, 987654321);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_7ints_nanoTooLow() {
+        LocalDateTime.of(2007, 7, 15, 12, 30, 40, -1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_7ints_nanoTooHigh() {
+        LocalDateTime.of(2007, 7, 15, 12, 30, 40, 1000000000);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_of_LocalDate_LocalTime() {
+        LocalDateTime dateTime = LocalDateTime.of(LocalDate.of(2007, 7, 15), LocalTime.of(12, 30, 40, 987654321));
+        check(dateTime, 2007, 7, 15, 12, 30, 40, 987654321);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_of_LocalDate_LocalTime_nullLocalDate() {
+        LocalDateTime.of(null, LocalTime.of(12, 30, 40, 987654321));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_of_LocalDate_LocalTime_nullLocalTime() {
+        LocalDateTime.of(LocalDate.of(2007, 7, 15), null);
+    }
+
+    //-----------------------------------------------------------------------
+    // ofInstant()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="instantFactory")
+    Object[][] data_instantFactory() {
+        return new Object[][] {
+                {Instant.ofEpochSecond(86400 + 3600 + 120 + 4, 500), ZONE_PARIS, LocalDateTime.of(1970, 1, 2, 2, 2, 4, 500)},
+                {Instant.ofEpochSecond(86400 + 3600 + 120 + 4, 500), OFFSET_MTWO, LocalDateTime.of(1970, 1, 1, 23, 2, 4, 500)},
+                {Instant.ofEpochSecond(-86400 + 4, 500), OFFSET_PTWO, LocalDateTime.of(1969, 12, 31, 2, 0, 4, 500)},
+                {OffsetDateTime.of(LocalDateTime.of(Year.MIN_VALUE, 1, 1, 0, 0), ZoneOffset.UTC).toInstant(),
+                        ZoneOffset.UTC, LocalDateTime.MIN},
+                {OffsetDateTime.of(LocalDateTime.of(Year.MAX_VALUE, 12, 31, 23, 59, 59, 999_999_999), ZoneOffset.UTC).toInstant(),
+                        ZoneOffset.UTC, LocalDateTime.MAX},
+        };
+    }
+
+    @Test(dataProvider="instantFactory")
+    public void factory_ofInstant(Instant instant, ZoneId zone, LocalDateTime expected) {
+        LocalDateTime test = LocalDateTime.ofInstant(instant, zone);
+        assertEquals(test, expected);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_ofInstant_instantTooBig() {
+        LocalDateTime.ofInstant(Instant.MAX, OFFSET_PONE) ;
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_ofInstant_instantTooSmall() {
+        LocalDateTime.ofInstant(Instant.MIN, OFFSET_PONE) ;
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_ofInstant_nullInstant() {
+        LocalDateTime.ofInstant((Instant) null, ZONE_GAZA);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_ofInstant_nullZone() {
+        LocalDateTime.ofInstant(Instant.EPOCH, (ZoneId) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // ofEpochSecond()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_ofEpochSecond_longOffset_afterEpoch() {
+        LocalDateTime base = LocalDateTime.of(1970, 1, 1, 2, 0, 0, 500);
+        for (int i = 0; i < 100000; i++) {
+            LocalDateTime test = LocalDateTime.ofEpochSecond(i, 500, OFFSET_PTWO);
+            assertEquals(test, base.plusSeconds(i));
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void factory_ofEpochSecond_longOffset_beforeEpoch() {
+        LocalDateTime base = LocalDateTime.of(1970, 1, 1, 2, 0, 0, 500);
+        for (int i = 0; i < 100000; i++) {
+            LocalDateTime test = LocalDateTime.ofEpochSecond(-i, 500, OFFSET_PTWO);
+            assertEquals(test, base.minusSeconds(i));
+        }
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_ofEpochSecond_longOffset_tooBig() {
+        LocalDateTime.ofEpochSecond(Long.MAX_VALUE, 500, OFFSET_PONE);  // TODO: better test
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_ofEpochSecond_longOffset_tooSmall() {
+        LocalDateTime.ofEpochSecond(Long.MIN_VALUE, 500, OFFSET_PONE);  // TODO: better test
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_ofEpochSecond_badNanos_toBig() {
+        LocalDateTime.ofEpochSecond(0, 1_000_000_000, OFFSET_PONE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_ofEpochSecond_badNanos_toSmall() {
+        LocalDateTime.ofEpochSecond(0, -1, OFFSET_PONE);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_ofEpochSecond_longOffset_nullOffset() {
+        LocalDateTime.ofEpochSecond(0L, 500, null);
+    }
+
+    //-----------------------------------------------------------------------
+    // from()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_from_TemporalAccessor() {
+        LocalDateTime base = LocalDateTime.of(2007, 7, 15, 17, 30);
+        assertEquals(LocalDateTime.from(base), base);
+        assertEquals(LocalDateTime.from(ZonedDateTime.of(base, ZoneOffset.ofHours(2))), base);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_from_TemporalAccessor_invalid_noDerive() {
+        LocalDateTime.from(LocalTime.of(12, 30));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_from_TemporalAccessor_null() {
+        LocalDateTime.from((TemporalAccessor) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // parse()
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="sampleToString", groups={"tck"})
+    public void test_parse(int y, int month, int d, int h, int m, int s, int n, String text) {
+        LocalDateTime t = LocalDateTime.parse(text);
+        assertEquals(t.getYear(), y);
+        assertEquals(t.getMonth().getValue(), month);
+        assertEquals(t.getDayOfMonth(), d);
+        assertEquals(t.getHour(), h);
+        assertEquals(t.getMinute(), m);
+        assertEquals(t.getSecond(), s);
+        assertEquals(t.getNano(), n);
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"})
+    public void factory_parse_illegalValue() {
+        LocalDateTime.parse("2008-06-32T11:15");
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"})
+    public void factory_parse_invalidValue() {
+        LocalDateTime.parse("2008-06-31T11:15");
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_parse_nullText() {
+        LocalDateTime.parse((String) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // parse(DateTimeFormatter)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_parse_formatter() {
+        DateTimeFormatter f = DateTimeFormatters.pattern("y M d H m s");
+        LocalDateTime test = LocalDateTime.parse("2010 12 3 11 30 45", f);
+        assertEquals(test, LocalDateTime.of(2010, 12, 3, 11, 30, 45));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_parse_formatter_nullText() {
+        DateTimeFormatter f = DateTimeFormatters.pattern("y M d H m s");
+        LocalDateTime.parse((String) null, f);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_parse_formatter_nullFormatter() {
+        LocalDateTime.parse("ANY", null);
+    }
+
+    //-----------------------------------------------------------------------
+    // get(TemporalField)
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_get_TemporalField() {
+        LocalDateTime test = LocalDateTime.of(2008, 6, 30, 12, 30, 40, 987654321);
+        assertEquals(test.get(ChronoField.YEAR), 2008);
+        assertEquals(test.get(ChronoField.MONTH_OF_YEAR), 6);
+        assertEquals(test.get(ChronoField.DAY_OF_MONTH), 30);
+        assertEquals(test.get(ChronoField.DAY_OF_WEEK), 1);
+        assertEquals(test.get(ChronoField.DAY_OF_YEAR), 182);
+
+        assertEquals(test.get(ChronoField.HOUR_OF_DAY), 12);
+        assertEquals(test.get(ChronoField.MINUTE_OF_HOUR), 30);
+        assertEquals(test.get(ChronoField.SECOND_OF_MINUTE), 40);
+        assertEquals(test.get(ChronoField.NANO_OF_SECOND), 987654321);
+        assertEquals(test.get(ChronoField.HOUR_OF_AMPM), 0);
+        assertEquals(test.get(ChronoField.AMPM_OF_DAY), 1);
+    }
+
+    @Test
+    public void test_getLong_TemporalField() {
+        LocalDateTime test = LocalDateTime.of(2008, 6, 30, 12, 30, 40, 987654321);
+        assertEquals(test.getLong(ChronoField.YEAR), 2008);
+        assertEquals(test.getLong(ChronoField.MONTH_OF_YEAR), 6);
+        assertEquals(test.getLong(ChronoField.DAY_OF_MONTH), 30);
+        assertEquals(test.getLong(ChronoField.DAY_OF_WEEK), 1);
+        assertEquals(test.getLong(ChronoField.DAY_OF_YEAR), 182);
+
+        assertEquals(test.getLong(ChronoField.HOUR_OF_DAY), 12);
+        assertEquals(test.getLong(ChronoField.MINUTE_OF_HOUR), 30);
+        assertEquals(test.getLong(ChronoField.SECOND_OF_MINUTE), 40);
+        assertEquals(test.getLong(ChronoField.NANO_OF_SECOND), 987654321);
+        assertEquals(test.getLong(ChronoField.HOUR_OF_AMPM), 0);
+        assertEquals(test.getLong(ChronoField.AMPM_OF_DAY), 1);
+    }
+
+    //-----------------------------------------------------------------------
+    // query(TemporalQuery)
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_query_chrono() {
+        assertEquals(TEST_2007_07_15_12_30_40_987654321.query(Queries.chrono()), ISOChrono.INSTANCE);
+        assertEquals(Queries.chrono().queryFrom(TEST_2007_07_15_12_30_40_987654321), ISOChrono.INSTANCE);
+    }
+
+    @Test
+    public void test_query_zoneId() {
+        assertEquals(TEST_2007_07_15_12_30_40_987654321.query(Queries.zoneId()), null);
+        assertEquals(Queries.zoneId().queryFrom(TEST_2007_07_15_12_30_40_987654321), null);
+    }
+
+    @Test
+    public void test_query_precision() {
+        assertEquals(TEST_2007_07_15_12_30_40_987654321.query(Queries.precision()), NANOS);
+        assertEquals(Queries.precision().queryFrom(TEST_2007_07_15_12_30_40_987654321), NANOS);
+    }
+
+    @Test
+    public void test_query_offset() {
+        assertEquals(TEST_2007_07_15_12_30_40_987654321.query(Queries.offset()), null);
+        assertEquals(Queries.offset().queryFrom(TEST_2007_07_15_12_30_40_987654321), null);
+    }
+
+    @Test
+    public void test_query_zone() {
+        assertEquals(TEST_2007_07_15_12_30_40_987654321.query(Queries.zone()), null);
+        assertEquals(Queries.zone().queryFrom(TEST_2007_07_15_12_30_40_987654321), null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_query_null() {
+        TEST_2007_07_15_12_30_40_987654321.query(null);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sampleDates")
+    Object[][] provider_sampleDates() {
+        return new Object[][] {
+            {2008, 7, 5},
+            {2007, 7, 5},
+            {2006, 7, 5},
+            {2005, 7, 5},
+            {2004, 1, 1},
+            {-1, 1, 2},
+        };
+    }
+
+    @DataProvider(name="sampleTimes")
+    Object[][] provider_sampleTimes() {
+        return new Object[][] {
+            {0, 0, 0, 0},
+            {0, 0, 0, 1},
+            {0, 0, 1, 0},
+            {0, 0, 1, 1},
+            {0, 1, 0, 0},
+            {0, 1, 0, 1},
+            {0, 1, 1, 0},
+            {0, 1, 1, 1},
+            {1, 0, 0, 0},
+            {1, 0, 0, 1},
+            {1, 0, 1, 0},
+            {1, 0, 1, 1},
+            {1, 1, 0, 0},
+            {1, 1, 0, 1},
+            {1, 1, 1, 0},
+            {1, 1, 1, 1},
+        };
+    }
+
+    //-----------------------------------------------------------------------
+    // get*()
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="sampleDates", groups={"tck"})
+    public void test_get_dates(int y, int m, int d) {
+        LocalDateTime a = LocalDateTime.of(y, m, d, 12, 30);
+        assertEquals(a.getYear(), y);
+        assertEquals(a.getMonth(), Month.of(m));
+        assertEquals(a.getDayOfMonth(), d);
+    }
+
+    @Test(dataProvider="sampleDates", groups={"tck"})
+    public void test_getDOY(int y, int m, int d) {
+        LocalDateTime a = LocalDateTime.of(y, m, d, 12 ,30);
+        int total = 0;
+        for (int i = 1; i < m; i++) {
+            total += Month.of(i).length(isIsoLeap(y));
+        }
+        int doy = total + d;
+        assertEquals(a.getDayOfYear(), doy);
+    }
+
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_get_times(int h, int m, int s, int ns) {
+        LocalDateTime a = LocalDateTime.of(TEST_2007_07_15_12_30_40_987654321.getDate(), LocalTime.of(h, m, s, ns));
+        assertEquals(a.getHour(), h);
+        assertEquals(a.getMinute(), m);
+        assertEquals(a.getSecond(), s);
+        assertEquals(a.getNano(), ns);
+    }
+
+    //-----------------------------------------------------------------------
+    // getDayOfWeek()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_getDayOfWeek() {
+        DayOfWeek dow = DayOfWeek.MONDAY;
+        for (Month month : Month.values()) {
+            int length = month.length(false);
+            for (int i = 1; i <= length; i++) {
+                LocalDateTime d = LocalDateTime.of(LocalDate.of(2007, month, i),
+                        TEST_2007_07_15_12_30_40_987654321.getTime());
+                assertSame(d.getDayOfWeek(), dow);
+                dow = dow.plus(1);
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // with()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_with_adjustment() {
+        final LocalDateTime sample = LocalDateTime.of(2012, 3, 4, 23, 5);
+        TemporalAdjuster adjuster = new TemporalAdjuster() {
+            @Override
+            public Temporal adjustInto(Temporal dateTime) {
+                return sample;
+            }
+        };
+        assertEquals(TEST_2007_07_15_12_30_40_987654321.with(adjuster), sample);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_with_adjustment_null() {
+        TEST_2007_07_15_12_30_40_987654321.with((TemporalAdjuster) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // withYear()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withYear_int_normal() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.withYear(2008);
+        check(t, 2008, 7, 15, 12, 30, 40, 987654321);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withYear_int_invalid() {
+        TEST_2007_07_15_12_30_40_987654321.withYear(Year.MIN_VALUE - 1);
+    }
+
+    @Test(groups={"tck"})
+    public void test_withYear_int_adjustDay() {
+        LocalDateTime t = LocalDateTime.of(2008, 2, 29, 12, 30).withYear(2007);
+        LocalDateTime expected = LocalDateTime.of(2007, 2, 28, 12, 30);
+        assertEquals(t, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // withMonth()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withMonth_int_normal() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.withMonth(1);
+        check(t, 2007, 1, 15, 12, 30, 40, 987654321);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withMonth_int_invalid() {
+        TEST_2007_07_15_12_30_40_987654321.withMonth(13);
+    }
+
+    @Test(groups={"tck"})
+    public void test_withMonth_int_adjustDay() {
+        LocalDateTime t = LocalDateTime.of(2007, 12, 31, 12, 30).withMonth(11);
+        LocalDateTime expected = LocalDateTime.of(2007, 11, 30, 12, 30);
+        assertEquals(t, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // withDayOfMonth()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withDayOfMonth_normal() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.withDayOfMonth(1);
+        check(t, 2007, 7, 1, 12, 30, 40, 987654321);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withDayOfMonth_invalid() {
+        LocalDateTime.of(2007, 11, 30, 12, 30).withDayOfMonth(32);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withDayOfMonth_invalidCombination() {
+        LocalDateTime.of(2007, 11, 30, 12, 30).withDayOfMonth(31);
+    }
+
+    //-----------------------------------------------------------------------
+    // withDayOfYear(int)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withDayOfYear_normal() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.withDayOfYear(33);
+        assertEquals(t, LocalDateTime.of(2007, 2, 2, 12, 30, 40, 987654321));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withDayOfYear_illegal() {
+        TEST_2007_07_15_12_30_40_987654321.withDayOfYear(367);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withDayOfYear_invalid() {
+        TEST_2007_07_15_12_30_40_987654321.withDayOfYear(366);
+    }
+
+    //-----------------------------------------------------------------------
+    // withHour()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withHour_normal() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321;
+        for (int i = 0; i < 24; i++) {
+            t = t.withHour(i);
+            assertEquals(t.getHour(), i);
+        }
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withHour_hourTooLow() {
+        TEST_2007_07_15_12_30_40_987654321.withHour(-1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withHour_hourTooHigh() {
+        TEST_2007_07_15_12_30_40_987654321.withHour(24);
+    }
+
+    //-----------------------------------------------------------------------
+    // withMinute()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withMinute_normal() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321;
+        for (int i = 0; i < 60; i++) {
+            t = t.withMinute(i);
+            assertEquals(t.getMinute(), i);
+        }
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withMinute_minuteTooLow() {
+        TEST_2007_07_15_12_30_40_987654321.withMinute(-1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withMinute_minuteTooHigh() {
+        TEST_2007_07_15_12_30_40_987654321.withMinute(60);
+    }
+
+    //-----------------------------------------------------------------------
+    // withSecond()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withSecond_normal() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321;
+        for (int i = 0; i < 60; i++) {
+            t = t.withSecond(i);
+            assertEquals(t.getSecond(), i);
+        }
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withSecond_secondTooLow() {
+        TEST_2007_07_15_12_30_40_987654321.withSecond(-1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withSecond_secondTooHigh() {
+        TEST_2007_07_15_12_30_40_987654321.withSecond(60);
+    }
+
+    //-----------------------------------------------------------------------
+    // withNano()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withNanoOfSecond_normal() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321;
+        t = t.withNano(1);
+        assertEquals(t.getNano(), 1);
+        t = t.withNano(10);
+        assertEquals(t.getNano(), 10);
+        t = t.withNano(100);
+        assertEquals(t.getNano(), 100);
+        t = t.withNano(999999999);
+        assertEquals(t.getNano(), 999999999);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withNanoOfSecond_nanoTooLow() {
+        TEST_2007_07_15_12_30_40_987654321.withNano(-1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withNanoOfSecond_nanoTooHigh() {
+        TEST_2007_07_15_12_30_40_987654321.withNano(1000000000);
+    }
+
+    //-----------------------------------------------------------------------
+    // truncatedTo(TemporalUnit)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_truncatedTo_normal() {
+        assertEquals(TEST_2007_07_15_12_30_40_987654321.truncatedTo(NANOS), TEST_2007_07_15_12_30_40_987654321);
+        assertEquals(TEST_2007_07_15_12_30_40_987654321.truncatedTo(SECONDS), TEST_2007_07_15_12_30_40_987654321.withNano(0));
+        assertEquals(TEST_2007_07_15_12_30_40_987654321.truncatedTo(DAYS), TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_truncatedTo_null() {
+        TEST_2007_07_15_12_30_40_987654321.truncatedTo(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // plus(adjuster)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plus_adjuster() {
+        Period p = Period.ofTime(0, 0, 62, 3);
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plus(p);
+        assertEquals(t, LocalDateTime.of(2007, 7, 15, 12, 31, 42, 987654324));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_plus_adjuster_null() {
+        TEST_2007_07_15_12_30_40_987654321.plus((TemporalAdder) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // plus(Period)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plus_Period_positiveMonths() {
+        MockSimplePeriod period = MockSimplePeriod.of(7, ChronoUnit.MONTHS);
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plus(period);
+        assertEquals(t, LocalDateTime.of(2008, 2, 15, 12, 30, 40, 987654321));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plus_Period_negativeDays() {
+        MockSimplePeriod period = MockSimplePeriod.of(-25, ChronoUnit.DAYS);
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plus(period);
+        assertEquals(t, LocalDateTime.of(2007, 6, 20, 12, 30, 40, 987654321));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_plus_Period_null() {
+        TEST_2007_07_15_12_30_40_987654321.plus((MockSimplePeriod) null);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plus_Period_invalidTooLarge() {
+        MockSimplePeriod period = MockSimplePeriod.of(1, ChronoUnit.YEARS);
+        LocalDateTime.of(Year.MAX_VALUE, 1, 1, 0, 0).plus(period);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plus_Period_invalidTooSmall() {
+        MockSimplePeriod period = MockSimplePeriod.of(-1, ChronoUnit.YEARS);
+        LocalDateTime.of(Year.MIN_VALUE, 1, 1, 0, 0).plus(period);
+    }
+
+    //-----------------------------------------------------------------------
+    // plus(long,TemporalUnit)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plus_longTemporalUnit_positiveMonths() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plus(7, ChronoUnit.MONTHS);
+        assertEquals(t, LocalDateTime.of(2008, 2, 15, 12, 30, 40, 987654321));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plus_longTemporalUnit_negativeDays() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plus(-25, ChronoUnit.DAYS);
+        assertEquals(t, LocalDateTime.of(2007, 6, 20, 12, 30, 40, 987654321));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_plus_longTemporalUnit_null() {
+        TEST_2007_07_15_12_30_40_987654321.plus(1, (TemporalUnit) null);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plus_longTemporalUnit_invalidTooLarge() {
+        LocalDateTime.of(Year.MAX_VALUE, 1, 1, 0, 0).plus(1, ChronoUnit.YEARS);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plus_longTemporalUnit_invalidTooSmall() {
+        LocalDateTime.of(Year.MIN_VALUE, 1, 1, 0, 0).plus(-1, ChronoUnit.YEARS);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusYears()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusYears_int_normal() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusYears(1);
+        check(t, 2008, 7, 15, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusYears_int_negative() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusYears(-1);
+        check(t, 2006, 7, 15, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusYears_int_adjustDay() {
+        LocalDateTime t = createDateMidnight(2008, 2, 29).plusYears(1);
+        check(t, 2009, 2, 28, 0, 0, 0, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusYears_int_invalidTooLarge() {
+        createDateMidnight(Year.MAX_VALUE, 1, 1).plusYears(1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusYears_int_invalidTooSmall() {
+        LocalDate.of(Year.MIN_VALUE, 1, 1).plusYears(-1);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusMonths()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusMonths_int_normal() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusMonths(1);
+        check(t, 2007, 8, 15, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMonths_int_overYears() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusMonths(25);
+        check(t, 2009, 8, 15, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMonths_int_negative() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusMonths(-1);
+        check(t, 2007, 6, 15, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMonths_int_negativeAcrossYear() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusMonths(-7);
+        check(t, 2006, 12, 15, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMonths_int_negativeOverYears() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusMonths(-31);
+        check(t, 2004, 12, 15, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMonths_int_adjustDayFromLeapYear() {
+        LocalDateTime t = createDateMidnight(2008, 2, 29).plusMonths(12);
+        check(t, 2009, 2, 28, 0, 0, 0, 0);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMonths_int_adjustDayFromMonthLength() {
+        LocalDateTime t = createDateMidnight(2007, 3, 31).plusMonths(1);
+        check(t, 2007, 4, 30, 0, 0, 0, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusMonths_int_invalidTooLarge() {
+        createDateMidnight(Year.MAX_VALUE, 12, 1).plusMonths(1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusMonths_int_invalidTooSmall() {
+        createDateMidnight(Year.MIN_VALUE, 1, 1).plusMonths(-1);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusWeeks()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="samplePlusWeeksSymmetry")
+    Object[][] provider_samplePlusWeeksSymmetry() {
+        return new Object[][] {
+            {createDateMidnight(-1, 1, 1)},
+            {createDateMidnight(-1, 2, 28)},
+            {createDateMidnight(-1, 3, 1)},
+            {createDateMidnight(-1, 12, 31)},
+            {createDateMidnight(0, 1, 1)},
+            {createDateMidnight(0, 2, 28)},
+            {createDateMidnight(0, 2, 29)},
+            {createDateMidnight(0, 3, 1)},
+            {createDateMidnight(0, 12, 31)},
+            {createDateMidnight(2007, 1, 1)},
+            {createDateMidnight(2007, 2, 28)},
+            {createDateMidnight(2007, 3, 1)},
+            {createDateMidnight(2007, 12, 31)},
+            {createDateMidnight(2008, 1, 1)},
+            {createDateMidnight(2008, 2, 28)},
+            {createDateMidnight(2008, 2, 29)},
+            {createDateMidnight(2008, 3, 1)},
+            {createDateMidnight(2008, 12, 31)},
+            {createDateMidnight(2099, 1, 1)},
+            {createDateMidnight(2099, 2, 28)},
+            {createDateMidnight(2099, 3, 1)},
+            {createDateMidnight(2099, 12, 31)},
+            {createDateMidnight(2100, 1, 1)},
+            {createDateMidnight(2100, 2, 28)},
+            {createDateMidnight(2100, 3, 1)},
+            {createDateMidnight(2100, 12, 31)},
+        };
+    }
+
+    @Test(dataProvider="samplePlusWeeksSymmetry", groups={"tck"})
+    public void test_plusWeeks_symmetry(LocalDateTime reference) {
+        for (int weeks = 0; weeks < 365 * 8; weeks++) {
+            LocalDateTime t = reference.plusWeeks(weeks).plusWeeks(-weeks);
+            assertEquals(t, reference);
+
+            t = reference.plusWeeks(-weeks).plusWeeks(weeks);
+            assertEquals(t, reference);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusWeeks_normal() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusWeeks(1);
+        check(t, 2007, 7, 22, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusWeeks_overMonths() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusWeeks(9);
+        check(t, 2007, 9, 16, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusWeeks_overYears() {
+        LocalDateTime t = LocalDateTime.of(2006, 7, 16, 12, 30, 40, 987654321).plusWeeks(52);
+        assertEquals(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusWeeks_overLeapYears() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusYears(-1).plusWeeks(104);
+        check(t, 2008, 7, 12, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusWeeks_negative() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusWeeks(-1);
+        check(t, 2007, 7, 8, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusWeeks_negativeAcrossYear() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusWeeks(-28);
+        check(t, 2006, 12, 31, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusWeeks_negativeOverYears() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusWeeks(-104);
+        check(t, 2005, 7, 17, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusWeeks_maximum() {
+        LocalDateTime t = createDateMidnight(Year.MAX_VALUE, 12, 24).plusWeeks(1);
+        check(t, Year.MAX_VALUE, 12, 31, 0, 0, 0, 0);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusWeeks_minimum() {
+        LocalDateTime t = createDateMidnight(Year.MIN_VALUE, 1, 8).plusWeeks(-1);
+        check(t, Year.MIN_VALUE, 1, 1, 0, 0, 0, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusWeeks_invalidTooLarge() {
+        createDateMidnight(Year.MAX_VALUE, 12, 25).plusWeeks(1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusWeeks_invalidTooSmall() {
+        createDateMidnight(Year.MIN_VALUE, 1, 7).plusWeeks(-1);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusDays()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="samplePlusDaysSymmetry")
+    Object[][] provider_samplePlusDaysSymmetry() {
+        return new Object[][] {
+            {createDateMidnight(-1, 1, 1)},
+            {createDateMidnight(-1, 2, 28)},
+            {createDateMidnight(-1, 3, 1)},
+            {createDateMidnight(-1, 12, 31)},
+            {createDateMidnight(0, 1, 1)},
+            {createDateMidnight(0, 2, 28)},
+            {createDateMidnight(0, 2, 29)},
+            {createDateMidnight(0, 3, 1)},
+            {createDateMidnight(0, 12, 31)},
+            {createDateMidnight(2007, 1, 1)},
+            {createDateMidnight(2007, 2, 28)},
+            {createDateMidnight(2007, 3, 1)},
+            {createDateMidnight(2007, 12, 31)},
+            {createDateMidnight(2008, 1, 1)},
+            {createDateMidnight(2008, 2, 28)},
+            {createDateMidnight(2008, 2, 29)},
+            {createDateMidnight(2008, 3, 1)},
+            {createDateMidnight(2008, 12, 31)},
+            {createDateMidnight(2099, 1, 1)},
+            {createDateMidnight(2099, 2, 28)},
+            {createDateMidnight(2099, 3, 1)},
+            {createDateMidnight(2099, 12, 31)},
+            {createDateMidnight(2100, 1, 1)},
+            {createDateMidnight(2100, 2, 28)},
+            {createDateMidnight(2100, 3, 1)},
+            {createDateMidnight(2100, 12, 31)},
+        };
+    }
+
+    @Test(dataProvider="samplePlusDaysSymmetry", groups={"tck"})
+    public void test_plusDays_symmetry(LocalDateTime reference) {
+        for (int days = 0; days < 365 * 8; days++) {
+            LocalDateTime t = reference.plusDays(days).plusDays(-days);
+            assertEquals(t, reference);
+
+            t = reference.plusDays(-days).plusDays(days);
+            assertEquals(t, reference);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusDays_normal() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusDays(1);
+        check(t, 2007, 7, 16, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusDays_overMonths() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusDays(62);
+        check(t, 2007, 9, 15, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusDays_overYears() {
+        LocalDateTime t = LocalDateTime.of(2006, 7, 14, 12, 30, 40, 987654321).plusDays(366);
+        assertEquals(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusDays_overLeapYears() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusYears(-1).plusDays(365 + 366);
+        check(t, 2008, 7, 15, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusDays_negative() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusDays(-1);
+        check(t, 2007, 7, 14, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusDays_negativeAcrossYear() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusDays(-196);
+        check(t, 2006, 12, 31, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusDays_negativeOverYears() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusDays(-730);
+        check(t, 2005, 7, 15, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusDays_maximum() {
+        LocalDateTime t = createDateMidnight(Year.MAX_VALUE, 12, 30).plusDays(1);
+        check(t, Year.MAX_VALUE, 12, 31, 0, 0, 0, 0);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusDays_minimum() {
+        LocalDateTime t = createDateMidnight(Year.MIN_VALUE, 1, 2).plusDays(-1);
+        check(t, Year.MIN_VALUE, 1, 1, 0, 0, 0, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusDays_invalidTooLarge() {
+        createDateMidnight(Year.MAX_VALUE, 12, 31).plusDays(1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusDays_invalidTooSmall() {
+        createDateMidnight(Year.MIN_VALUE, 1, 1).plusDays(-1);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void test_plusDays_overflowTooLarge() {
+        createDateMidnight(Year.MAX_VALUE, 12, 31).plusDays(Long.MAX_VALUE);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void test_plusDays_overflowTooSmall() {
+        createDateMidnight(Year.MIN_VALUE, 1, 1).plusDays(Long.MIN_VALUE);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusHours()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusHours_one() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT);
+        LocalDate d = t.getDate();
+
+        for (int i = 0; i < 50; i++) {
+            t = t.plusHours(1);
+
+            if ((i + 1) % 24 == 0) {
+                d = d.plusDays(1);
+            }
+
+            assertEquals(t.getDate(), d);
+            assertEquals(t.getHour(), (i + 1) % 24);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusHours_fromZero() {
+        LocalDateTime base = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT);
+        LocalDate d = base.getDate().minusDays(3);
+        LocalTime t = LocalTime.of(21, 0);
+
+        for (int i = -50; i < 50; i++) {
+            LocalDateTime dt = base.plusHours(i);
+            t = t.plusHours(1);
+
+            if (t.getHour() == 0) {
+                d = d.plusDays(1);
+            }
+
+            assertEquals(dt.getDate(), d);
+            assertEquals(dt.getTime(), t);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusHours_fromOne() {
+        LocalDateTime base = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(1, 0));
+        LocalDate d = base.getDate().minusDays(3);
+        LocalTime t = LocalTime.of(22, 0);
+
+        for (int i = -50; i < 50; i++) {
+            LocalDateTime dt = base.plusHours(i);
+
+            t = t.plusHours(1);
+
+            if (t.getHour() == 0) {
+                d = d.plusDays(1);
+            }
+
+            assertEquals(dt.getDate(), d);
+            assertEquals(dt.getTime(), t);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // plusMinutes()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusMinutes_one() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT);
+        LocalDate d = t.getDate();
+
+        int hour = 0;
+        int min = 0;
+
+        for (int i = 0; i < 70; i++) {
+            t = t.plusMinutes(1);
+            min++;
+            if (min == 60) {
+                hour++;
+                min = 0;
+            }
+
+            assertEquals(t.getDate(), d);
+            assertEquals(t.getHour(), hour);
+            assertEquals(t.getMinute(), min);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMinutes_fromZero() {
+        LocalDateTime base = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT);
+        LocalDate d = base.getDate().minusDays(1);
+        LocalTime t = LocalTime.of(22, 49);
+
+        for (int i = -70; i < 70; i++) {
+            LocalDateTime dt = base.plusMinutes(i);
+            t = t.plusMinutes(1);
+
+            if (t == LocalTime.MIDNIGHT) {
+                d = d.plusDays(1);
+            }
+
+            assertEquals(dt.getDate(), d, String.valueOf(i));
+            assertEquals(dt.getTime(), t, String.valueOf(i));
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMinutes_noChange_oneDay() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusMinutes(24 * 60);
+        assertEquals(t.getDate(), TEST_2007_07_15_12_30_40_987654321.getDate().plusDays(1));
+    }
+
+    //-----------------------------------------------------------------------
+    // plusSeconds()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusSeconds_one() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT);
+        LocalDate d = t.getDate();
+
+        int hour = 0;
+        int min = 0;
+        int sec = 0;
+
+        for (int i = 0; i < 3700; i++) {
+            t = t.plusSeconds(1);
+            sec++;
+            if (sec == 60) {
+                min++;
+                sec = 0;
+            }
+            if (min == 60) {
+                hour++;
+                min = 0;
+            }
+
+            assertEquals(t.getDate(), d);
+            assertEquals(t.getHour(), hour);
+            assertEquals(t.getMinute(), min);
+            assertEquals(t.getSecond(), sec);
+        }
+    }
+
+    @DataProvider(name="plusSeconds_fromZero")
+    Iterator<Object[]> plusSeconds_fromZero() {
+        return new Iterator<Object[]>() {
+            int delta = 30;
+
+            int i = -3660;
+            LocalDate date = TEST_2007_07_15_12_30_40_987654321.getDate().minusDays(1);
+            int hour = 22;
+            int min = 59;
+            int sec = 0;
+
+            public boolean hasNext() {
+                return i <= 3660;
+            }
+
+            public Object[] next() {
+                final Object[] ret = new Object[] {i, date, hour, min, sec};
+                i += delta;
+                sec += delta;
+
+                if (sec >= 60) {
+                    min++;
+                    sec -= 60;
+
+                    if (min == 60) {
+                        hour++;
+                        min = 0;
+
+                        if (hour == 24) {
+                            hour = 0;
+                        }
+                    }
+                }
+
+                if (i == 0) {
+                    date = date.plusDays(1);
+                }
+
+                return ret;
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    @Test(dataProvider="plusSeconds_fromZero", groups={"tck"})
+    public void test_plusSeconds_fromZero(int seconds, LocalDate date, int hour, int min, int sec) {
+        LocalDateTime base = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT);
+        LocalDateTime t = base.plusSeconds(seconds);
+
+        assertEquals(date, t.getDate());
+        assertEquals(hour, t.getHour());
+        assertEquals(min, t.getMinute());
+        assertEquals(sec, t.getSecond());
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusSeconds_noChange_oneDay() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusSeconds(24 * 60 * 60);
+        assertEquals(t.getDate(), TEST_2007_07_15_12_30_40_987654321.getDate().plusDays(1));
+    }
+
+    //-----------------------------------------------------------------------
+    // plusNanos()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusNanos_halfABillion() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT);
+        LocalDate d = t.getDate();
+
+        int hour = 0;
+        int min = 0;
+        int sec = 0;
+        int nanos = 0;
+
+        for (long i = 0; i < 3700 * 1000000000L; i+= 500000000) {
+            t = t.plusNanos(500000000);
+            nanos += 500000000;
+            if (nanos == 1000000000) {
+                sec++;
+                nanos = 0;
+            }
+            if (sec == 60) {
+                min++;
+                sec = 0;
+            }
+            if (min == 60) {
+                hour++;
+                min = 0;
+            }
+
+            assertEquals(t.getDate(), d, String.valueOf(i));
+            assertEquals(t.getHour(), hour);
+            assertEquals(t.getMinute(), min);
+            assertEquals(t.getSecond(), sec);
+            assertEquals(t.getNano(), nanos);
+        }
+    }
+
+    @DataProvider(name="plusNanos_fromZero")
+    Iterator<Object[]> plusNanos_fromZero() {
+        return new Iterator<Object[]>() {
+            long delta = 7500000000L;
+
+            long i = -3660 * 1000000000L;
+            LocalDate date = TEST_2007_07_15_12_30_40_987654321.getDate().minusDays(1);
+            int hour = 22;
+            int min = 59;
+            int sec = 0;
+            long nanos = 0;
+
+            public boolean hasNext() {
+                return i <= 3660 * 1000000000L;
+            }
+
+            public Object[] next() {
+                final Object[] ret = new Object[] {i, date, hour, min, sec, (int)nanos};
+                i += delta;
+                nanos += delta;
+
+                if (nanos >= 1000000000L) {
+                    sec += nanos / 1000000000L;
+                    nanos %= 1000000000L;
+
+                    if (sec >= 60) {
+                        min++;
+                        sec %= 60;
+
+                        if (min == 60) {
+                            hour++;
+                            min = 0;
+
+                            if (hour == 24) {
+                                hour = 0;
+                                date = date.plusDays(1);
+                            }
+                        }
+                    }
+                }
+
+                return ret;
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    @Test(dataProvider="plusNanos_fromZero", groups={"tck"})
+    public void test_plusNanos_fromZero(long nanoseconds, LocalDate date, int hour, int min, int sec, int nanos) {
+        LocalDateTime base = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT);
+        LocalDateTime t = base.plusNanos(nanoseconds);
+
+        assertEquals(date, t.getDate());
+        assertEquals(hour, t.getHour());
+        assertEquals(min, t.getMinute());
+        assertEquals(sec, t.getSecond());
+        assertEquals(nanos, t.getNano());
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusNanos_noChange_oneDay() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusNanos(24 * 60 * 60 * 1000000000L);
+        assertEquals(t.getDate(), TEST_2007_07_15_12_30_40_987654321.getDate().plusDays(1));
+    }
+
+    //-----------------------------------------------------------------------
+    // minus(adjuster)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minus_adjuster() {
+        Period p = Period.ofTime(0, 0, 62, 3);
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minus(p);
+        assertEquals(t, LocalDateTime.of(2007, 7, 15, 12, 29, 38, 987654318));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_minus_adjuster_null() {
+        TEST_2007_07_15_12_30_40_987654321.minus((TemporalSubtractor) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // minus(Period)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minus_Period_positiveMonths() {
+        MockSimplePeriod period = MockSimplePeriod.of(7, ChronoUnit.MONTHS);
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minus(period);
+        assertEquals(t, LocalDateTime.of(2006, 12, 15, 12, 30, 40, 987654321));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minus_Period_negativeDays() {
+        MockSimplePeriod period = MockSimplePeriod.of(-25, ChronoUnit.DAYS);
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minus(period);
+        assertEquals(t, LocalDateTime.of(2007, 8, 9, 12, 30, 40, 987654321));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_minus_Period_null() {
+        TEST_2007_07_15_12_30_40_987654321.minus((MockSimplePeriod) null);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minus_Period_invalidTooLarge() {
+        MockSimplePeriod period = MockSimplePeriod.of(-1, ChronoUnit.YEARS);
+        LocalDateTime.of(Year.MAX_VALUE, 1, 1, 0, 0).minus(period);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minus_Period_invalidTooSmall() {
+        MockSimplePeriod period = MockSimplePeriod.of(1, ChronoUnit.YEARS);
+        LocalDateTime.of(Year.MIN_VALUE, 1, 1, 0, 0).minus(period);
+    }
+
+    //-----------------------------------------------------------------------
+    // minus(long,TemporalUnit)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minus_longTemporalUnit_positiveMonths() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minus(7, ChronoUnit.MONTHS);
+        assertEquals(t, LocalDateTime.of(2006, 12, 15, 12, 30, 40, 987654321));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minus_longTemporalUnit_negativeDays() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minus(-25, ChronoUnit.DAYS);
+        assertEquals(t, LocalDateTime.of(2007, 8, 9, 12, 30, 40, 987654321));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_minus_longTemporalUnit_null() {
+        TEST_2007_07_15_12_30_40_987654321.minus(1, (TemporalUnit) null);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minus_longTemporalUnit_invalidTooLarge() {
+        LocalDateTime.of(Year.MAX_VALUE, 1, 1, 0, 0).minus(-1, ChronoUnit.YEARS);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minus_longTemporalUnit_invalidTooSmall() {
+        LocalDateTime.of(Year.MIN_VALUE, 1, 1, 0, 0).minus(1, ChronoUnit.YEARS);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusYears()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusYears_int_normal() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusYears(1);
+        check(t, 2006, 7, 15, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusYears_int_negative() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusYears(-1);
+        check(t, 2008, 7, 15, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusYears_int_adjustDay() {
+        LocalDateTime t = createDateMidnight(2008, 2, 29).minusYears(1);
+        check(t, 2007, 2, 28, 0, 0, 0, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minusYears_int_invalidTooLarge() {
+        createDateMidnight(Year.MAX_VALUE, 1, 1).minusYears(-1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minusYears_int_invalidTooSmall() {
+        createDateMidnight(Year.MIN_VALUE, 1, 1).minusYears(1);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusMonths()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusMonths_int_normal() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusMonths(1);
+        check(t, 2007, 6, 15, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMonths_int_overYears() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusMonths(25);
+        check(t, 2005, 6, 15, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMonths_int_negative() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusMonths(-1);
+        check(t, 2007, 8, 15, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMonths_int_negativeAcrossYear() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusMonths(-7);
+        check(t, 2008, 2, 15, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMonths_int_negativeOverYears() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusMonths(-31);
+        check(t, 2010, 2, 15, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMonths_int_adjustDayFromLeapYear() {
+        LocalDateTime t = createDateMidnight(2008, 2, 29).minusMonths(12);
+        check(t, 2007, 2, 28, 0, 0, 0, 0);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMonths_int_adjustDayFromMonthLength() {
+        LocalDateTime t = createDateMidnight(2007, 3, 31).minusMonths(1);
+        check(t, 2007, 2, 28, 0, 0, 0, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minusMonths_int_invalidTooLarge() {
+        createDateMidnight(Year.MAX_VALUE, 12, 1).minusMonths(-1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minusMonths_int_invalidTooSmall() {
+        createDateMidnight(Year.MIN_VALUE, 1, 1).minusMonths(1);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusWeeks()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sampleMinusWeeksSymmetry")
+    Object[][] provider_sampleMinusWeeksSymmetry() {
+        return new Object[][] {
+            {createDateMidnight(-1, 1, 1)},
+            {createDateMidnight(-1, 2, 28)},
+            {createDateMidnight(-1, 3, 1)},
+            {createDateMidnight(-1, 12, 31)},
+            {createDateMidnight(0, 1, 1)},
+            {createDateMidnight(0, 2, 28)},
+            {createDateMidnight(0, 2, 29)},
+            {createDateMidnight(0, 3, 1)},
+            {createDateMidnight(0, 12, 31)},
+            {createDateMidnight(2007, 1, 1)},
+            {createDateMidnight(2007, 2, 28)},
+            {createDateMidnight(2007, 3, 1)},
+            {createDateMidnight(2007, 12, 31)},
+            {createDateMidnight(2008, 1, 1)},
+            {createDateMidnight(2008, 2, 28)},
+            {createDateMidnight(2008, 2, 29)},
+            {createDateMidnight(2008, 3, 1)},
+            {createDateMidnight(2008, 12, 31)},
+            {createDateMidnight(2099, 1, 1)},
+            {createDateMidnight(2099, 2, 28)},
+            {createDateMidnight(2099, 3, 1)},
+            {createDateMidnight(2099, 12, 31)},
+            {createDateMidnight(2100, 1, 1)},
+            {createDateMidnight(2100, 2, 28)},
+            {createDateMidnight(2100, 3, 1)},
+            {createDateMidnight(2100, 12, 31)},
+        };
+    }
+
+    @Test(dataProvider="sampleMinusWeeksSymmetry", groups={"tck"})
+    public void test_minusWeeks_symmetry(LocalDateTime reference) {
+        for (int weeks = 0; weeks < 365 * 8; weeks++) {
+            LocalDateTime t = reference.minusWeeks(weeks).minusWeeks(-weeks);
+            assertEquals(t, reference);
+
+            t = reference.minusWeeks(-weeks).minusWeeks(weeks);
+            assertEquals(t, reference);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusWeeks_normal() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusWeeks(1);
+        check(t, 2007, 7, 8, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusWeeks_overMonths() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusWeeks(9);
+        check(t, 2007, 5, 13, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusWeeks_overYears() {
+        LocalDateTime t = LocalDateTime.of(2008, 7, 13, 12, 30, 40, 987654321).minusWeeks(52);
+        assertEquals(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusWeeks_overLeapYears() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusYears(-1).minusWeeks(104);
+        check(t, 2006, 7, 18, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusWeeks_negative() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusWeeks(-1);
+        check(t, 2007, 7, 22, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusWeeks_negativeAcrossYear() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusWeeks(-28);
+        check(t, 2008, 1, 27, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusWeeks_negativeOverYears() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusWeeks(-104);
+        check(t, 2009, 7, 12, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusWeeks_maximum() {
+        LocalDateTime t = createDateMidnight(Year.MAX_VALUE, 12, 24).minusWeeks(-1);
+        check(t, Year.MAX_VALUE, 12, 31, 0, 0, 0, 0);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusWeeks_minimum() {
+        LocalDateTime t = createDateMidnight(Year.MIN_VALUE, 1, 8).minusWeeks(1);
+        check(t, Year.MIN_VALUE, 1, 1, 0, 0, 0, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minusWeeks_invalidTooLarge() {
+        createDateMidnight(Year.MAX_VALUE, 12, 25).minusWeeks(-1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minusWeeks_invalidTooSmall() {
+        createDateMidnight(Year.MIN_VALUE, 1, 7).minusWeeks(1);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusDays()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sampleMinusDaysSymmetry")
+    Object[][] provider_sampleMinusDaysSymmetry() {
+        return new Object[][] {
+            {createDateMidnight(-1, 1, 1)},
+            {createDateMidnight(-1, 2, 28)},
+            {createDateMidnight(-1, 3, 1)},
+            {createDateMidnight(-1, 12, 31)},
+            {createDateMidnight(0, 1, 1)},
+            {createDateMidnight(0, 2, 28)},
+            {createDateMidnight(0, 2, 29)},
+            {createDateMidnight(0, 3, 1)},
+            {createDateMidnight(0, 12, 31)},
+            {createDateMidnight(2007, 1, 1)},
+            {createDateMidnight(2007, 2, 28)},
+            {createDateMidnight(2007, 3, 1)},
+            {createDateMidnight(2007, 12, 31)},
+            {createDateMidnight(2008, 1, 1)},
+            {createDateMidnight(2008, 2, 28)},
+            {createDateMidnight(2008, 2, 29)},
+            {createDateMidnight(2008, 3, 1)},
+            {createDateMidnight(2008, 12, 31)},
+            {createDateMidnight(2099, 1, 1)},
+            {createDateMidnight(2099, 2, 28)},
+            {createDateMidnight(2099, 3, 1)},
+            {createDateMidnight(2099, 12, 31)},
+            {createDateMidnight(2100, 1, 1)},
+            {createDateMidnight(2100, 2, 28)},
+            {createDateMidnight(2100, 3, 1)},
+            {createDateMidnight(2100, 12, 31)},
+        };
+    }
+
+    @Test(dataProvider="sampleMinusDaysSymmetry", groups={"tck"})
+    public void test_minusDays_symmetry(LocalDateTime reference) {
+        for (int days = 0; days < 365 * 8; days++) {
+            LocalDateTime t = reference.minusDays(days).minusDays(-days);
+            assertEquals(t, reference);
+
+            t = reference.minusDays(-days).minusDays(days);
+            assertEquals(t, reference);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusDays_normal() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusDays(1);
+        check(t, 2007, 7, 14, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusDays_overMonths() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusDays(62);
+        check(t, 2007, 5, 14, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusDays_overYears() {
+        LocalDateTime t = LocalDateTime.of(2008, 7, 16, 12, 30, 40, 987654321).minusDays(367);
+        assertEquals(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusDays_overLeapYears() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusYears(2).minusDays(365 + 366);
+        assertEquals(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusDays_negative() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusDays(-1);
+        check(t, 2007, 7, 16, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusDays_negativeAcrossYear() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusDays(-169);
+        check(t, 2007, 12, 31, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusDays_negativeOverYears() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusDays(-731);
+        check(t, 2009, 7, 15, 12, 30, 40, 987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusDays_maximum() {
+        LocalDateTime t = createDateMidnight(Year.MAX_VALUE, 12, 30).minusDays(-1);
+        check(t, Year.MAX_VALUE, 12, 31, 0, 0, 0, 0);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusDays_minimum() {
+        LocalDateTime t = createDateMidnight(Year.MIN_VALUE, 1, 2).minusDays(1);
+        check(t, Year.MIN_VALUE, 1, 1, 0, 0, 0, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minusDays_invalidTooLarge() {
+        createDateMidnight(Year.MAX_VALUE, 12, 31).minusDays(-1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minusDays_invalidTooSmall() {
+        createDateMidnight(Year.MIN_VALUE, 1, 1).minusDays(1);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void test_minusDays_overflowTooLarge() {
+        createDateMidnight(Year.MAX_VALUE, 12, 31).minusDays(Long.MIN_VALUE);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void test_minusDays_overflowTooSmall() {
+        createDateMidnight(Year.MIN_VALUE, 1, 1).minusDays(Long.MAX_VALUE);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusHours()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusHours_one() {
+        LocalDateTime t =TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT);
+        LocalDate d = t.getDate();
+
+        for (int i = 0; i < 50; i++) {
+            t = t.minusHours(1);
+
+            if (i % 24 == 0) {
+                d = d.minusDays(1);
+            }
+
+            assertEquals(t.getDate(), d);
+            assertEquals(t.getHour(), (((-i + 23) % 24) + 24) % 24);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusHours_fromZero() {
+        LocalDateTime base = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT);
+        LocalDate d = base.getDate().plusDays(2);
+        LocalTime t = LocalTime.of(3, 0);
+
+        for (int i = -50; i < 50; i++) {
+            LocalDateTime dt = base.minusHours(i);
+            t = t.minusHours(1);
+
+            if (t.getHour() == 23) {
+                d = d.minusDays(1);
+            }
+
+            assertEquals(dt.getDate(), d, String.valueOf(i));
+            assertEquals(dt.getTime(), t);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusHours_fromOne() {
+        LocalDateTime base = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(1, 0));
+        LocalDate d = base.getDate().plusDays(2);
+        LocalTime t = LocalTime.of(4, 0);
+
+        for (int i = -50; i < 50; i++) {
+            LocalDateTime dt = base.minusHours(i);
+
+            t = t.minusHours(1);
+
+            if (t.getHour() == 23) {
+                d = d.minusDays(1);
+            }
+
+            assertEquals(dt.getDate(), d, String.valueOf(i));
+            assertEquals(dt.getTime(), t);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // minusMinutes()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusMinutes_one() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT);
+        LocalDate d = t.getDate().minusDays(1);
+
+        int hour = 0;
+        int min = 0;
+
+        for (int i = 0; i < 70; i++) {
+            t = t.minusMinutes(1);
+            min--;
+            if (min == -1) {
+                hour--;
+                min = 59;
+
+                if (hour == -1) {
+                    hour = 23;
+                }
+            }
+            assertEquals(t.getDate(), d);
+            assertEquals(t.getHour(), hour);
+            assertEquals(t.getMinute(), min);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMinutes_fromZero() {
+        LocalDateTime base = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT);
+        LocalDate d = base.getDate().minusDays(1);
+        LocalTime t = LocalTime.of(22, 49);
+
+        for (int i = 70; i > -70; i--) {
+            LocalDateTime dt = base.minusMinutes(i);
+            t = t.plusMinutes(1);
+
+            if (t == LocalTime.MIDNIGHT) {
+                d = d.plusDays(1);
+            }
+
+            assertEquals(dt.getDate(), d);
+            assertEquals(dt.getTime(), t);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMinutes_noChange_oneDay() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusMinutes(24 * 60);
+        assertEquals(t.getDate(), TEST_2007_07_15_12_30_40_987654321.getDate().minusDays(1));
+    }
+
+    //-----------------------------------------------------------------------
+    // minusSeconds()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusSeconds_one() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT);
+        LocalDate d = t.getDate().minusDays(1);
+
+        int hour = 0;
+        int min = 0;
+        int sec = 0;
+
+        for (int i = 0; i < 3700; i++) {
+            t = t.minusSeconds(1);
+            sec--;
+            if (sec == -1) {
+                min--;
+                sec = 59;
+
+                if (min == -1) {
+                    hour--;
+                    min = 59;
+
+                    if (hour == -1) {
+                        hour = 23;
+                    }
+                }
+            }
+
+            assertEquals(t.getDate(), d);
+            assertEquals(t.getHour(), hour);
+            assertEquals(t.getMinute(), min);
+            assertEquals(t.getSecond(), sec);
+        }
+    }
+
+    @DataProvider(name="minusSeconds_fromZero")
+    Iterator<Object[]> minusSeconds_fromZero() {
+        return new Iterator<Object[]>() {
+            int delta = 30;
+
+            int i = 3660;
+            LocalDate date = TEST_2007_07_15_12_30_40_987654321.getDate().minusDays(1);
+            int hour = 22;
+            int min = 59;
+            int sec = 0;
+
+            public boolean hasNext() {
+                return i >= -3660;
+            }
+
+            public Object[] next() {
+                final Object[] ret = new Object[] {i, date, hour, min, sec};
+                i -= delta;
+                sec += delta;
+
+                if (sec >= 60) {
+                    min++;
+                    sec -= 60;
+
+                    if (min == 60) {
+                        hour++;
+                        min = 0;
+
+                        if (hour == 24) {
+                            hour = 0;
+                        }
+                    }
+                }
+
+                if (i == 0) {
+                    date = date.plusDays(1);
+                }
+
+                return ret;
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    @Test(dataProvider="minusSeconds_fromZero", groups={"tck"})
+    public void test_minusSeconds_fromZero(int seconds, LocalDate date, int hour, int min, int sec) {
+        LocalDateTime base = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT);
+        LocalDateTime t = base.minusSeconds(seconds);
+
+        assertEquals(date, t.getDate());
+        assertEquals(hour, t.getHour());
+        assertEquals(min, t.getMinute());
+        assertEquals(sec, t.getSecond());
+    }
+
+    //-----------------------------------------------------------------------
+    // minusNanos()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusNanos_halfABillion() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT);
+        LocalDate d = t.getDate().minusDays(1);
+
+        int hour = 0;
+        int min = 0;
+        int sec = 0;
+        int nanos = 0;
+
+        for (long i = 0; i < 3700 * 1000000000L; i+= 500000000) {
+            t = t.minusNanos(500000000);
+            nanos -= 500000000;
+
+            if (nanos < 0) {
+                sec--;
+                nanos += 1000000000;
+
+                if (sec == -1) {
+                    min--;
+                    sec += 60;
+
+                    if (min == -1) {
+                        hour--;
+                        min += 60;
+
+                        if (hour == -1) {
+                            hour += 24;
+                        }
+                    }
+                }
+            }
+
+            assertEquals(t.getDate(), d);
+            assertEquals(t.getHour(), hour);
+            assertEquals(t.getMinute(), min);
+            assertEquals(t.getSecond(), sec);
+            assertEquals(t.getNano(), nanos);
+        }
+    }
+
+    @DataProvider(name="minusNanos_fromZero")
+    Iterator<Object[]> minusNanos_fromZero() {
+        return new Iterator<Object[]>() {
+            long delta = 7500000000L;
+
+            long i = 3660 * 1000000000L;
+            LocalDate date = TEST_2007_07_15_12_30_40_987654321.getDate().minusDays(1);
+            int hour = 22;
+            int min = 59;
+            int sec = 0;
+            long nanos = 0;
+
+            public boolean hasNext() {
+                return i >= -3660 * 1000000000L;
+            }
+
+            public Object[] next() {
+                final Object[] ret = new Object[] {i, date, hour, min, sec, (int)nanos};
+                i -= delta;
+                nanos += delta;
+
+                if (nanos >= 1000000000L) {
+                    sec += nanos / 1000000000L;
+                    nanos %= 1000000000L;
+
+                    if (sec >= 60) {
+                        min++;
+                        sec %= 60;
+
+                        if (min == 60) {
+                            hour++;
+                            min = 0;
+
+                            if (hour == 24) {
+                                hour = 0;
+                                date = date.plusDays(1);
+                            }
+                        }
+                    }
+                }
+
+                return ret;
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    @Test(dataProvider="minusNanos_fromZero", groups={"tck"})
+    public void test_minusNanos_fromZero(long nanoseconds, LocalDate date, int hour, int min, int sec, int nanos) {
+        LocalDateTime base = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT);
+        LocalDateTime t = base.minusNanos(nanoseconds);
+
+        assertEquals(date, t.getDate());
+        assertEquals(hour, t.getHour());
+        assertEquals(min, t.getMinute());
+        assertEquals(sec, t.getSecond());
+        assertEquals(nanos, t.getNano());
+    }
+
+    //-----------------------------------------------------------------------
+    // atOffset()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_atOffset() {
+        LocalDateTime t = LocalDateTime.of(2008, 6, 30, 11, 30);
+        assertEquals(t.atOffset(OFFSET_PTWO), OffsetDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 30), OFFSET_PTWO));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_atOffset_nullZoneOffset() {
+        LocalDateTime t = LocalDateTime.of(2008, 6, 30, 11, 30);
+        t.atOffset((ZoneOffset) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // atZone()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_atZone() {
+        LocalDateTime t = LocalDateTime.of(2008, 6, 30, 11, 30);
+        assertEquals(t.atZone(ZONE_PARIS),
+                ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 30), ZONE_PARIS));
+    }
+
+    @Test(groups={"tck"})
+    public void test_atZone_Offset() {
+        LocalDateTime t = LocalDateTime.of(2008, 6, 30, 11, 30);
+        assertEquals(t.atZone(OFFSET_PTWO), ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 30), OFFSET_PTWO));
+    }
+
+    @Test(groups={"tck"})
+    public void test_atZone_dstGap() {
+        LocalDateTime t = LocalDateTime.of(2007, 4, 1, 0, 0);
+        assertEquals(t.atZone(ZONE_GAZA),
+                ZonedDateTime.of(LocalDateTime.of(2007, 4, 1, 1, 0), ZONE_GAZA));
+    }
+
+    @Test(groups={"tck"})
+    public void test_atZone_dstOverlap() {
+        LocalDateTime t = LocalDateTime.of(2007, 10, 28, 2, 30);
+        assertEquals(t.atZone(ZONE_PARIS),
+                ZonedDateTime.ofStrict(LocalDateTime.of(2007, 10, 28, 2, 30), OFFSET_PTWO, ZONE_PARIS));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_atZone_nullTimeZone() {
+        LocalDateTime t = LocalDateTime.of(2008, 6, 30, 11, 30);
+        t.atZone((ZoneId) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // toEpochSecond()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_toEpochSecond_afterEpoch() {
+        for (int i = -5; i < 5; i++) {
+            ZoneOffset offset = ZoneOffset.ofHours(i);
+            for (int j = 0; j < 100000; j++) {
+                LocalDateTime a = LocalDateTime.of(1970, 1, 1, 0, 0).plusSeconds(j);
+                assertEquals(a.toEpochSecond(offset), j - i * 3600);
+            }
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_toEpochSecond_beforeEpoch() {
+        for (int i = 0; i < 100000; i++) {
+            LocalDateTime a = LocalDateTime.of(1970, 1, 1, 0, 0).minusSeconds(i);
+            assertEquals(a.toEpochSecond(ZoneOffset.UTC), -i);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // compareTo()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_comparisons() {
+        test_comparisons_LocalDateTime(
+            LocalDate.of(Year.MIN_VALUE, 1, 1),
+            LocalDate.of(Year.MIN_VALUE, 12, 31),
+            LocalDate.of(-1, 1, 1),
+            LocalDate.of(-1, 12, 31),
+            LocalDate.of(0, 1, 1),
+            LocalDate.of(0, 12, 31),
+            LocalDate.of(1, 1, 1),
+            LocalDate.of(1, 12, 31),
+            LocalDate.of(2008, 1, 1),
+            LocalDate.of(2008, 2, 29),
+            LocalDate.of(2008, 12, 31),
+            LocalDate.of(Year.MAX_VALUE, 1, 1),
+            LocalDate.of(Year.MAX_VALUE, 12, 31)
+        );
+    }
+
+    void test_comparisons_LocalDateTime(LocalDate... localDates) {
+        test_comparisons_LocalDateTime(
+            localDates,
+            LocalTime.MIDNIGHT,
+            LocalTime.of(0, 0, 0, 999999999),
+            LocalTime.of(0, 0, 59, 0),
+            LocalTime.of(0, 0, 59, 999999999),
+            LocalTime.of(0, 59, 0, 0),
+            LocalTime.of(0, 59, 59, 999999999),
+            LocalTime.NOON,
+            LocalTime.of(12, 0, 0, 999999999),
+            LocalTime.of(12, 0, 59, 0),
+            LocalTime.of(12, 0, 59, 999999999),
+            LocalTime.of(12, 59, 0, 0),
+            LocalTime.of(12, 59, 59, 999999999),
+            LocalTime.of(23, 0, 0, 0),
+            LocalTime.of(23, 0, 0, 999999999),
+            LocalTime.of(23, 0, 59, 0),
+            LocalTime.of(23, 0, 59, 999999999),
+            LocalTime.of(23, 59, 0, 0),
+            LocalTime.of(23, 59, 59, 999999999)
+        );
+    }
+
+    void test_comparisons_LocalDateTime(LocalDate[] localDates, LocalTime... localTimes) {
+        LocalDateTime[] localDateTimes = new LocalDateTime[localDates.length * localTimes.length];
+        int i = 0;
+
+        for (LocalDate localDate : localDates) {
+            for (LocalTime localTime : localTimes) {
+                localDateTimes[i++] = LocalDateTime.of(localDate, localTime);
+            }
+        }
+
+        doTest_comparisons_LocalDateTime(localDateTimes);
+    }
+
+    void doTest_comparisons_LocalDateTime(LocalDateTime[] localDateTimes) {
+        for (int i = 0; i < localDateTimes.length; i++) {
+            LocalDateTime a = localDateTimes[i];
+            for (int j = 0; j < localDateTimes.length; j++) {
+                LocalDateTime b = localDateTimes[j];
+                if (i < j) {
+                    assertTrue(a.compareTo(b) < 0, a + " <=> " + b);
+                    assertEquals(a.isBefore(b), true, a + " <=> " + b);
+                    assertEquals(a.isAfter(b), false, a + " <=> " + b);
+                    assertEquals(a.equals(b), false, a + " <=> " + b);
+                } else if (i > j) {
+                    assertTrue(a.compareTo(b) > 0, a + " <=> " + b);
+                    assertEquals(a.isBefore(b), false, a + " <=> " + b);
+                    assertEquals(a.isAfter(b), true, a + " <=> " + b);
+                    assertEquals(a.equals(b), false, a + " <=> " + b);
+                } else {
+                    assertEquals(a.compareTo(b), 0, a + " <=> " + b);
+                    assertEquals(a.isBefore(b), false, a + " <=> " + b);
+                    assertEquals(a.isAfter(b), false, a + " <=> " + b);
+                    assertEquals(a.equals(b), true, a + " <=> " + b);
+                }
+            }
+        }
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_compareTo_ObjectNull() {
+        TEST_2007_07_15_12_30_40_987654321.compareTo(null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_isBefore_ObjectNull() {
+        TEST_2007_07_15_12_30_40_987654321.isBefore(null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_isAfter_ObjectNull() {
+        TEST_2007_07_15_12_30_40_987654321.isAfter(null);
+    }
+
+    @Test(expectedExceptions=ClassCastException.class, groups={"tck"})
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public void compareToNonLocalDateTime() {
+       Comparable c = TEST_2007_07_15_12_30_40_987654321;
+       c.compareTo(new Object());
+    }
+
+    //-----------------------------------------------------------------------
+    // equals()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sampleDateTimes")
+    Iterator<Object[]> provider_sampleDateTimes() {
+        return new Iterator<Object[]>() {
+            Object[][] sampleDates = provider_sampleDates();
+            Object[][] sampleTimes = provider_sampleTimes();
+            int datesIndex = 0;
+            int timesIndex = 0;
+
+            public boolean hasNext() {
+                return datesIndex < sampleDates.length;
+            }
+
+            public Object[] next() {
+                Object[] sampleDate = sampleDates[datesIndex];
+                Object[] sampleTime = sampleTimes[timesIndex];
+
+                Object[] ret = new Object[sampleDate.length + sampleTime.length];
+
+                System.arraycopy(sampleDate, 0, ret, 0, sampleDate.length);
+                System.arraycopy(sampleTime, 0, ret, sampleDate.length, sampleTime.length);
+
+                if (++timesIndex == sampleTimes.length) {
+                    datesIndex++;
+                    timesIndex = 0;
+                }
+
+                return ret;
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    @Test(dataProvider="sampleDateTimes", groups={"tck"})
+    public void test_equals_true(int y, int m, int d, int h, int mi, int s, int n) {
+        LocalDateTime a = LocalDateTime.of(y, m, d, h, mi, s, n);
+        LocalDateTime b = LocalDateTime.of(y, m, d, h, mi, s, n);
+        assertTrue(a.equals(b));
+    }
+
+    @Test(dataProvider="sampleDateTimes", groups={"tck"})
+    public void test_equals_false_year_differs(int y, int m, int d, int h, int mi, int s, int n) {
+        LocalDateTime a = LocalDateTime.of(y, m, d, h, mi, s, n);
+        LocalDateTime b = LocalDateTime.of(y + 1, m, d, h, mi, s, n);
+        assertFalse(a.equals(b));
+    }
+
+    @Test(dataProvider="sampleDateTimes", groups={"tck"})
+    public void test_equals_false_month_differs(int y, int m, int d, int h, int mi, int s, int n) {
+        LocalDateTime a = LocalDateTime.of(y, m, d, h, mi, s, n);
+        LocalDateTime b = LocalDateTime.of(y, m + 1, d, h, mi, s, n);
+        assertFalse(a.equals(b));
+    }
+
+    @Test(dataProvider="sampleDateTimes", groups={"tck"})
+    public void test_equals_false_day_differs(int y, int m, int d, int h, int mi, int s, int n) {
+        LocalDateTime a = LocalDateTime.of(y, m, d, h, mi, s, n);
+        LocalDateTime b = LocalDateTime.of(y, m, d + 1, h, mi, s, n);
+        assertFalse(a.equals(b));
+    }
+
+    @Test(dataProvider="sampleDateTimes", groups={"tck"})
+    public void test_equals_false_hour_differs(int y, int m, int d, int h, int mi, int s, int n) {
+        LocalDateTime a = LocalDateTime.of(y, m, d, h, mi, s, n);
+        LocalDateTime b = LocalDateTime.of(y, m, d, h + 1, mi, s, n);
+        assertFalse(a.equals(b));
+    }
+
+    @Test(dataProvider="sampleDateTimes", groups={"tck"})
+    public void test_equals_false_minute_differs(int y, int m, int d, int h, int mi, int s, int n) {
+        LocalDateTime a = LocalDateTime.of(y, m, d, h, mi, s, n);
+        LocalDateTime b = LocalDateTime.of(y, m, d, h, mi + 1, s, n);
+        assertFalse(a.equals(b));
+    }
+
+    @Test(dataProvider="sampleDateTimes", groups={"tck"})
+    public void test_equals_false_second_differs(int y, int m, int d, int h, int mi, int s, int n) {
+        LocalDateTime a = LocalDateTime.of(y, m, d, h, mi, s, n);
+        LocalDateTime b = LocalDateTime.of(y, m, d, h, mi, s + 1, n);
+        assertFalse(a.equals(b));
+    }
+
+    @Test(dataProvider="sampleDateTimes", groups={"tck"})
+    public void test_equals_false_nano_differs(int y, int m, int d, int h, int mi, int s, int n) {
+        LocalDateTime a = LocalDateTime.of(y, m, d, h, mi, s, n);
+        LocalDateTime b = LocalDateTime.of(y, m, d, h, mi, s, n + 1);
+        assertFalse(a.equals(b));
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_itself_true() {
+        assertEquals(TEST_2007_07_15_12_30_40_987654321.equals(TEST_2007_07_15_12_30_40_987654321), true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_string_false() {
+        assertEquals(TEST_2007_07_15_12_30_40_987654321.equals("2007-07-15T12:30:40.987654321"), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_null_false() {
+        assertEquals(TEST_2007_07_15_12_30_40_987654321.equals(null), false);
+    }
+
+    //-----------------------------------------------------------------------
+    // hashCode()
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="sampleDateTimes", groups={"tck"})
+    public void test_hashCode(int y, int m, int d, int h, int mi, int s, int n) {
+        LocalDateTime a = LocalDateTime.of(y, m, d, h, mi, s, n);
+        assertEquals(a.hashCode(), a.hashCode());
+        LocalDateTime b = LocalDateTime.of(y, m, d, h, mi, s, n);
+        assertEquals(a.hashCode(), b.hashCode());
+    }
+
+    //-----------------------------------------------------------------------
+    // toString()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sampleToString")
+    Object[][] provider_sampleToString() {
+        return new Object[][] {
+            {2008, 7, 5, 2, 1, 0, 0, "2008-07-05T02:01"},
+            {2007, 12, 31, 23, 59, 1, 0, "2007-12-31T23:59:01"},
+            {999, 12, 31, 23, 59, 59, 990000000, "0999-12-31T23:59:59.990"},
+            {-1, 1, 2, 23, 59, 59, 999990000, "-0001-01-02T23:59:59.999990"},
+            {-2008, 1, 2, 23, 59, 59, 999999990, "-2008-01-02T23:59:59.999999990"},
+        };
+    }
+
+    @Test(dataProvider="sampleToString", groups={"tck"})
+    public void test_toString(int y, int m, int d, int h, int mi, int s, int n, String expected) {
+        LocalDateTime t = LocalDateTime.of(y, m, d, h, mi, s, n);
+        String str = t.toString();
+        assertEquals(str, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // toString(DateTimeFormatter)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_toString_formatter() {
+        DateTimeFormatter f = DateTimeFormatters.pattern("y M d H m s");
+        String t = LocalDateTime.of(2010, 12, 3, 11, 30, 45).toString(f);
+        assertEquals(t, "2010 12 3 11 30 45");
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_toString_formatter_null() {
+        LocalDateTime.of(2010, 12, 3, 11, 30, 45).toString(null);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/TCKLocalTime.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,2226 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time;
+
+import static java.time.temporal.ChronoField.AMPM_OF_DAY;
+import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_AMPM;
+import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_DAY;
+import static java.time.temporal.ChronoField.HOUR_OF_AMPM;
+import static java.time.temporal.ChronoField.HOUR_OF_DAY;
+import static java.time.temporal.ChronoField.MICRO_OF_DAY;
+import static java.time.temporal.ChronoField.MICRO_OF_SECOND;
+import static java.time.temporal.ChronoField.MILLI_OF_DAY;
+import static java.time.temporal.ChronoField.MILLI_OF_SECOND;
+import static java.time.temporal.ChronoField.MINUTE_OF_DAY;
+import static java.time.temporal.ChronoField.MINUTE_OF_HOUR;
+import static java.time.temporal.ChronoField.NANO_OF_DAY;
+import static java.time.temporal.ChronoField.NANO_OF_SECOND;
+import static java.time.temporal.ChronoField.SECOND_OF_DAY;
+import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.FOREVER;
+import static java.time.temporal.ChronoUnit.HOURS;
+import static java.time.temporal.ChronoUnit.MICROS;
+import static java.time.temporal.ChronoUnit.MILLIS;
+import static java.time.temporal.ChronoUnit.MINUTES;
+import static java.time.temporal.ChronoUnit.MONTHS;
+import static java.time.temporal.ChronoUnit.NANOS;
+import static java.time.temporal.ChronoUnit.SECONDS;
+import static java.time.temporal.ChronoUnit.WEEKS;
+import static java.time.temporal.ChronoUnit.YEARS;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.List;
+
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.Period;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatters;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.JulianFields;
+import java.time.temporal.OffsetTime;
+import java.time.temporal.Queries;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdder;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalSubtractor;
+import java.time.temporal.TemporalUnit;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import test.java.time.MockSimplePeriod;
+
+/**
+ * Test LocalTime.
+ */
+@Test
+public class TCKLocalTime extends AbstractDateTimeTest {
+
+    private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2);
+
+    private LocalTime TEST_12_30_40_987654321;
+
+    private static final TemporalUnit[] INVALID_UNITS;
+    static {
+        EnumSet<ChronoUnit> set = EnumSet.range(WEEKS, FOREVER);
+        INVALID_UNITS = (TemporalUnit[]) set.toArray(new TemporalUnit[set.size()]);
+    }
+
+    @BeforeMethod(groups={"tck","implementation"})
+    public void setUp() {
+        TEST_12_30_40_987654321 = LocalTime.of(12, 30, 40, 987654321);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    protected List<TemporalAccessor> samples() {
+        TemporalAccessor[] array = {TEST_12_30_40_987654321, LocalTime.MIN, LocalTime.MAX, LocalTime.MIDNIGHT, LocalTime.NOON};
+        return Arrays.asList(array);
+    }
+
+    @Override
+    protected List<TemporalField> validFields() {
+        TemporalField[] array = {
+            NANO_OF_SECOND,
+            NANO_OF_DAY,
+            MICRO_OF_SECOND,
+            MICRO_OF_DAY,
+            MILLI_OF_SECOND,
+            MILLI_OF_DAY,
+            SECOND_OF_MINUTE,
+            SECOND_OF_DAY,
+            MINUTE_OF_HOUR,
+            MINUTE_OF_DAY,
+            CLOCK_HOUR_OF_AMPM,
+            HOUR_OF_AMPM,
+            CLOCK_HOUR_OF_DAY,
+            HOUR_OF_DAY,
+            AMPM_OF_DAY,
+        };
+        return Arrays.asList(array);
+    }
+
+    @Override
+    protected List<TemporalField> invalidFields() {
+        List<TemporalField> list = new ArrayList<>(Arrays.<TemporalField>asList(ChronoField.values()));
+        list.removeAll(validFields());
+        list.add(JulianFields.JULIAN_DAY);
+        list.add(JulianFields.MODIFIED_JULIAN_DAY);
+        list.add(JulianFields.RATA_DIE);
+        return list;
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_serialization() throws Exception {
+        assertSerializable(TEST_12_30_40_987654321);
+        assertSerializable(LocalTime.MIN);
+        assertSerializable(LocalTime.MAX);
+    }
+
+    @Test
+    public void test_serialization_format_h() throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try (DataOutputStream dos = new DataOutputStream(baos) ) {
+            dos.writeByte(4);
+            dos.writeByte(-1 - 22);
+        }
+        byte[] bytes = baos.toByteArray();
+        assertSerializedBySer(LocalTime.of(22, 0), bytes);
+    }
+
+    @Test
+    public void test_serialization_format_hm() throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try (DataOutputStream dos = new DataOutputStream(baos) ) {
+            dos.writeByte(4);
+            dos.writeByte(22);
+            dos.writeByte(-1 - 17);
+        }
+        byte[] bytes = baos.toByteArray();
+        assertSerializedBySer(LocalTime.of(22, 17), bytes);
+    }
+
+    @Test
+    public void test_serialization_format_hms() throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try (DataOutputStream dos = new DataOutputStream(baos) ) {
+            dos.writeByte(4);
+            dos.writeByte(22);
+            dos.writeByte(17);
+            dos.writeByte(-1 - 59);
+        }
+        byte[] bytes = baos.toByteArray();
+        assertSerializedBySer(LocalTime.of(22, 17, 59), bytes);
+    }
+
+    @Test
+    public void test_serialization_format_hmsn() throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try (DataOutputStream dos = new DataOutputStream(baos) ) {
+            dos.writeByte(4);
+            dos.writeByte(22);
+            dos.writeByte(17);
+            dos.writeByte(59);
+            dos.writeInt(459_000_000);
+        }
+        byte[] bytes = baos.toByteArray();
+        assertSerializedBySer(LocalTime.of(22, 17, 59, 459_000_000), bytes);
+    }
+
+    //-----------------------------------------------------------------------
+    private void check(LocalTime test, int h, int m, int s, int n) {
+        assertEquals(test.getHour(), h);
+        assertEquals(test.getMinute(), m);
+        assertEquals(test.getSecond(), s);
+        assertEquals(test.getNano(), n);
+        assertEquals(test, test);
+        assertEquals(test.hashCode(), test.hashCode());
+        assertEquals(LocalTime.of(h, m, s, n), test);
+    }
+
+    //-----------------------------------------------------------------------
+    // constants
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck","implementation"})
+    public void constant_MIDNIGHT() {
+        check(LocalTime.MIDNIGHT, 0, 0, 0, 0);
+    }
+
+    @Test
+    public void constant_MIDDAY() {
+        check(LocalTime.NOON, 12, 0, 0, 0);
+    }
+
+    @Test
+    public void constant_MIN() {
+        check(LocalTime.MIN, 0, 0, 0, 0);
+    }
+
+    @Test
+    public void constant_MAX() {
+        check(LocalTime.MAX, 23, 59, 59, 999999999);
+    }
+
+    //-----------------------------------------------------------------------
+    // now()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void now() {
+        LocalTime expected = LocalTime.now(Clock.systemDefaultZone());
+        LocalTime test = LocalTime.now();
+        long diff = Math.abs(test.toNanoOfDay() - expected.toNanoOfDay());
+        assertTrue(diff < 100000000);  // less than 0.1 secs
+    }
+
+    //-----------------------------------------------------------------------
+    // now(ZoneId)
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void now_ZoneId_nullZoneId() {
+        LocalTime.now((ZoneId) null);
+    }
+
+    @Test(groups={"tck"})
+    public void now_ZoneId() {
+        ZoneId zone = ZoneId.of("UTC+01:02:03");
+        LocalTime expected = LocalTime.now(Clock.system(zone));
+        LocalTime test = LocalTime.now(zone);
+        for (int i = 0; i < 100; i++) {
+            if (expected.equals(test)) {
+                return;
+            }
+            expected = LocalTime.now(Clock.system(zone));
+            test = LocalTime.now(zone);
+        }
+        assertEquals(test, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // now(Clock)
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void now_Clock_nullClock() {
+        LocalTime.now((Clock) null);
+    }
+
+    @Test(groups={"tck"})
+    public void now_Clock_allSecsInDay() {
+        for (int i = 0; i < (2 * 24 * 60 * 60); i++) {
+            Instant instant = Instant.ofEpochSecond(i, 8);
+            Clock clock = Clock.fixed(instant, ZoneOffset.UTC);
+            LocalTime test = LocalTime.now(clock);
+            assertEquals(test.getHour(), (i / (60 * 60)) % 24);
+            assertEquals(test.getMinute(), (i / 60) % 60);
+            assertEquals(test.getSecond(), i % 60);
+            assertEquals(test.getNano(), 8);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void now_Clock_beforeEpoch() {
+        for (int i =-1; i >= -(24 * 60 * 60); i--) {
+            Instant instant = Instant.ofEpochSecond(i, 8);
+            Clock clock = Clock.fixed(instant, ZoneOffset.UTC);
+            LocalTime test = LocalTime.now(clock);
+            assertEquals(test.getHour(), ((i + 24 * 60 * 60) / (60 * 60)) % 24);
+            assertEquals(test.getMinute(), ((i + 24 * 60 * 60) / 60) % 60);
+            assertEquals(test.getSecond(), (i + 24 * 60 * 60) % 60);
+            assertEquals(test.getNano(), 8);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void now_Clock_max() {
+        Clock clock = Clock.fixed(Instant.MAX, ZoneOffset.UTC);
+        LocalTime test = LocalTime.now(clock);
+        assertEquals(test.getHour(), 23);
+        assertEquals(test.getMinute(), 59);
+        assertEquals(test.getSecond(), 59);
+        assertEquals(test.getNano(), 999_999_999);
+    }
+
+    @Test(groups={"tck"})
+    public void now_Clock_min() {
+        Clock clock = Clock.fixed(Instant.MIN, ZoneOffset.UTC);
+        LocalTime test = LocalTime.now(clock);
+        assertEquals(test.getHour(), 0);
+        assertEquals(test.getMinute(), 0);
+        assertEquals(test.getSecond(), 0);
+        assertEquals(test.getNano(), 0);
+    }
+
+    //-----------------------------------------------------------------------
+    // of() factories
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_time_2ints() {
+        LocalTime test = LocalTime.of(12, 30);
+        check(test, 12, 30, 0, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_time_2ints_hourTooLow() {
+        LocalTime.of(-1, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_time_2ints_hourTooHigh() {
+        LocalTime.of(24, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_time_2ints_minuteTooLow() {
+        LocalTime.of(0, -1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_time_2ints_minuteTooHigh() {
+        LocalTime.of(0, 60);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_time_3ints() {
+        LocalTime test = LocalTime.of(12, 30, 40);
+        check(test, 12, 30, 40, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_time_3ints_hourTooLow() {
+        LocalTime.of(-1, 0, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_time_3ints_hourTooHigh() {
+        LocalTime.of(24, 0, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_time_3ints_minuteTooLow() {
+        LocalTime.of(0, -1, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_time_3ints_minuteTooHigh() {
+        LocalTime.of(0, 60, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_time_3ints_secondTooLow() {
+        LocalTime.of(0, 0, -1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_time_3ints_secondTooHigh() {
+        LocalTime.of(0, 0, 60);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_time_4ints() {
+        LocalTime test = LocalTime.of(12, 30, 40, 987654321);
+        check(test, 12, 30, 40, 987654321);
+        test = LocalTime.of(12, 0, 40, 987654321);
+        check(test, 12, 0, 40, 987654321);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_time_4ints_hourTooLow() {
+        LocalTime.of(-1, 0, 0, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_time_4ints_hourTooHigh() {
+        LocalTime.of(24, 0, 0, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_time_4ints_minuteTooLow() {
+        LocalTime.of(0, -1, 0, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_time_4ints_minuteTooHigh() {
+        LocalTime.of(0, 60, 0, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_time_4ints_secondTooLow() {
+        LocalTime.of(0, 0, -1, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_time_4ints_secondTooHigh() {
+        LocalTime.of(0, 0, 60, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_time_4ints_nanoTooLow() {
+        LocalTime.of(0, 0, 0, -1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_time_4ints_nanoTooHigh() {
+        LocalTime.of(0, 0, 0, 1000000000);
+    }
+
+    //-----------------------------------------------------------------------
+    // ofSecondOfDay(long)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_ofSecondOfDay() {
+        LocalTime localTime = LocalTime.ofSecondOfDay(2 * 60 * 60 + 17 * 60 + 23);
+        check(localTime, 2, 17, 23, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_ofSecondOfDay_tooLow() {
+        LocalTime.ofSecondOfDay(-1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_ofSecondOfDay_tooHigh() {
+        LocalTime.ofSecondOfDay(24 * 60 * 60);
+    }
+
+    //-----------------------------------------------------------------------
+    // ofSecondOfDay(long, int)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_ofSecondOfDay_long_int() {
+        LocalTime localTime = LocalTime.ofSecondOfDay(2 * 60 * 60 + 17 * 60 + 23, 987);
+        check(localTime, 2, 17, 23, 987);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_ofSecondOfDay_long_int_tooLowSecs() {
+        LocalTime.ofSecondOfDay(-1, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_ofSecondOfDay_long_int_tooHighSecs() {
+        LocalTime.ofSecondOfDay(24 * 60 * 60, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_ofSecondOfDay_long_int_tooLowNanos() {
+        LocalTime.ofSecondOfDay(0, -1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_ofSecondOfDay_long_int_tooHighNanos() {
+        LocalTime.ofSecondOfDay(0, 1000000000);
+    }
+
+    //-----------------------------------------------------------------------
+    // ofNanoOfDay(long)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_ofNanoOfDay() {
+        LocalTime localTime = LocalTime.ofNanoOfDay(60 * 60 * 1000000000L + 17);
+        check(localTime, 1, 0, 0, 17);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_ofNanoOfDay_tooLow() {
+        LocalTime.ofNanoOfDay(-1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_ofNanoOfDay_tooHigh() {
+        LocalTime.ofNanoOfDay(24 * 60 * 60 * 1000000000L);
+    }
+
+    //-----------------------------------------------------------------------
+    // from()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_from_TemporalAccessor() {
+        assertEquals(LocalTime.from(LocalTime.of(17, 30)), LocalTime.of(17, 30));
+        assertEquals(LocalTime.from(LocalDateTime.of(2012, 5, 1, 17, 30)), LocalTime.of(17, 30));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_from_TemporalAccessor_invalid_noDerive() {
+        LocalTime.from(LocalDate.of(2007, 7, 15));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_from_TemporalAccessor_null() {
+        LocalTime.from((TemporalAccessor) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // parse()
+    //-----------------------------------------------------------------------
+    @Test(dataProvider = "sampleToString", groups={"tck"})
+    public void factory_parse_validText(int h, int m, int s, int n, String parsable) {
+        LocalTime t = LocalTime.parse(parsable);
+        assertNotNull(t, parsable);
+        assertEquals(t.getHour(), h);
+        assertEquals(t.getMinute(), m);
+        assertEquals(t.getSecond(), s);
+        assertEquals(t.getNano(), n);
+    }
+
+    @DataProvider(name="sampleBadParse")
+    Object[][] provider_sampleBadParse() {
+        return new Object[][]{
+                {"00;00"},
+                {"12-00"},
+                {"-01:00"},
+                {"00:00:00-09"},
+                {"00:00:00,09"},
+                {"00:00:abs"},
+                {"11"},
+                {"11:30+01:00"},
+                {"11:30+01:00[Europe/Paris]"},
+        };
+    }
+
+    @Test(dataProvider = "sampleBadParse", expectedExceptions={DateTimeParseException.class}, groups={"tck"})
+    public void factory_parse_invalidText(String unparsable) {
+        LocalTime.parse(unparsable);
+    }
+
+    //-----------------------------------------------------------------------s
+    @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"})
+    public void factory_parse_illegalHour() {
+        LocalTime.parse("25:00");
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"})
+    public void factory_parse_illegalMinute() {
+        LocalTime.parse("12:60");
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"})
+    public void factory_parse_illegalSecond() {
+        LocalTime.parse("12:12:60");
+    }
+
+    //-----------------------------------------------------------------------s
+    @Test(expectedExceptions = {NullPointerException.class}, groups={"tck"})
+    public void factory_parse_nullTest() {
+        LocalTime.parse((String) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // parse(DateTimeFormatter)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_parse_formatter() {
+        DateTimeFormatter f = DateTimeFormatters.pattern("H m s");
+        LocalTime test = LocalTime.parse("14 30 40", f);
+        assertEquals(test, LocalTime.of(14, 30, 40));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_parse_formatter_nullText() {
+        DateTimeFormatter f = DateTimeFormatters.pattern("H m s");
+        LocalTime.parse((String) null, f);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_parse_formatter_nullFormatter() {
+        LocalTime.parse("ANY", null);
+    }
+
+    //-----------------------------------------------------------------------
+    // get(TemporalField)
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_get_TemporalField() {
+        LocalTime test = TEST_12_30_40_987654321;
+        assertEquals(test.get(ChronoField.HOUR_OF_DAY), 12);
+        assertEquals(test.get(ChronoField.MINUTE_OF_HOUR), 30);
+        assertEquals(test.get(ChronoField.SECOND_OF_MINUTE), 40);
+        assertEquals(test.get(ChronoField.NANO_OF_SECOND), 987654321);
+
+        assertEquals(test.get(ChronoField.SECOND_OF_DAY), 12 * 3600 + 30 * 60 + 40);
+        assertEquals(test.get(ChronoField.MINUTE_OF_DAY), 12 * 60 + 30);
+        assertEquals(test.get(ChronoField.HOUR_OF_AMPM), 0);
+        assertEquals(test.get(ChronoField.CLOCK_HOUR_OF_AMPM), 12);
+        assertEquals(test.get(ChronoField.CLOCK_HOUR_OF_DAY), 12);
+        assertEquals(test.get(ChronoField.AMPM_OF_DAY), 1);
+    }
+
+    @Test
+    public void test_getLong_TemporalField() {
+        LocalTime test = TEST_12_30_40_987654321;
+        assertEquals(test.getLong(ChronoField.HOUR_OF_DAY), 12);
+        assertEquals(test.getLong(ChronoField.MINUTE_OF_HOUR), 30);
+        assertEquals(test.getLong(ChronoField.SECOND_OF_MINUTE), 40);
+        assertEquals(test.getLong(ChronoField.NANO_OF_SECOND), 987654321);
+
+        assertEquals(test.getLong(ChronoField.SECOND_OF_DAY), 12 * 3600 + 30 * 60 + 40);
+        assertEquals(test.getLong(ChronoField.MINUTE_OF_DAY), 12 * 60 + 30);
+        assertEquals(test.getLong(ChronoField.HOUR_OF_AMPM), 0);
+        assertEquals(test.getLong(ChronoField.CLOCK_HOUR_OF_AMPM), 12);
+        assertEquals(test.getLong(ChronoField.CLOCK_HOUR_OF_DAY), 12);
+        assertEquals(test.getLong(ChronoField.AMPM_OF_DAY), 1);
+    }
+
+    //-----------------------------------------------------------------------
+    // query(TemporalQuery)
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_query_chrono() {
+        assertEquals(TEST_12_30_40_987654321.query(Queries.chrono()), null);
+        assertEquals(Queries.chrono().queryFrom(TEST_12_30_40_987654321), null);
+    }
+
+    @Test
+    public void test_query_zoneId() {
+        assertEquals(TEST_12_30_40_987654321.query(Queries.zoneId()), null);
+        assertEquals(Queries.zoneId().queryFrom(TEST_12_30_40_987654321), null);
+    }
+
+    @Test
+    public void test_query_precision() {
+        assertEquals(TEST_12_30_40_987654321.query(Queries.precision()), NANOS);
+        assertEquals(Queries.precision().queryFrom(TEST_12_30_40_987654321), NANOS);
+    }
+
+    @Test
+    public void test_query_offset() {
+        assertEquals(TEST_12_30_40_987654321.query(Queries.offset()), null);
+        assertEquals(Queries.offset().queryFrom(TEST_12_30_40_987654321), null);
+    }
+
+    @Test
+    public void test_query_zone() {
+        assertEquals(TEST_12_30_40_987654321.query(Queries.zone()), null);
+        assertEquals(Queries.zone().queryFrom(TEST_12_30_40_987654321), null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_query_null() {
+        TEST_12_30_40_987654321.query(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // get*()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sampleTimes")
+    Object[][] provider_sampleTimes() {
+        return new Object[][] {
+            {0, 0, 0, 0},
+            {0, 0, 0, 1},
+            {0, 0, 1, 0},
+            {0, 0, 1, 1},
+            {0, 1, 0, 0},
+            {0, 1, 0, 1},
+            {0, 1, 1, 0},
+            {0, 1, 1, 1},
+            {1, 0, 0, 0},
+            {1, 0, 0, 1},
+            {1, 0, 1, 0},
+            {1, 0, 1, 1},
+            {1, 1, 0, 0},
+            {1, 1, 0, 1},
+            {1, 1, 1, 0},
+            {1, 1, 1, 1},
+        };
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_get(int h, int m, int s, int ns) {
+        LocalTime a = LocalTime.of(h, m, s, ns);
+        assertEquals(a.getHour(), h);
+        assertEquals(a.getMinute(), m);
+        assertEquals(a.getSecond(), s);
+        assertEquals(a.getNano(), ns);
+    }
+
+    //-----------------------------------------------------------------------
+    // with()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_with_adjustment() {
+        final LocalTime sample = LocalTime.of(23, 5);
+        TemporalAdjuster adjuster = new TemporalAdjuster() {
+            @Override
+            public Temporal adjustInto(Temporal dateTime) {
+                return sample;
+            }
+        };
+        assertEquals(TEST_12_30_40_987654321.with(adjuster), sample);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_with_adjustment_null() {
+        TEST_12_30_40_987654321.with((TemporalAdjuster) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // withHour()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withHour_normal() {
+        LocalTime t = TEST_12_30_40_987654321;
+        for (int i = 0; i < 24; i++) {
+            t = t.withHour(i);
+            assertEquals(t.getHour(), i);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_withHour_noChange_equal() {
+        LocalTime t = TEST_12_30_40_987654321.withHour(12);
+        assertEquals(t, TEST_12_30_40_987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_withHour_toMidnight_equal() {
+        LocalTime t = LocalTime.of(1, 0).withHour(0);
+        assertEquals(t, LocalTime.MIDNIGHT);
+    }
+
+    @Test(groups={"tck"})
+    public void test_withHour_toMidday_equal() {
+        LocalTime t = LocalTime.of(1, 0).withHour(12);
+        assertEquals(t, LocalTime.NOON);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withHour_hourTooLow() {
+        TEST_12_30_40_987654321.withHour(-1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withHour_hourTooHigh() {
+        TEST_12_30_40_987654321.withHour(24);
+    }
+
+    //-----------------------------------------------------------------------
+    // withMinute()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withMinute_normal() {
+        LocalTime t = TEST_12_30_40_987654321;
+        for (int i = 0; i < 60; i++) {
+            t = t.withMinute(i);
+            assertEquals(t.getMinute(), i);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_withMinute_noChange_equal() {
+        LocalTime t = TEST_12_30_40_987654321.withMinute(30);
+        assertEquals(t, TEST_12_30_40_987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_withMinute_toMidnight_equal() {
+        LocalTime t = LocalTime.of(0, 1).withMinute(0);
+        assertEquals(t, LocalTime.MIDNIGHT);
+    }
+
+    @Test(groups={"tck"})
+    public void test_withMinute_toMidday_equals() {
+        LocalTime t = LocalTime.of(12, 1).withMinute(0);
+        assertEquals(t, LocalTime.NOON);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withMinute_minuteTooLow() {
+        TEST_12_30_40_987654321.withMinute(-1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withMinute_minuteTooHigh() {
+        TEST_12_30_40_987654321.withMinute(60);
+    }
+
+    //-----------------------------------------------------------------------
+    // withSecond()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withSecond_normal() {
+        LocalTime t = TEST_12_30_40_987654321;
+        for (int i = 0; i < 60; i++) {
+            t = t.withSecond(i);
+            assertEquals(t.getSecond(), i);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_withSecond_noChange_equal() {
+        LocalTime t = TEST_12_30_40_987654321.withSecond(40);
+        assertEquals(t, TEST_12_30_40_987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_withSecond_toMidnight_equal() {
+        LocalTime t = LocalTime.of(0, 0, 1).withSecond(0);
+        assertEquals(t, LocalTime.MIDNIGHT);
+    }
+
+    @Test(groups={"tck"})
+    public void test_withSecond_toMidday_equal() {
+        LocalTime t = LocalTime.of(12, 0, 1).withSecond(0);
+        assertEquals(t, LocalTime.NOON);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withSecond_secondTooLow() {
+        TEST_12_30_40_987654321.withSecond(-1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withSecond_secondTooHigh() {
+        TEST_12_30_40_987654321.withSecond(60);
+    }
+
+    //-----------------------------------------------------------------------
+    // withNano()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withNanoOfSecond_normal() {
+        LocalTime t = TEST_12_30_40_987654321;
+        t = t.withNano(1);
+        assertEquals(t.getNano(), 1);
+        t = t.withNano(10);
+        assertEquals(t.getNano(), 10);
+        t = t.withNano(100);
+        assertEquals(t.getNano(), 100);
+        t = t.withNano(999999999);
+        assertEquals(t.getNano(), 999999999);
+    }
+
+    @Test(groups={"tck"})
+    public void test_withNanoOfSecond_noChange_equal() {
+        LocalTime t = TEST_12_30_40_987654321.withNano(987654321);
+        assertEquals(t, TEST_12_30_40_987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_withNanoOfSecond_toMidnight_equal() {
+        LocalTime t = LocalTime.of(0, 0, 0, 1).withNano(0);
+        assertEquals(t, LocalTime.MIDNIGHT);
+    }
+
+    @Test(groups={"tck"})
+    public void test_withNanoOfSecond_toMidday_equal() {
+        LocalTime t = LocalTime.of(12, 0, 0, 1).withNano(0);
+        assertEquals(t, LocalTime.NOON);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withNanoOfSecond_nanoTooLow() {
+        TEST_12_30_40_987654321.withNano(-1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withNanoOfSecond_nanoTooHigh() {
+        TEST_12_30_40_987654321.withNano(1000000000);
+    }
+
+    //-----------------------------------------------------------------------
+    // truncated(TemporalUnit)
+    //-----------------------------------------------------------------------
+    @DataProvider(name="truncatedToValid")
+    Object[][] data_truncatedToValid() {
+        return new Object[][] {
+            {LocalTime.of(1, 2, 3, 123_456_789), NANOS, LocalTime.of(1, 2, 3, 123_456_789)},
+            {LocalTime.of(1, 2, 3, 123_456_789), MICROS, LocalTime.of(1, 2, 3, 123_456_000)},
+            {LocalTime.of(1, 2, 3, 123_456_789), MILLIS, LocalTime.of(1, 2, 3, 1230_00_000)},
+            {LocalTime.of(1, 2, 3, 123_456_789), SECONDS, LocalTime.of(1, 2, 3)},
+            {LocalTime.of(1, 2, 3, 123_456_789), MINUTES, LocalTime.of(1, 2)},
+            {LocalTime.of(1, 2, 3, 123_456_789), HOURS, LocalTime.of(1, 0)},
+            {LocalTime.of(1, 2, 3, 123_456_789), DAYS, LocalTime.MIDNIGHT},
+        };
+    }
+
+    @Test(groups={"tck"}, dataProvider="truncatedToValid")
+    public void test_truncatedTo_valid(LocalTime input, TemporalUnit unit, LocalTime expected) {
+        assertEquals(input.truncatedTo(unit), expected);
+    }
+
+    @DataProvider(name="truncatedToInvalid")
+    Object[][] data_truncatedToInvalid() {
+        return new Object[][] {
+            {LocalTime.of(1, 2, 3, 123_456_789), WEEKS},
+            {LocalTime.of(1, 2, 3, 123_456_789), MONTHS},
+            {LocalTime.of(1, 2, 3, 123_456_789), YEARS},
+        };
+    }
+
+    @Test(groups={"tck"}, dataProvider="truncatedToInvalid", expectedExceptions=DateTimeException.class)
+    public void test_truncatedTo_invalid(LocalTime input, TemporalUnit unit) {
+        input.truncatedTo(unit);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_truncatedTo_null() {
+        TEST_12_30_40_987654321.truncatedTo(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // plus(PlusAdjuster)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plus_Adjuster_positiveHours() {
+        TemporalAdder period = MockSimplePeriod.of(7, ChronoUnit.HOURS);
+        LocalTime t = TEST_12_30_40_987654321.plus(period);
+        assertEquals(t, LocalTime.of(19, 30, 40, 987654321));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plus_Adjuster_negativeMinutes() {
+        TemporalAdder period = MockSimplePeriod.of(-25, ChronoUnit.MINUTES);
+        LocalTime t = TEST_12_30_40_987654321.plus(period);
+        assertEquals(t, LocalTime.of(12, 5, 40, 987654321));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plus_Adjuster_zero() {
+        TemporalAdder period = Period.ZERO;
+        LocalTime t = TEST_12_30_40_987654321.plus(period);
+        assertEquals(t, TEST_12_30_40_987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plus_Adjuster_wrap() {
+        TemporalAdder p = Period.ofTime(1, 0, 0);
+        LocalTime t = LocalTime.of(23, 30).plus(p);
+        assertEquals(t, LocalTime.of(0, 30));
+    }
+
+    @Test(groups={"tck"}, expectedExceptions=DateTimeException.class)
+    public void test_plus_Adjuster_dateNotAllowed() {
+        TemporalAdder period = MockSimplePeriod.of(7, ChronoUnit.MONTHS);
+        TEST_12_30_40_987654321.plus(period);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_plus_Adjuster_null() {
+        TEST_12_30_40_987654321.plus((TemporalAdder) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // plus(long,TemporalUnit)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plus_longTemporalUnit_positiveHours() {
+        LocalTime t = TEST_12_30_40_987654321.plus(7, ChronoUnit.HOURS);
+        assertEquals(t, LocalTime.of(19, 30, 40, 987654321));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plus_longTemporalUnit_negativeMinutes() {
+        LocalTime t = TEST_12_30_40_987654321.plus(-25, ChronoUnit.MINUTES);
+        assertEquals(t, LocalTime.of(12, 5, 40, 987654321));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plus_longTemporalUnit_zero() {
+        LocalTime t = TEST_12_30_40_987654321.plus(0, ChronoUnit.MINUTES);
+        assertEquals(t, TEST_12_30_40_987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plus_longTemporalUnit_invalidUnit() {
+        for (TemporalUnit unit : INVALID_UNITS) {
+            try {
+                TEST_12_30_40_987654321.plus(1, unit);
+                fail("Unit should not be allowed " + unit);
+            } catch (DateTimeException ex) {
+                // expected
+            }
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_plus_longTemporalUnit_multiples() {
+        assertEquals(TEST_12_30_40_987654321.plus(0, DAYS), TEST_12_30_40_987654321);
+        assertEquals(TEST_12_30_40_987654321.plus(1, DAYS), TEST_12_30_40_987654321);
+        assertEquals(TEST_12_30_40_987654321.plus(2, DAYS), TEST_12_30_40_987654321);
+        assertEquals(TEST_12_30_40_987654321.plus(-3, DAYS), TEST_12_30_40_987654321);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_plus_longTemporalUnit_null() {
+        TEST_12_30_40_987654321.plus(1, (TemporalUnit) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // plus(adjuster)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plus_adjuster() {
+        Period p = Period.ofTime(0, 0, 62, 3);
+        LocalTime t = TEST_12_30_40_987654321.plus(p);
+        assertEquals(t, LocalTime.of(12, 31, 42, 987654324));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plus_adjuster_big() {
+        Period p = Period.ofTime(0, 0, 0, Long.MAX_VALUE);
+        LocalTime t = TEST_12_30_40_987654321.plus(p);
+        assertEquals(t, TEST_12_30_40_987654321.plusNanos(Long.MAX_VALUE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plus_adjuster_zero_equal() {
+        LocalTime t = TEST_12_30_40_987654321.plus(Period.ZERO);
+        assertEquals(t, TEST_12_30_40_987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plus_adjuster_wrap() {
+        Period p = Period.ofTime(1, 0, 0);
+        LocalTime t = LocalTime.of(23, 30).plus(p);
+        assertEquals(t, LocalTime.of(0, 30));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_plus_adjuster_null() {
+        TEST_12_30_40_987654321.plus((TemporalAdder) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusHours()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusHours_one() {
+        LocalTime t = LocalTime.MIDNIGHT;
+        for (int i = 0; i < 50; i++) {
+            t = t.plusHours(1);
+            assertEquals(t.getHour(), (i + 1) % 24);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusHours_fromZero() {
+        LocalTime base = LocalTime.MIDNIGHT;
+        for (int i = -50; i < 50; i++) {
+            LocalTime t = base.plusHours(i);
+            assertEquals(t.getHour(), (i + 72) % 24);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusHours_fromOne() {
+        LocalTime base = LocalTime.of(1, 0);
+        for (int i = -50; i < 50; i++) {
+            LocalTime t = base.plusHours(i);
+            assertEquals(t.getHour(), (1 + i + 72) % 24);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusHours_noChange_equal() {
+        LocalTime t = TEST_12_30_40_987654321.plusHours(0);
+        assertEquals(t, TEST_12_30_40_987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusHours_toMidnight_equal() {
+        LocalTime t = LocalTime.of(23, 0).plusHours(1);
+        assertEquals(t, LocalTime.MIDNIGHT);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusHours_toMidday_equal() {
+        LocalTime t = LocalTime.of(11, 0).plusHours(1);
+        assertEquals(t, LocalTime.NOON);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusHours_big() {
+        LocalTime t = LocalTime.of(2, 30).plusHours(Long.MAX_VALUE);
+        int hours = (int) (Long.MAX_VALUE % 24L);
+        assertEquals(t, LocalTime.of(2, 30).plusHours(hours));
+    }
+
+    //-----------------------------------------------------------------------
+    // plusMinutes()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusMinutes_one() {
+        LocalTime t = LocalTime.MIDNIGHT;
+        int hour = 0;
+        int min = 0;
+        for (int i = 0; i < 70; i++) {
+            t = t.plusMinutes(1);
+            min++;
+            if (min == 60) {
+                hour++;
+                min = 0;
+            }
+            assertEquals(t.getHour(), hour);
+            assertEquals(t.getMinute(), min);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMinutes_fromZero() {
+        LocalTime base = LocalTime.MIDNIGHT;
+        int hour;
+        int min;
+        for (int i = -70; i < 70; i++) {
+            LocalTime t = base.plusMinutes(i);
+            if (i < -60) {
+                hour = 22;
+                min = i + 120;
+            } else if (i < 0) {
+                hour = 23;
+                min = i + 60;
+            } else if (i >= 60) {
+                hour = 1;
+                min = i - 60;
+            } else {
+                hour = 0;
+                min = i;
+            }
+            assertEquals(t.getHour(), hour);
+            assertEquals(t.getMinute(), min);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMinutes_noChange_equal() {
+        LocalTime t = TEST_12_30_40_987654321.plusMinutes(0);
+        assertEquals(t, TEST_12_30_40_987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMinutes_noChange_oneDay_equal() {
+        LocalTime t = TEST_12_30_40_987654321.plusMinutes(24 * 60);
+        assertEquals(t, TEST_12_30_40_987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMinutes_toMidnight_equal() {
+        LocalTime t = LocalTime.of(23, 59).plusMinutes(1);
+        assertEquals(t, LocalTime.MIDNIGHT);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMinutes_toMidday_equal() {
+        LocalTime t = LocalTime.of(11, 59).plusMinutes(1);
+        assertEquals(t, LocalTime.NOON);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMinutes_big() {
+        LocalTime t = LocalTime.of(2, 30).plusMinutes(Long.MAX_VALUE);
+        int mins = (int) (Long.MAX_VALUE % (24L * 60L));
+        assertEquals(t, LocalTime.of(2, 30).plusMinutes(mins));
+    }
+
+    //-----------------------------------------------------------------------
+    // plusSeconds()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusSeconds_one() {
+        LocalTime t = LocalTime.MIDNIGHT;
+        int hour = 0;
+        int min = 0;
+        int sec = 0;
+        for (int i = 0; i < 3700; i++) {
+            t = t.plusSeconds(1);
+            sec++;
+            if (sec == 60) {
+                min++;
+                sec = 0;
+            }
+            if (min == 60) {
+                hour++;
+                min = 0;
+            }
+            assertEquals(t.getHour(), hour);
+            assertEquals(t.getMinute(), min);
+            assertEquals(t.getSecond(), sec);
+        }
+    }
+
+    @DataProvider(name="plusSeconds_fromZero")
+    Iterator<Object[]> plusSeconds_fromZero() {
+        return new Iterator<Object[]>() {
+            int delta = 30;
+            int i = -3660;
+            int hour = 22;
+            int min = 59;
+            int sec = 0;
+
+            public boolean hasNext() {
+                return i <= 3660;
+            }
+
+            public Object[] next() {
+                final Object[] ret = new Object[] {i, hour, min, sec};
+                i += delta;
+                sec += delta;
+
+                if (sec >= 60) {
+                    min++;
+                    sec -= 60;
+
+                    if (min == 60) {
+                        hour++;
+                        min = 0;
+
+                        if (hour == 24) {
+                            hour = 0;
+                        }
+                    }
+                }
+
+                return ret;
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    @Test(dataProvider="plusSeconds_fromZero", groups={"tck"})
+    public void test_plusSeconds_fromZero(int seconds, int hour, int min, int sec) {
+        LocalTime base = LocalTime.MIDNIGHT;
+        LocalTime t = base.plusSeconds(seconds);
+
+        assertEquals(hour, t.getHour());
+        assertEquals(min, t.getMinute());
+        assertEquals(sec, t.getSecond());
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusSeconds_noChange_equal() {
+        LocalTime t = TEST_12_30_40_987654321.plusSeconds(0);
+        assertEquals(t, TEST_12_30_40_987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusSeconds_noChange_oneDay_equal() {
+        LocalTime t = TEST_12_30_40_987654321.plusSeconds(24 * 60 * 60);
+        assertEquals(t, TEST_12_30_40_987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusSeconds_toMidnight_equal() {
+        LocalTime t = LocalTime.of(23, 59, 59).plusSeconds(1);
+        assertEquals(t, LocalTime.MIDNIGHT);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusSeconds_toMidday_equal() {
+        LocalTime t = LocalTime.of(11, 59, 59).plusSeconds(1);
+        assertEquals(t, LocalTime.NOON);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusNanos()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusNanos_halfABillion() {
+        LocalTime t = LocalTime.MIDNIGHT;
+        int hour = 0;
+        int min = 0;
+        int sec = 0;
+        int nanos = 0;
+        for (long i = 0; i < 3700 * 1000000000L; i+= 500000000) {
+            t = t.plusNanos(500000000);
+            nanos += 500000000;
+            if (nanos == 1000000000) {
+                sec++;
+                nanos = 0;
+            }
+            if (sec == 60) {
+                min++;
+                sec = 0;
+            }
+            if (min == 60) {
+                hour++;
+                min = 0;
+            }
+            assertEquals(t.getHour(), hour);
+            assertEquals(t.getMinute(), min);
+            assertEquals(t.getSecond(), sec);
+            assertEquals(t.getNano(), nanos);
+        }
+    }
+
+    @DataProvider(name="plusNanos_fromZero")
+    Iterator<Object[]> plusNanos_fromZero() {
+        return new Iterator<Object[]>() {
+            long delta = 7500000000L;
+            long i = -3660 * 1000000000L;
+            int hour = 22;
+            int min = 59;
+            int sec = 0;
+            long nanos = 0;
+
+            public boolean hasNext() {
+                return i <= 3660 * 1000000000L;
+            }
+
+            public Object[] next() {
+                final Object[] ret = new Object[] {i, hour, min, sec, (int)nanos};
+                i += delta;
+                nanos += delta;
+
+                if (nanos >= 1000000000L) {
+                    sec += nanos / 1000000000L;
+                    nanos %= 1000000000L;
+
+                    if (sec >= 60) {
+                        min++;
+                        sec %= 60;
+
+                        if (min == 60) {
+                            hour++;
+                            min = 0;
+
+                            if (hour == 24) {
+                                hour = 0;
+                            }
+                        }
+                    }
+                }
+
+                return ret;
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    @Test(dataProvider="plusNanos_fromZero", groups={"tck"})
+    public void test_plusNanos_fromZero(long nanoseconds, int hour, int min, int sec, int nanos) {
+        LocalTime base = LocalTime.MIDNIGHT;
+        LocalTime t = base.plusNanos(nanoseconds);
+
+        assertEquals(hour, t.getHour());
+        assertEquals(min, t.getMinute());
+        assertEquals(sec, t.getSecond());
+        assertEquals(nanos, t.getNano());
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusNanos_noChange_equal() {
+        LocalTime t = TEST_12_30_40_987654321.plusNanos(0);
+        assertEquals(t, TEST_12_30_40_987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusNanos_noChange_oneDay_equal() {
+        LocalTime t = TEST_12_30_40_987654321.plusNanos(24 * 60 * 60 * 1000000000L);
+        assertEquals(t, TEST_12_30_40_987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusNanos_toMidnight_equal() {
+        LocalTime t = LocalTime.of(23, 59, 59, 999999999).plusNanos(1);
+        assertEquals(t, LocalTime.MIDNIGHT);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusNanos_toMidday_equal() {
+        LocalTime t = LocalTime.of(11, 59, 59, 999999999).plusNanos(1);
+        assertEquals(t, LocalTime.NOON);
+    }
+
+    //-----------------------------------------------------------------------
+    // minus(MinusAdjuster)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minus_Adjuster() {
+        TemporalSubtractor p = Period.ofTime(0, 0, 62, 3);
+        LocalTime t = TEST_12_30_40_987654321.minus(p);
+        assertEquals(t, LocalTime.of(12, 29, 38, 987654318));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minus_Adjuster_positiveHours() {
+        TemporalSubtractor period = MockSimplePeriod.of(7, ChronoUnit.HOURS);
+        LocalTime t = TEST_12_30_40_987654321.minus(period);
+        assertEquals(t, LocalTime.of(5, 30, 40, 987654321));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minus_Adjuster_negativeMinutes() {
+        TemporalSubtractor period = MockSimplePeriod.of(-25, ChronoUnit.MINUTES);
+        LocalTime t = TEST_12_30_40_987654321.minus(period);
+        assertEquals(t, LocalTime.of(12, 55, 40, 987654321));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minus_Adjuster_big1() {
+        TemporalSubtractor p = Period.ofTime(0, 0, 0, Long.MAX_VALUE);
+        LocalTime t = TEST_12_30_40_987654321.minus(p);
+        assertEquals(t, TEST_12_30_40_987654321.minusNanos(Long.MAX_VALUE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minus_Adjuster_zero() {
+        TemporalSubtractor p = Period.ZERO;
+        LocalTime t = TEST_12_30_40_987654321.minus(p);
+        assertEquals(t, TEST_12_30_40_987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minus_Adjuster_wrap() {
+        TemporalSubtractor p = Period.ofTime(1, 0, 0);
+        LocalTime t = LocalTime.of(0, 30).minus(p);
+        assertEquals(t, LocalTime.of(23, 30));
+    }
+
+    @Test(groups={"tck"}, expectedExceptions=DateTimeException.class)
+    public void test_minus_Adjuster_dateNotAllowed() {
+        TemporalSubtractor period = MockSimplePeriod.of(7, ChronoUnit.MONTHS);
+        TEST_12_30_40_987654321.minus(period);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_minus_Adjuster_null() {
+        TEST_12_30_40_987654321.minus((TemporalSubtractor) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // minus(long,TemporalUnit)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minus_longTemporalUnit_positiveHours() {
+        LocalTime t = TEST_12_30_40_987654321.minus(7, ChronoUnit.HOURS);
+        assertEquals(t, LocalTime.of(5, 30, 40, 987654321));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minus_longTemporalUnit_negativeMinutes() {
+        LocalTime t = TEST_12_30_40_987654321.minus(-25, ChronoUnit.MINUTES);
+        assertEquals(t, LocalTime.of(12, 55, 40, 987654321));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minus_longTemporalUnit_zero() {
+        LocalTime t = TEST_12_30_40_987654321.minus(0, ChronoUnit.MINUTES);
+        assertEquals(t, TEST_12_30_40_987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minus_longTemporalUnit_invalidUnit() {
+        for (TemporalUnit unit : INVALID_UNITS) {
+            try {
+                TEST_12_30_40_987654321.minus(1, unit);
+                fail("Unit should not be allowed " + unit);
+            } catch (DateTimeException ex) {
+                // expected
+            }
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_minus_longTemporalUnit_long_multiples() {
+        assertEquals(TEST_12_30_40_987654321.minus(0, DAYS), TEST_12_30_40_987654321);
+        assertEquals(TEST_12_30_40_987654321.minus(1, DAYS), TEST_12_30_40_987654321);
+        assertEquals(TEST_12_30_40_987654321.minus(2, DAYS), TEST_12_30_40_987654321);
+        assertEquals(TEST_12_30_40_987654321.minus(-3, DAYS), TEST_12_30_40_987654321);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_minus_longTemporalUnit_null() {
+        TEST_12_30_40_987654321.minus(1, (TemporalUnit) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusHours()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusHours_one() {
+        LocalTime t = LocalTime.MIDNIGHT;
+        for (int i = 0; i < 50; i++) {
+            t = t.minusHours(1);
+            assertEquals(t.getHour(), (((-i + 23) % 24) + 24) % 24, String.valueOf(i));
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusHours_fromZero() {
+        LocalTime base = LocalTime.MIDNIGHT;
+        for (int i = -50; i < 50; i++) {
+            LocalTime t = base.minusHours(i);
+            assertEquals(t.getHour(), ((-i % 24) + 24) % 24);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusHours_fromOne() {
+        LocalTime base = LocalTime.of(1, 0);
+        for (int i = -50; i < 50; i++) {
+            LocalTime t = base.minusHours(i);
+            assertEquals(t.getHour(), (1 + (-i % 24) + 24) % 24);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusHours_noChange_equal() {
+        LocalTime t = TEST_12_30_40_987654321.minusHours(0);
+        assertEquals(t, TEST_12_30_40_987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusHours_toMidnight_equal() {
+        LocalTime t = LocalTime.of(1, 0).minusHours(1);
+        assertEquals(t, LocalTime.MIDNIGHT);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusHours_toMidday_equal() {
+        LocalTime t = LocalTime.of(13, 0).minusHours(1);
+        assertEquals(t, LocalTime.NOON);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusHours_big() {
+        LocalTime t = LocalTime.of(2, 30).minusHours(Long.MAX_VALUE);
+        int hours = (int) (Long.MAX_VALUE % 24L);
+        assertEquals(t, LocalTime.of(2, 30).minusHours(hours));
+    }
+
+    //-----------------------------------------------------------------------
+    // minusMinutes()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusMinutes_one() {
+        LocalTime t = LocalTime.MIDNIGHT;
+        int hour = 0;
+        int min = 0;
+        for (int i = 0; i < 70; i++) {
+            t = t.minusMinutes(1);
+            min--;
+            if (min == -1) {
+                hour--;
+                min = 59;
+
+                if (hour == -1) {
+                    hour = 23;
+                }
+            }
+            assertEquals(t.getHour(), hour);
+            assertEquals(t.getMinute(), min);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMinutes_fromZero() {
+        LocalTime base = LocalTime.MIDNIGHT;
+        int hour = 22;
+        int min = 49;
+        for (int i = 70; i > -70; i--) {
+            LocalTime t = base.minusMinutes(i);
+            min++;
+
+            if (min == 60) {
+                hour++;
+                min = 0;
+
+                if (hour == 24) {
+                    hour = 0;
+                }
+            }
+
+            assertEquals(t.getHour(), hour);
+            assertEquals(t.getMinute(), min);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMinutes_noChange_equal() {
+        LocalTime t = TEST_12_30_40_987654321.minusMinutes(0);
+        assertEquals(t, TEST_12_30_40_987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMinutes_noChange_oneDay_equal() {
+        LocalTime t = TEST_12_30_40_987654321.minusMinutes(24 * 60);
+        assertEquals(t, TEST_12_30_40_987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMinutes_toMidnight_equal() {
+        LocalTime t = LocalTime.of(0, 1).minusMinutes(1);
+        assertEquals(t, LocalTime.MIDNIGHT);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMinutes_toMidday_equals() {
+        LocalTime t = LocalTime.of(12, 1).minusMinutes(1);
+        assertEquals(t, LocalTime.NOON);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMinutes_big() {
+        LocalTime t = LocalTime.of(2, 30).minusMinutes(Long.MAX_VALUE);
+        int mins = (int) (Long.MAX_VALUE % (24L * 60L));
+        assertEquals(t, LocalTime.of(2, 30).minusMinutes(mins));
+    }
+
+    //-----------------------------------------------------------------------
+    // minusSeconds()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusSeconds_one() {
+        LocalTime t = LocalTime.MIDNIGHT;
+        int hour = 0;
+        int min = 0;
+        int sec = 0;
+        for (int i = 0; i < 3700; i++) {
+            t = t.minusSeconds(1);
+            sec--;
+            if (sec == -1) {
+                min--;
+                sec = 59;
+
+                if (min == -1) {
+                    hour--;
+                    min = 59;
+
+                    if (hour == -1) {
+                        hour = 23;
+                    }
+                }
+            }
+            assertEquals(t.getHour(), hour);
+            assertEquals(t.getMinute(), min);
+            assertEquals(t.getSecond(), sec);
+        }
+    }
+
+    @DataProvider(name="minusSeconds_fromZero")
+    Iterator<Object[]> minusSeconds_fromZero() {
+        return new Iterator<Object[]>() {
+            int delta = 30;
+            int i = 3660;
+            int hour = 22;
+            int min = 59;
+            int sec = 0;
+
+            public boolean hasNext() {
+                return i >= -3660;
+            }
+
+            public Object[] next() {
+                final Object[] ret = new Object[] {i, hour, min, sec};
+                i -= delta;
+                sec += delta;
+
+                if (sec >= 60) {
+                    min++;
+                    sec -= 60;
+
+                    if (min == 60) {
+                        hour++;
+                        min = 0;
+
+                        if (hour == 24) {
+                            hour = 0;
+                        }
+                    }
+                }
+
+                return ret;
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    @Test(dataProvider="minusSeconds_fromZero", groups={"tck"})
+    public void test_minusSeconds_fromZero(int seconds, int hour, int min, int sec) {
+        LocalTime base = LocalTime.MIDNIGHT;
+        LocalTime t = base.minusSeconds(seconds);
+
+        assertEquals(t.getHour(), hour);
+        assertEquals(t.getMinute(), min);
+        assertEquals(t.getSecond(), sec);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusSeconds_noChange_equal() {
+        LocalTime t = TEST_12_30_40_987654321.minusSeconds(0);
+        assertEquals(t, TEST_12_30_40_987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusSeconds_noChange_oneDay_equal() {
+        LocalTime t = TEST_12_30_40_987654321.minusSeconds(24 * 60 * 60);
+        assertEquals(t, TEST_12_30_40_987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusSeconds_toMidnight_equal() {
+        LocalTime t = LocalTime.of(0, 0, 1).minusSeconds(1);
+        assertEquals(t, LocalTime.MIDNIGHT);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusSeconds_toMidday_equal() {
+        LocalTime t = LocalTime.of(12, 0, 1).minusSeconds(1);
+        assertEquals(t, LocalTime.NOON);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusSeconds_big() {
+        LocalTime t = LocalTime.of(2, 30).minusSeconds(Long.MAX_VALUE);
+        int secs = (int) (Long.MAX_VALUE % (24L * 60L * 60L));
+        assertEquals(t, LocalTime.of(2, 30).minusSeconds(secs));
+    }
+
+    //-----------------------------------------------------------------------
+    // minusNanos()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusNanos_halfABillion() {
+        LocalTime t = LocalTime.MIDNIGHT;
+        int hour = 0;
+        int min = 0;
+        int sec = 0;
+        int nanos = 0;
+        for (long i = 0; i < 3700 * 1000000000L; i+= 500000000) {
+            t = t.minusNanos(500000000);
+            nanos -= 500000000;
+
+            if (nanos < 0) {
+                sec--;
+                nanos += 1000000000;
+
+                if (sec == -1) {
+                    min--;
+                    sec += 60;
+
+                    if (min == -1) {
+                        hour--;
+                        min += 60;
+
+                        if (hour == -1) {
+                            hour += 24;
+                        }
+                    }
+                }
+            }
+
+            assertEquals(t.getHour(), hour);
+            assertEquals(t.getMinute(), min);
+            assertEquals(t.getSecond(), sec);
+            assertEquals(t.getNano(), nanos);
+        }
+    }
+
+    @DataProvider(name="minusNanos_fromZero")
+    Iterator<Object[]> minusNanos_fromZero() {
+        return new Iterator<Object[]>() {
+            long delta = 7500000000L;
+            long i = 3660 * 1000000000L;
+            int hour = 22;
+            int min = 59;
+            int sec = 0;
+            long nanos = 0;
+
+            public boolean hasNext() {
+                return i >= -3660 * 1000000000L;
+            }
+
+            public Object[] next() {
+                final Object[] ret = new Object[] {i, hour, min, sec, (int)nanos};
+                i -= delta;
+                nanos += delta;
+
+                if (nanos >= 1000000000L) {
+                    sec += nanos / 1000000000L;
+                    nanos %= 1000000000L;
+
+                    if (sec >= 60) {
+                        min++;
+                        sec %= 60;
+
+                        if (min == 60) {
+                            hour++;
+                            min = 0;
+
+                            if (hour == 24) {
+                                hour = 0;
+                            }
+                        }
+                    }
+                }
+
+                return ret;
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    @Test(dataProvider="minusNanos_fromZero", groups={"tck"})
+    public void test_minusNanos_fromZero(long nanoseconds, int hour, int min, int sec, int nanos) {
+        LocalTime base = LocalTime.MIDNIGHT;
+        LocalTime t = base.minusNanos(nanoseconds);
+
+        assertEquals(hour, t.getHour());
+        assertEquals(min, t.getMinute());
+        assertEquals(sec, t.getSecond());
+        assertEquals(nanos, t.getNano());
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusNanos_noChange_equal() {
+        LocalTime t = TEST_12_30_40_987654321.minusNanos(0);
+        assertEquals(t, TEST_12_30_40_987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusNanos_noChange_oneDay_equal() {
+        LocalTime t = TEST_12_30_40_987654321.minusNanos(24 * 60 * 60 * 1000000000L);
+        assertEquals(t, TEST_12_30_40_987654321);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusNanos_toMidnight_equal() {
+        LocalTime t = LocalTime.of(0, 0, 0, 1).minusNanos(1);
+        assertEquals(t, LocalTime.MIDNIGHT);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusNanos_toMidday_equal() {
+        LocalTime t = LocalTime.of(12, 0, 0, 1).minusNanos(1);
+        assertEquals(t, LocalTime.NOON);
+    }
+
+    //-----------------------------------------------------------------------
+    // atDate()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_atDate() {
+        LocalTime t = LocalTime.of(11, 30);
+        assertEquals(t.atDate(LocalDate.of(2012, 6, 30)), LocalDateTime.of(2012, 6, 30, 11, 30));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_atDate_nullDate() {
+        TEST_12_30_40_987654321.atDate((LocalDate) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // atOffset()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_atOffset() {
+        LocalTime t = LocalTime.of(11, 30);
+        assertEquals(t.atOffset(OFFSET_PTWO), OffsetTime.of(LocalTime.of(11, 30), OFFSET_PTWO));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_atOffset_nullZoneOffset() {
+        LocalTime t = LocalTime.of(11, 30);
+        t.atOffset((ZoneOffset) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // toSecondOfDay()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_toSecondOfDay() {
+        LocalTime t = LocalTime.of(0, 0);
+        for (int i = 0; i < 24 * 60 * 60; i++) {
+            assertEquals(t.toSecondOfDay(), i);
+            t = t.plusSeconds(1);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_toSecondOfDay_fromNanoOfDay_symmetry() {
+        LocalTime t = LocalTime.of(0, 0);
+        for (int i = 0; i < 24 * 60 * 60; i++) {
+            assertEquals(LocalTime.ofSecondOfDay(t.toSecondOfDay()), t);
+            t = t.plusSeconds(1);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // toNanoOfDay()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_toNanoOfDay() {
+        LocalTime t = LocalTime.of(0, 0);
+        for (int i = 0; i < 1000000; i++) {
+            assertEquals(t.toNanoOfDay(), i);
+            t = t.plusNanos(1);
+        }
+        t = LocalTime.of(0, 0);
+        for (int i = 1; i <= 1000000; i++) {
+            t = t.minusNanos(1);
+            assertEquals(t.toNanoOfDay(), 24 * 60 * 60 * 1000000000L - i);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_toNanoOfDay_fromNanoOfDay_symmetry() {
+        LocalTime t = LocalTime.of(0, 0);
+        for (int i = 0; i < 1000000; i++) {
+            assertEquals(LocalTime.ofNanoOfDay(t.toNanoOfDay()), t);
+            t = t.plusNanos(1);
+        }
+        t = LocalTime.of(0, 0);
+        for (int i = 1; i <= 1000000; i++) {
+            t = t.minusNanos(1);
+            assertEquals(LocalTime.ofNanoOfDay(t.toNanoOfDay()), t);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // compareTo()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_comparisons() {
+        doTest_comparisons_LocalTime(
+            LocalTime.MIDNIGHT,
+            LocalTime.of(0, 0, 0, 999999999),
+            LocalTime.of(0, 0, 59, 0),
+            LocalTime.of(0, 0, 59, 999999999),
+            LocalTime.of(0, 59, 0, 0),
+            LocalTime.of(0, 59, 0, 999999999),
+            LocalTime.of(0, 59, 59, 0),
+            LocalTime.of(0, 59, 59, 999999999),
+            LocalTime.NOON,
+            LocalTime.of(12, 0, 0, 999999999),
+            LocalTime.of(12, 0, 59, 0),
+            LocalTime.of(12, 0, 59, 999999999),
+            LocalTime.of(12, 59, 0, 0),
+            LocalTime.of(12, 59, 0, 999999999),
+            LocalTime.of(12, 59, 59, 0),
+            LocalTime.of(12, 59, 59, 999999999),
+            LocalTime.of(23, 0, 0, 0),
+            LocalTime.of(23, 0, 0, 999999999),
+            LocalTime.of(23, 0, 59, 0),
+            LocalTime.of(23, 0, 59, 999999999),
+            LocalTime.of(23, 59, 0, 0),
+            LocalTime.of(23, 59, 0, 999999999),
+            LocalTime.of(23, 59, 59, 0),
+            LocalTime.of(23, 59, 59, 999999999)
+        );
+    }
+
+    void doTest_comparisons_LocalTime(LocalTime... localTimes) {
+        for (int i = 0; i < localTimes.length; i++) {
+            LocalTime a = localTimes[i];
+            for (int j = 0; j < localTimes.length; j++) {
+                LocalTime b = localTimes[j];
+                if (i < j) {
+                    assertTrue(a.compareTo(b) < 0, a + " <=> " + b);
+                    assertEquals(a.isBefore(b), true, a + " <=> " + b);
+                    assertEquals(a.isAfter(b), false, a + " <=> " + b);
+                    assertEquals(a.equals(b), false, a + " <=> " + b);
+                } else if (i > j) {
+                    assertTrue(a.compareTo(b) > 0, a + " <=> " + b);
+                    assertEquals(a.isBefore(b), false, a + " <=> " + b);
+                    assertEquals(a.isAfter(b), true, a + " <=> " + b);
+                    assertEquals(a.equals(b), false, a + " <=> " + b);
+                } else {
+                    assertEquals(a.compareTo(b), 0, a + " <=> " + b);
+                    assertEquals(a.isBefore(b), false, a + " <=> " + b);
+                    assertEquals(a.isAfter(b), false, a + " <=> " + b);
+                    assertEquals(a.equals(b), true, a + " <=> " + b);
+                }
+            }
+        }
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_compareTo_ObjectNull() {
+        TEST_12_30_40_987654321.compareTo(null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_isBefore_ObjectNull() {
+        TEST_12_30_40_987654321.isBefore(null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_isAfter_ObjectNull() {
+        TEST_12_30_40_987654321.isAfter(null);
+    }
+
+    @Test(expectedExceptions=ClassCastException.class, groups={"tck"})
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public void compareToNonLocalTime() {
+       Comparable c = TEST_12_30_40_987654321;
+       c.compareTo(new Object());
+    }
+
+    //-----------------------------------------------------------------------
+    // equals()
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_equals_true(int h, int m, int s, int n) {
+        LocalTime a = LocalTime.of(h, m, s, n);
+        LocalTime b = LocalTime.of(h, m, s, n);
+        assertEquals(a.equals(b), true);
+    }
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_equals_false_hour_differs(int h, int m, int s, int n) {
+        LocalTime a = LocalTime.of(h, m, s, n);
+        LocalTime b = LocalTime.of(h + 1, m, s, n);
+        assertEquals(a.equals(b), false);
+    }
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_equals_false_minute_differs(int h, int m, int s, int n) {
+        LocalTime a = LocalTime.of(h, m, s, n);
+        LocalTime b = LocalTime.of(h, m + 1, s, n);
+        assertEquals(a.equals(b), false);
+    }
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_equals_false_second_differs(int h, int m, int s, int n) {
+        LocalTime a = LocalTime.of(h, m, s, n);
+        LocalTime b = LocalTime.of(h, m, s + 1, n);
+        assertEquals(a.equals(b), false);
+    }
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_equals_false_nano_differs(int h, int m, int s, int n) {
+        LocalTime a = LocalTime.of(h, m, s, n);
+        LocalTime b = LocalTime.of(h, m, s, n + 1);
+        assertEquals(a.equals(b), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_itself_true() {
+        assertEquals(TEST_12_30_40_987654321.equals(TEST_12_30_40_987654321), true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_string_false() {
+        assertEquals(TEST_12_30_40_987654321.equals("2007-07-15"), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_null_false() {
+        assertEquals(TEST_12_30_40_987654321.equals(null), false);
+    }
+
+    //-----------------------------------------------------------------------
+    // hashCode()
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_hashCode_same(int h, int m, int s, int n) {
+        LocalTime a = LocalTime.of(h, m, s, n);
+        LocalTime b = LocalTime.of(h, m, s, n);
+        assertEquals(a.hashCode(), b.hashCode());
+    }
+
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_hashCode_hour_differs(int h, int m, int s, int n) {
+        LocalTime a = LocalTime.of(h, m, s, n);
+        LocalTime b = LocalTime.of(h + 1, m, s, n);
+        assertEquals(a.hashCode() == b.hashCode(), false);
+    }
+
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_hashCode_minute_differs(int h, int m, int s, int n) {
+        LocalTime a = LocalTime.of(h, m, s, n);
+        LocalTime b = LocalTime.of(h, m + 1, s, n);
+        assertEquals(a.hashCode() == b.hashCode(), false);
+    }
+
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_hashCode_second_differs(int h, int m, int s, int n) {
+        LocalTime a = LocalTime.of(h, m, s, n);
+        LocalTime b = LocalTime.of(h, m, s + 1, n);
+        assertEquals(a.hashCode() == b.hashCode(), false);
+    }
+
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_hashCode_nano_differs(int h, int m, int s, int n) {
+        LocalTime a = LocalTime.of(h, m, s, n);
+        LocalTime b = LocalTime.of(h, m, s, n + 1);
+        assertEquals(a.hashCode() == b.hashCode(), false);
+    }
+
+    //-----------------------------------------------------------------------
+    // toString()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sampleToString")
+    Object[][] provider_sampleToString() {
+        return new Object[][] {
+            {0, 0, 0, 0, "00:00"},
+            {1, 0, 0, 0, "01:00"},
+            {23, 0, 0, 0, "23:00"},
+            {0, 1, 0, 0, "00:01"},
+            {12, 30, 0, 0, "12:30"},
+            {23, 59, 0, 0, "23:59"},
+            {0, 0, 1, 0, "00:00:01"},
+            {0, 0, 59, 0, "00:00:59"},
+            {0, 0, 0, 100000000, "00:00:00.100"},
+            {0, 0, 0, 10000000, "00:00:00.010"},
+            {0, 0, 0, 1000000, "00:00:00.001"},
+            {0, 0, 0, 100000, "00:00:00.000100"},
+            {0, 0, 0, 10000, "00:00:00.000010"},
+            {0, 0, 0, 1000, "00:00:00.000001"},
+            {0, 0, 0, 100, "00:00:00.000000100"},
+            {0, 0, 0, 10, "00:00:00.000000010"},
+            {0, 0, 0, 1, "00:00:00.000000001"},
+            {0, 0, 0, 999999999, "00:00:00.999999999"},
+            {0, 0, 0, 99999999, "00:00:00.099999999"},
+            {0, 0, 0, 9999999, "00:00:00.009999999"},
+            {0, 0, 0, 999999, "00:00:00.000999999"},
+            {0, 0, 0, 99999, "00:00:00.000099999"},
+            {0, 0, 0, 9999, "00:00:00.000009999"},
+            {0, 0, 0, 999, "00:00:00.000000999"},
+            {0, 0, 0, 99, "00:00:00.000000099"},
+            {0, 0, 0, 9, "00:00:00.000000009"},
+        };
+    }
+
+    @Test(dataProvider="sampleToString", groups={"tck"})
+    public void test_toString(int h, int m, int s, int n, String expected) {
+        LocalTime t = LocalTime.of(h, m, s, n);
+        String str = t.toString();
+        assertEquals(str, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // toString(DateTimeFormatter)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_toString_formatter() {
+        DateTimeFormatter f = DateTimeFormatters.pattern("H m s");
+        String t = LocalTime.of(11, 30, 45).toString(f);
+        assertEquals(t, "11 30 45");
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_toString_formatter_null() {
+        LocalTime.of(11, 30, 45).toString(null);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/TCKMonth.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,486 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time;
+
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static org.testng.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.Month;
+import java.time.format.TextStyle;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.ISOChrono;
+import java.time.temporal.JulianFields;
+import java.time.temporal.Queries;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalField;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test Month.
+ */
+@Test
+public class TCKMonth extends AbstractDateTimeTest {
+
+    private static final int MAX_LENGTH = 12;
+
+    //-----------------------------------------------------------------------
+    @Override
+    protected List<TemporalAccessor> samples() {
+        TemporalAccessor[] array = {Month.JANUARY, Month.JUNE, Month.DECEMBER, };
+        return Arrays.asList(array);
+    }
+
+    @Override
+    protected List<TemporalField> validFields() {
+        TemporalField[] array = {
+            MONTH_OF_YEAR,
+        };
+        return Arrays.asList(array);
+    }
+
+    @Override
+    protected List<TemporalField> invalidFields() {
+        List<TemporalField> list = new ArrayList<>(Arrays.<TemporalField>asList(ChronoField.values()));
+        list.removeAll(validFields());
+        list.add(JulianFields.JULIAN_DAY);
+        list.add(JulianFields.MODIFIED_JULIAN_DAY);
+        list.add(JulianFields.RATA_DIE);
+        return list;
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_factory_int_singleton() {
+        for (int i = 1; i <= MAX_LENGTH; i++) {
+            Month test = Month.of(i);
+            assertEquals(test.getValue(), i);
+        }
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_int_tooLow() {
+        Month.of(0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_int_tooHigh() {
+        Month.of(13);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_factory_CalendricalObject() {
+        assertEquals(Month.from(LocalDate.of(2011, 6, 6)), Month.JUNE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_CalendricalObject_invalid_noDerive() {
+        Month.from(LocalTime.of(12, 30));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_factory_CalendricalObject_null() {
+        Month.from((TemporalAccessor) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // get(TemporalField)
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_get_TemporalField() {
+        assertEquals(Month.JULY.get(ChronoField.MONTH_OF_YEAR), 7);
+    }
+
+    @Test
+    public void test_getLong_TemporalField() {
+        assertEquals(Month.JULY.getLong(ChronoField.MONTH_OF_YEAR), 7);
+    }
+
+    //-----------------------------------------------------------------------
+    // query(TemporalQuery)
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_query_chrono() {
+        assertEquals(Month.JUNE.query(Queries.chrono()), ISOChrono.INSTANCE);
+        assertEquals(Queries.chrono().queryFrom(Month.JUNE), ISOChrono.INSTANCE);
+    }
+
+    @Test
+    public void test_query_zoneId() {
+        assertEquals(Month.JUNE.query(Queries.zoneId()), null);
+        assertEquals(Queries.zoneId().queryFrom(Month.JUNE), null);
+    }
+
+    @Test
+    public void test_query_precision() {
+        assertEquals(Month.JUNE.query(Queries.precision()), ChronoUnit.MONTHS);
+        assertEquals(Queries.precision().queryFrom(Month.JUNE), ChronoUnit.MONTHS);
+    }
+
+    @Test
+    public void test_query_offset() {
+        assertEquals(Month.JUNE.query(Queries.offset()), null);
+        assertEquals(Queries.offset().queryFrom(Month.JUNE), null);
+    }
+
+    @Test
+    public void test_query_zone() {
+        assertEquals(Month.JUNE.query(Queries.zone()), null);
+        assertEquals(Queries.zone().queryFrom(Month.JUNE), null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_query_null() {
+        Month.JUNE.query(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // getText()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_getText() {
+        assertEquals(Month.JANUARY.getText(TextStyle.SHORT, Locale.US), "Jan");
+    }
+
+    @Test(expectedExceptions = NullPointerException.class, groups={"tck"})
+    public void test_getText_nullStyle() {
+        Month.JANUARY.getText(null, Locale.US);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class, groups={"tck"})
+    public void test_getText_nullLocale() {
+        Month.JANUARY.getText(TextStyle.FULL, null);
+    }
+
+    //-----------------------------------------------------------------------
+    // plus(long), plus(long,unit)
+    //-----------------------------------------------------------------------
+    @DataProvider(name="plus")
+    Object[][] data_plus() {
+        return new Object[][] {
+            {1, -13, 12},
+            {1, -12, 1},
+            {1, -11, 2},
+            {1, -10, 3},
+            {1, -9, 4},
+            {1, -8, 5},
+            {1, -7, 6},
+            {1, -6, 7},
+            {1, -5, 8},
+            {1, -4, 9},
+            {1, -3, 10},
+            {1, -2, 11},
+            {1, -1, 12},
+            {1, 0, 1},
+            {1, 1, 2},
+            {1, 2, 3},
+            {1, 3, 4},
+            {1, 4, 5},
+            {1, 5, 6},
+            {1, 6, 7},
+            {1, 7, 8},
+            {1, 8, 9},
+            {1, 9, 10},
+            {1, 10, 11},
+            {1, 11, 12},
+            {1, 12, 1},
+            {1, 13, 2},
+
+            {1, 1, 2},
+            {2, 1, 3},
+            {3, 1, 4},
+            {4, 1, 5},
+            {5, 1, 6},
+            {6, 1, 7},
+            {7, 1, 8},
+            {8, 1, 9},
+            {9, 1, 10},
+            {10, 1, 11},
+            {11, 1, 12},
+            {12, 1, 1},
+
+            {1, -1, 12},
+            {2, -1, 1},
+            {3, -1, 2},
+            {4, -1, 3},
+            {5, -1, 4},
+            {6, -1, 5},
+            {7, -1, 6},
+            {8, -1, 7},
+            {9, -1, 8},
+            {10, -1, 9},
+            {11, -1, 10},
+            {12, -1, 11},
+        };
+    }
+
+    @Test(dataProvider="plus", groups={"tck"})
+    public void test_plus_long(int base, long amount, int expected) {
+        assertEquals(Month.of(base).plus(amount), Month.of(expected));
+    }
+
+    //-----------------------------------------------------------------------
+    // minus(long), minus(long,unit)
+    //-----------------------------------------------------------------------
+    @DataProvider(name="minus")
+    Object[][] data_minus() {
+        return new Object[][] {
+            {1, -13, 2},
+            {1, -12, 1},
+            {1, -11, 12},
+            {1, -10, 11},
+            {1, -9, 10},
+            {1, -8, 9},
+            {1, -7, 8},
+            {1, -6, 7},
+            {1, -5, 6},
+            {1, -4, 5},
+            {1, -3, 4},
+            {1, -2, 3},
+            {1, -1, 2},
+            {1, 0, 1},
+            {1, 1, 12},
+            {1, 2, 11},
+            {1, 3, 10},
+            {1, 4, 9},
+            {1, 5, 8},
+            {1, 6, 7},
+            {1, 7, 6},
+            {1, 8, 5},
+            {1, 9, 4},
+            {1, 10, 3},
+            {1, 11, 2},
+            {1, 12, 1},
+            {1, 13, 12},
+        };
+    }
+
+    @Test(dataProvider="minus", groups={"tck"})
+    public void test_minus_long(int base, long amount, int expected) {
+        assertEquals(Month.of(base).minus(amount), Month.of(expected));
+    }
+
+    //-----------------------------------------------------------------------
+    // length(boolean)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_length_boolean_notLeapYear() {
+        assertEquals(Month.JANUARY.length(false), 31);
+        assertEquals(Month.FEBRUARY.length(false), 28);
+        assertEquals(Month.MARCH.length(false), 31);
+        assertEquals(Month.APRIL.length(false), 30);
+        assertEquals(Month.MAY.length(false), 31);
+        assertEquals(Month.JUNE.length(false), 30);
+        assertEquals(Month.JULY.length(false), 31);
+        assertEquals(Month.AUGUST.length(false), 31);
+        assertEquals(Month.SEPTEMBER.length(false), 30);
+        assertEquals(Month.OCTOBER.length(false), 31);
+        assertEquals(Month.NOVEMBER.length(false), 30);
+        assertEquals(Month.DECEMBER.length(false), 31);
+    }
+
+    @Test(groups={"tck"})
+    public void test_length_boolean_leapYear() {
+        assertEquals(Month.JANUARY.length(true), 31);
+        assertEquals(Month.FEBRUARY.length(true), 29);
+        assertEquals(Month.MARCH.length(true), 31);
+        assertEquals(Month.APRIL.length(true), 30);
+        assertEquals(Month.MAY.length(true), 31);
+        assertEquals(Month.JUNE.length(true), 30);
+        assertEquals(Month.JULY.length(true), 31);
+        assertEquals(Month.AUGUST.length(true), 31);
+        assertEquals(Month.SEPTEMBER.length(true), 30);
+        assertEquals(Month.OCTOBER.length(true), 31);
+        assertEquals(Month.NOVEMBER.length(true), 30);
+        assertEquals(Month.DECEMBER.length(true), 31);
+    }
+
+    //-----------------------------------------------------------------------
+    // minLength()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minLength() {
+        assertEquals(Month.JANUARY.minLength(), 31);
+        assertEquals(Month.FEBRUARY.minLength(), 28);
+        assertEquals(Month.MARCH.minLength(), 31);
+        assertEquals(Month.APRIL.minLength(), 30);
+        assertEquals(Month.MAY.minLength(), 31);
+        assertEquals(Month.JUNE.minLength(), 30);
+        assertEquals(Month.JULY.minLength(), 31);
+        assertEquals(Month.AUGUST.minLength(), 31);
+        assertEquals(Month.SEPTEMBER.minLength(), 30);
+        assertEquals(Month.OCTOBER.minLength(), 31);
+        assertEquals(Month.NOVEMBER.minLength(), 30);
+        assertEquals(Month.DECEMBER.minLength(), 31);
+    }
+
+    //-----------------------------------------------------------------------
+    // maxLength()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_maxLength() {
+        assertEquals(Month.JANUARY.maxLength(), 31);
+        assertEquals(Month.FEBRUARY.maxLength(), 29);
+        assertEquals(Month.MARCH.maxLength(), 31);
+        assertEquals(Month.APRIL.maxLength(), 30);
+        assertEquals(Month.MAY.maxLength(), 31);
+        assertEquals(Month.JUNE.maxLength(), 30);
+        assertEquals(Month.JULY.maxLength(), 31);
+        assertEquals(Month.AUGUST.maxLength(), 31);
+        assertEquals(Month.SEPTEMBER.maxLength(), 30);
+        assertEquals(Month.OCTOBER.maxLength(), 31);
+        assertEquals(Month.NOVEMBER.maxLength(), 30);
+        assertEquals(Month.DECEMBER.maxLength(), 31);
+    }
+
+    //-----------------------------------------------------------------------
+    // firstDayOfYear(boolean)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_firstDayOfYear_notLeapYear() {
+        assertEquals(Month.JANUARY.firstDayOfYear(false), 1);
+        assertEquals(Month.FEBRUARY.firstDayOfYear(false), 1 + 31);
+        assertEquals(Month.MARCH.firstDayOfYear(false), 1 + 31 + 28);
+        assertEquals(Month.APRIL.firstDayOfYear(false), 1 + 31 + 28 + 31);
+        assertEquals(Month.MAY.firstDayOfYear(false), 1 + 31 + 28 + 31 + 30);
+        assertEquals(Month.JUNE.firstDayOfYear(false), 1 + 31 + 28 + 31 + 30 + 31);
+        assertEquals(Month.JULY.firstDayOfYear(false), 1 + 31 + 28 + 31 + 30 + 31 + 30);
+        assertEquals(Month.AUGUST.firstDayOfYear(false), 1 + 31 + 28 + 31 + 30 + 31 + 30 + 31);
+        assertEquals(Month.SEPTEMBER.firstDayOfYear(false), 1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31);
+        assertEquals(Month.OCTOBER.firstDayOfYear(false), 1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30);
+        assertEquals(Month.NOVEMBER.firstDayOfYear(false), 1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31);
+        assertEquals(Month.DECEMBER.firstDayOfYear(false), 1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30);
+    }
+
+    @Test(groups={"tck"})
+    public void test_firstDayOfYear_leapYear() {
+        assertEquals(Month.JANUARY.firstDayOfYear(true), 1);
+        assertEquals(Month.FEBRUARY.firstDayOfYear(true), 1 + 31);
+        assertEquals(Month.MARCH.firstDayOfYear(true), 1 + 31 + 29);
+        assertEquals(Month.APRIL.firstDayOfYear(true), 1 + 31 + 29 + 31);
+        assertEquals(Month.MAY.firstDayOfYear(true), 1 + 31 + 29 + 31 + 30);
+        assertEquals(Month.JUNE.firstDayOfYear(true), 1 + 31 + 29 + 31 + 30 + 31);
+        assertEquals(Month.JULY.firstDayOfYear(true), 1 + 31 + 29 + 31 + 30 + 31 + 30);
+        assertEquals(Month.AUGUST.firstDayOfYear(true), 1 + 31 + 29 + 31 + 30 + 31 + 30 + 31);
+        assertEquals(Month.SEPTEMBER.firstDayOfYear(true), 1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31);
+        assertEquals(Month.OCTOBER.firstDayOfYear(true), 1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30);
+        assertEquals(Month.NOVEMBER.firstDayOfYear(true), 1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31);
+        assertEquals(Month.DECEMBER.firstDayOfYear(true), 1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30);
+    }
+
+    //-----------------------------------------------------------------------
+    // firstMonthOfQuarter()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_firstMonthOfQuarter() {
+        assertEquals(Month.JANUARY.firstMonthOfQuarter(), Month.JANUARY);
+        assertEquals(Month.FEBRUARY.firstMonthOfQuarter(), Month.JANUARY);
+        assertEquals(Month.MARCH.firstMonthOfQuarter(), Month.JANUARY);
+        assertEquals(Month.APRIL.firstMonthOfQuarter(), Month.APRIL);
+        assertEquals(Month.MAY.firstMonthOfQuarter(), Month.APRIL);
+        assertEquals(Month.JUNE.firstMonthOfQuarter(), Month.APRIL);
+        assertEquals(Month.JULY.firstMonthOfQuarter(), Month.JULY);
+        assertEquals(Month.AUGUST.firstMonthOfQuarter(), Month.JULY);
+        assertEquals(Month.SEPTEMBER.firstMonthOfQuarter(), Month.JULY);
+        assertEquals(Month.OCTOBER.firstMonthOfQuarter(), Month.OCTOBER);
+        assertEquals(Month.NOVEMBER.firstMonthOfQuarter(), Month.OCTOBER);
+        assertEquals(Month.DECEMBER.firstMonthOfQuarter(), Month.OCTOBER);
+    }
+
+    //-----------------------------------------------------------------------
+    // toString()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_toString() {
+        assertEquals(Month.JANUARY.toString(), "JANUARY");
+        assertEquals(Month.FEBRUARY.toString(), "FEBRUARY");
+        assertEquals(Month.MARCH.toString(), "MARCH");
+        assertEquals(Month.APRIL.toString(), "APRIL");
+        assertEquals(Month.MAY.toString(), "MAY");
+        assertEquals(Month.JUNE.toString(), "JUNE");
+        assertEquals(Month.JULY.toString(), "JULY");
+        assertEquals(Month.AUGUST.toString(), "AUGUST");
+        assertEquals(Month.SEPTEMBER.toString(), "SEPTEMBER");
+        assertEquals(Month.OCTOBER.toString(), "OCTOBER");
+        assertEquals(Month.NOVEMBER.toString(), "NOVEMBER");
+        assertEquals(Month.DECEMBER.toString(), "DECEMBER");
+    }
+
+    //-----------------------------------------------------------------------
+    // generated methods
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_enum() {
+        assertEquals(Month.valueOf("JANUARY"), Month.JANUARY);
+        assertEquals(Month.values()[0], Month.JANUARY);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/TCKZoneId.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+
+import java.time.ZoneId;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test ZoneId.
+ */
+@Test
+public class TCKZoneId extends AbstractTCKTest {
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_serialization() throws Exception {
+        assertSerializable(ZoneId.of("Europe/London"));
+    }
+
+    @Test
+    public void test_serialization_format() throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try (DataOutputStream dos = new DataOutputStream(baos) ) {
+            dos.writeByte(7);
+            dos.writeUTF("Europe/London");
+        }
+        byte[] bytes = baos.toByteArray();
+        assertSerializedBySer(ZoneId.of("Europe/London"), bytes);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/TCKZoneOffset.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,680 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time;
+
+import static java.time.temporal.ChronoField.OFFSET_SECONDS;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import java.time.DateTimeException;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.temporal.ChronoField;
+import java.time.temporal.JulianFields;
+import java.time.temporal.OffsetDate;
+import java.time.temporal.Queries;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalField;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test ZoneOffset.
+ */
+@Test
+public class TCKZoneOffset extends AbstractDateTimeTest {
+
+    //-----------------------------------------------------------------------
+    @Override
+    protected List<TemporalAccessor> samples() {
+        TemporalAccessor[] array = {ZoneOffset.ofHours(1), ZoneOffset.ofHoursMinutesSeconds(-5, -6, -30) };
+        return Arrays.asList(array);
+    }
+
+    @Override
+    protected List<TemporalField> validFields() {
+        TemporalField[] array = {
+            OFFSET_SECONDS,
+        };
+        return Arrays.asList(array);
+    }
+
+    @Override
+    protected List<TemporalField> invalidFields() {
+        List<TemporalField> list = new ArrayList<>(Arrays.<TemporalField>asList(ChronoField.values()));
+        list.removeAll(validFields());
+        list.add(JulianFields.JULIAN_DAY);
+        list.add(JulianFields.MODIFIED_JULIAN_DAY);
+        list.add(JulianFields.RATA_DIE);
+        return list;
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_serialization() throws Exception {
+        assertSerializable(ZoneOffset.of("+01:30"));
+    }
+
+    @Test
+    public void test_serialization_format_quarterPositive() throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try (DataOutputStream dos = new DataOutputStream(baos) ) {
+            dos.writeByte(8);
+            dos.writeByte(6);  // stored as quarter hours
+        }
+        byte[] bytes = baos.toByteArray();
+        assertSerializedBySer(ZoneOffset.ofHoursMinutes(1, 30), bytes);
+    }
+
+    @Test
+    public void test_serialization_format_quarterNegative() throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try (DataOutputStream dos = new DataOutputStream(baos) ) {
+            dos.writeByte(8);
+            dos.writeByte(-10);  // stored as quarter hours
+        }
+        byte[] bytes = baos.toByteArray();
+        assertSerializedBySer(ZoneOffset.ofHoursMinutes(-2, -30), bytes);
+    }
+
+    @Test
+    public void test_serialization_format_full() throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try (DataOutputStream dos = new DataOutputStream(baos) ) {
+            dos.writeByte(8);
+            dos.writeByte(127);
+            dos.writeInt(53265);
+        }
+        byte[] bytes = baos.toByteArray();
+        assertSerializedBySer(ZoneOffset.ofTotalSeconds(53265), bytes);
+    }
+
+    //-----------------------------------------------------------------------
+    // constants
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_constant_UTC() {
+        ZoneOffset test = ZoneOffset.UTC;
+        doTestOffset(test, 0, 0, 0);
+    }
+
+    @Test
+    public void test_constant_MIN() {
+        ZoneOffset test = ZoneOffset.MIN;
+        doTestOffset(test, -18, 0, 0);
+    }
+
+    @Test
+    public void test_constant_MAX() {
+        ZoneOffset test = ZoneOffset.MAX;
+        doTestOffset(test, 18, 0, 0);
+    }
+
+    //-----------------------------------------------------------------------
+    // of(String)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_factory_string_UTC() {
+        String[] values = new String[] {
+            "Z", "+0",
+            "+00","+0000","+00:00","+000000","+00:00:00",
+            "-00","-0000","-00:00","-000000","-00:00:00",
+        };
+        for (int i = 0; i < values.length; i++) {
+            ZoneOffset test = ZoneOffset.of(values[i]);
+            assertSame(test, ZoneOffset.UTC);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_factory_string_invalid() {
+        String[] values = new String[] {
+            "","A","B","C","D","E","F","G","H","I","J","K","L","M",
+            "N","O","P","Q","R","S","T","U","V","W","X","Y","ZZ",
+            "0", "+0:00","+00:0","+0:0",
+            "+000","+00000",
+            "+0:00:00","+00:0:00","+00:00:0","+0:0:0","+0:0:00","+00:0:0","+0:00:0",
+            "1", "+01_00","+01;00","+01@00","+01:AA",
+            "+19","+19:00","+18:01","+18:00:01","+1801","+180001",
+            "-0:00","-00:0","-0:0",
+            "-000","-00000",
+            "-0:00:00","-00:0:00","-00:00:0","-0:0:0","-0:0:00","-00:0:0","-0:00:0",
+            "-19","-19:00","-18:01","-18:00:01","-1801","-180001",
+            "-01_00","-01;00","-01@00","-01:AA",
+            "@01:00",
+        };
+        for (int i = 0; i < values.length; i++) {
+            try {
+                ZoneOffset.of(values[i]);
+                fail("Should have failed:" + values[i]);
+            } catch (DateTimeException ex) {
+                // expected
+            }
+        }
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_factory_string_null() {
+        ZoneOffset.of((String) null);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_factory_string_singleDigitHours() {
+        for (int i = -9; i <= 9; i++) {
+            String str = (i < 0 ? "-" : "+") + Math.abs(i);
+            ZoneOffset test = ZoneOffset.of(str);
+            doTestOffset(test, i, 0, 0);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_factory_string_hours() {
+        for (int i = -18; i <= 18; i++) {
+            String str = (i < 0 ? "-" : "+") + Integer.toString(Math.abs(i) + 100).substring(1);
+            ZoneOffset test = ZoneOffset.of(str);
+            doTestOffset(test, i, 0, 0);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_factory_string_hours_minutes_noColon() {
+        for (int i = -17; i <= 17; i++) {
+            for (int j = -59; j <= 59; j++) {
+                if ((i < 0 && j <= 0) || (i > 0 && j >= 0) || i == 0) {
+                    String str = (i < 0 || j < 0 ? "-" : "+") +
+                        Integer.toString(Math.abs(i) + 100).substring(1) +
+                        Integer.toString(Math.abs(j) + 100).substring(1);
+                    ZoneOffset test = ZoneOffset.of(str);
+                    doTestOffset(test, i, j, 0);
+                }
+            }
+        }
+        ZoneOffset test1 = ZoneOffset.of("-1800");
+        doTestOffset(test1, -18, 0, 0);
+        ZoneOffset test2 = ZoneOffset.of("+1800");
+        doTestOffset(test2, 18, 0, 0);
+    }
+
+    @Test(groups={"tck"})
+    public void test_factory_string_hours_minutes_colon() {
+        for (int i = -17; i <= 17; i++) {
+            for (int j = -59; j <= 59; j++) {
+                if ((i < 0 && j <= 0) || (i > 0 && j >= 0) || i == 0) {
+                    String str = (i < 0 || j < 0 ? "-" : "+") +
+                        Integer.toString(Math.abs(i) + 100).substring(1) + ":" +
+                        Integer.toString(Math.abs(j) + 100).substring(1);
+                    ZoneOffset test = ZoneOffset.of(str);
+                    doTestOffset(test, i, j, 0);
+                }
+            }
+        }
+        ZoneOffset test1 = ZoneOffset.of("-18:00");
+        doTestOffset(test1, -18, 0, 0);
+        ZoneOffset test2 = ZoneOffset.of("+18:00");
+        doTestOffset(test2, 18, 0, 0);
+    }
+
+    @Test(groups={"tck"})
+    public void test_factory_string_hours_minutes_seconds_noColon() {
+        for (int i = -17; i <= 17; i++) {
+            for (int j = -59; j <= 59; j++) {
+                for (int k = -59; k <= 59; k++) {
+                    if ((i < 0 && j <= 0 && k <= 0) || (i > 0 && j >= 0 && k >= 0) ||
+                            (i == 0 && ((j < 0 && k <= 0) || (j > 0 && k >= 0) || j == 0))) {
+                        String str = (i < 0 || j < 0 || k < 0 ? "-" : "+") +
+                            Integer.toString(Math.abs(i) + 100).substring(1) +
+                            Integer.toString(Math.abs(j) + 100).substring(1) +
+                            Integer.toString(Math.abs(k) + 100).substring(1);
+                        ZoneOffset test = ZoneOffset.of(str);
+                        doTestOffset(test, i, j, k);
+                    }
+                }
+            }
+        }
+        ZoneOffset test1 = ZoneOffset.of("-180000");
+        doTestOffset(test1, -18, 0, 0);
+        ZoneOffset test2 = ZoneOffset.of("+180000");
+        doTestOffset(test2, 18, 0, 0);
+    }
+
+    @Test(groups={"tck"})
+    public void test_factory_string_hours_minutes_seconds_colon() {
+        for (int i = -17; i <= 17; i++) {
+            for (int j = -59; j <= 59; j++) {
+                for (int k = -59; k <= 59; k++) {
+                    if ((i < 0 && j <= 0 && k <= 0) || (i > 0 && j >= 0 && k >= 0) ||
+                            (i == 0 && ((j < 0 && k <= 0) || (j > 0 && k >= 0) || j == 0))) {
+                        String str = (i < 0 || j < 0 || k < 0 ? "-" : "+") +
+                            Integer.toString(Math.abs(i) + 100).substring(1) + ":" +
+                            Integer.toString(Math.abs(j) + 100).substring(1) + ":" +
+                            Integer.toString(Math.abs(k) + 100).substring(1);
+                        ZoneOffset test = ZoneOffset.of(str);
+                        doTestOffset(test, i, j, k);
+                    }
+                }
+            }
+        }
+        ZoneOffset test1 = ZoneOffset.of("-18:00:00");
+        doTestOffset(test1, -18, 0, 0);
+        ZoneOffset test2 = ZoneOffset.of("+18:00:00");
+        doTestOffset(test2, 18, 0, 0);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_factory_int_hours() {
+        for (int i = -18; i <= 18; i++) {
+            ZoneOffset test = ZoneOffset.ofHours(i);
+            doTestOffset(test, i, 0, 0);
+        }
+    }
+
+    @Test(groups={"tck"}, expectedExceptions=DateTimeException.class)
+    public void test_factory_int_hours_tooBig() {
+        ZoneOffset.ofHours(19);
+    }
+
+    @Test(groups={"tck"}, expectedExceptions=DateTimeException.class)
+    public void test_factory_int_hours_tooSmall() {
+        ZoneOffset.ofHours(-19);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_factory_int_hours_minutes() {
+        for (int i = -17; i <= 17; i++) {
+            for (int j = -59; j <= 59; j++) {
+                if ((i < 0 && j <= 0) || (i > 0 && j >= 0) || i == 0) {
+                    ZoneOffset test = ZoneOffset.ofHoursMinutes(i, j);
+                    doTestOffset(test, i, j, 0);
+                }
+            }
+        }
+        ZoneOffset test1 = ZoneOffset.ofHoursMinutes(-18, 0);
+        doTestOffset(test1, -18, 0, 0);
+        ZoneOffset test2 = ZoneOffset.ofHoursMinutes(18, 0);
+        doTestOffset(test2, 18, 0, 0);
+    }
+
+    @Test(groups={"tck"}, expectedExceptions=DateTimeException.class)
+    public void test_factory_int_hours_minutes_tooBig() {
+        ZoneOffset.ofHoursMinutes(19, 0);
+    }
+
+    @Test(groups={"tck"}, expectedExceptions=DateTimeException.class)
+    public void test_factory_int_hours_minutes_tooSmall() {
+        ZoneOffset.ofHoursMinutes(-19, 0);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_factory_int_hours_minutes_seconds() {
+        for (int i = -17; i <= 17; i++) {
+            for (int j = -59; j <= 59; j++) {
+                for (int k = -59; k <= 59; k++) {
+                    if ((i < 0 && j <= 0 && k <= 0) || (i > 0 && j >= 0 && k >= 0) ||
+                            (i == 0 && ((j < 0 && k <= 0) || (j > 0 && k >= 0) || j == 0))) {
+                        ZoneOffset test = ZoneOffset.ofHoursMinutesSeconds(i, j, k);
+                        doTestOffset(test, i, j, k);
+                    }
+                }
+            }
+        }
+        ZoneOffset test1 = ZoneOffset.ofHoursMinutesSeconds(-18, 0, 0);
+        doTestOffset(test1, -18, 0, 0);
+        ZoneOffset test2 = ZoneOffset.ofHoursMinutesSeconds(18, 0, 0);
+        doTestOffset(test2, 18, 0, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_int_hours_minutes_seconds_plusHoursMinusMinutes() {
+        ZoneOffset.ofHoursMinutesSeconds(1, -1, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_int_hours_minutes_seconds_plusHoursMinusSeconds() {
+        ZoneOffset.ofHoursMinutesSeconds(1, 0, -1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_int_hours_minutes_seconds_minusHoursPlusMinutes() {
+        ZoneOffset.ofHoursMinutesSeconds(-1, 1, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_int_hours_minutes_seconds_minusHoursPlusSeconds() {
+        ZoneOffset.ofHoursMinutesSeconds(-1, 0, 1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_int_hours_minutes_seconds_zeroHoursMinusMinutesPlusSeconds() {
+        ZoneOffset.ofHoursMinutesSeconds(0, -1, 1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_int_hours_minutes_seconds_zeroHoursPlusMinutesMinusSeconds() {
+        ZoneOffset.ofHoursMinutesSeconds(0, 1, -1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_int_hours_minutes_seconds_minutesTooLarge() {
+        ZoneOffset.ofHoursMinutesSeconds(0, 60, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_int_hours_minutes_seconds_minutesTooSmall() {
+        ZoneOffset.ofHoursMinutesSeconds(0, -60, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_int_hours_minutes_seconds_secondsTooLarge() {
+        ZoneOffset.ofHoursMinutesSeconds(0, 0, 60);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_int_hours_minutes_seconds_secondsTooSmall() {
+        ZoneOffset.ofHoursMinutesSeconds(0, 0, 60);
+    }
+
+    @Test(groups={"tck"}, expectedExceptions=DateTimeException.class)
+    public void test_factory_int_hours_minutes_seconds_hoursTooBig() {
+        ZoneOffset.ofHoursMinutesSeconds(19, 0, 0);
+    }
+
+    @Test(groups={"tck"}, expectedExceptions=DateTimeException.class)
+    public void test_factory_int_hours_minutes_seconds_hoursTooSmall() {
+        ZoneOffset.ofHoursMinutesSeconds(-19, 0, 0);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_factory_ofTotalSeconds() {
+        assertEquals(ZoneOffset.ofTotalSeconds(60 * 60 + 1), ZoneOffset.ofHoursMinutesSeconds(1, 0, 1));
+        assertEquals(ZoneOffset.ofTotalSeconds(18 * 60 * 60), ZoneOffset.ofHours(18));
+        assertEquals(ZoneOffset.ofTotalSeconds(-18 * 60 * 60), ZoneOffset.ofHours(-18));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_ofTotalSeconds_tooLarge() {
+        ZoneOffset.ofTotalSeconds(18 * 60 * 60 + 1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_ofTotalSeconds_tooSmall() {
+        ZoneOffset.ofTotalSeconds(-18 * 60 * 60 - 1);
+    }
+
+    //-----------------------------------------------------------------------
+    // from()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_factory_CalendricalObject() {
+        assertEquals(ZoneOffset.from(OffsetDate.of(LocalDate.of(2012, 5, 2), ZoneOffset.ofHours(6))), ZoneOffset.ofHours(6));
+        assertEquals(ZoneOffset.from(ZonedDateTime.of(LocalDateTime.of(LocalDate.of(2007, 7, 15),
+                LocalTime.of(17, 30)), ZoneOffset.ofHours(2))), ZoneOffset.ofHours(2));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_CalendricalObject_invalid_noDerive() {
+        ZoneOffset.from(LocalTime.of(12, 30));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_factory_CalendricalObject_null() {
+        ZoneOffset.from((TemporalAccessor) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // getTotalSeconds()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_getTotalSeconds() {
+        ZoneOffset offset = ZoneOffset.ofTotalSeconds(60 * 60 + 1);
+        assertEquals(offset.getTotalSeconds(), 60 * 60 + 1);
+    }
+
+    //-----------------------------------------------------------------------
+    // getId()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_getId() {
+        ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(1, 0, 0);
+        assertEquals(offset.getId(), "+01:00");
+        offset = ZoneOffset.ofHoursMinutesSeconds(1, 2, 3);
+        assertEquals(offset.getId(), "+01:02:03");
+        offset = ZoneOffset.UTC;
+        assertEquals(offset.getId(), "Z");
+    }
+
+    //-----------------------------------------------------------------------
+    // getRules()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_getRules() {
+        ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(1, 2, 3);
+        assertEquals(offset.getRules().isFixedOffset(), true);
+        assertEquals(offset.getRules().getOffset((Instant) null), offset);
+        assertEquals(offset.getRules().getDaylightSavings((Instant) null), Duration.ZERO);
+        assertEquals(offset.getRules().getStandardOffset((Instant) null), offset);
+        assertEquals(offset.getRules().nextTransition((Instant) null), null);
+        assertEquals(offset.getRules().previousTransition((Instant) null), null);
+
+        assertEquals(offset.getRules().isValidOffset((LocalDateTime) null, offset), true);
+        assertEquals(offset.getRules().isValidOffset((LocalDateTime) null, ZoneOffset.UTC), false);
+        assertEquals(offset.getRules().isValidOffset((LocalDateTime) null, null), false);
+        assertEquals(offset.getRules().getOffset((LocalDateTime) null), offset);
+        assertEquals(offset.getRules().getValidOffsets((LocalDateTime) null), Arrays.asList(offset));
+        assertEquals(offset.getRules().getTransition((LocalDateTime) null), null);
+        assertEquals(offset.getRules().getTransitions().size(), 0);
+        assertEquals(offset.getRules().getTransitionRules().size(), 0);
+    }
+
+    //-----------------------------------------------------------------------
+    // get(TemporalField)
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_get_TemporalField() {
+        assertEquals(ZoneOffset.UTC.get(OFFSET_SECONDS), 0);
+        assertEquals(ZoneOffset.ofHours(-2).get(OFFSET_SECONDS), -7200);
+        assertEquals(ZoneOffset.ofHoursMinutesSeconds(0, 1, 5).get(OFFSET_SECONDS), 65);
+    }
+
+    @Test
+    public void test_getLong_TemporalField() {
+        assertEquals(ZoneOffset.UTC.getLong(OFFSET_SECONDS), 0);
+        assertEquals(ZoneOffset.ofHours(-2).getLong(OFFSET_SECONDS), -7200);
+        assertEquals(ZoneOffset.ofHoursMinutesSeconds(0, 1, 5).getLong(OFFSET_SECONDS), 65);
+    }
+
+    //-----------------------------------------------------------------------
+    // query(TemporalQuery)
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_query_chrono() {
+        ZoneOffset test = ZoneOffset.ofHoursMinutes(1, 30);
+        assertEquals(test.query(Queries.chrono()), null);
+        assertEquals(Queries.chrono().queryFrom(test), null);
+    }
+
+    @Test
+    public void test_query_zoneId() {
+        ZoneOffset test = ZoneOffset.ofHoursMinutes(1, 30);
+        assertEquals(test.query(Queries.zoneId()), null);
+        assertEquals(Queries.zoneId().queryFrom(test), null);
+    }
+
+    @Test
+    public void test_query_precision() {
+        ZoneOffset test = ZoneOffset.ofHoursMinutes(1, 30);
+        assertEquals(test.query(Queries.precision()), null);
+        assertEquals(Queries.precision().queryFrom(test), null);
+    }
+
+    @Test
+    public void test_query_offset() {
+        ZoneOffset test = ZoneOffset.ofHoursMinutes(1, 30);
+        assertEquals(test.query(Queries.offset()), test);
+        assertEquals(Queries.offset().queryFrom(test), test);
+    }
+
+    @Test
+    public void test_query_zone() {
+        ZoneOffset test = ZoneOffset.ofHoursMinutes(1, 30);
+        assertEquals(test.query(Queries.zone()), test);
+        assertEquals(Queries.zone().queryFrom(test), test);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_query_null() {
+        ZoneOffset.ofHoursMinutes(1, 30).query(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // compareTo()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_compareTo() {
+        ZoneOffset offset1 = ZoneOffset.ofHoursMinutesSeconds(1, 2, 3);
+        ZoneOffset offset2 = ZoneOffset.ofHoursMinutesSeconds(2, 3, 4);
+        assertTrue(offset1.compareTo(offset2) > 0);
+        assertTrue(offset2.compareTo(offset1) < 0);
+        assertTrue(offset1.compareTo(offset1) == 0);
+        assertTrue(offset2.compareTo(offset2) == 0);
+    }
+
+    //-----------------------------------------------------------------------
+    // equals() / hashCode()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_equals() {
+        ZoneOffset offset1 = ZoneOffset.ofHoursMinutesSeconds(1, 2, 3);
+        ZoneOffset offset2 = ZoneOffset.ofHoursMinutesSeconds(2, 3, 4);
+        ZoneOffset offset2b = ZoneOffset.ofHoursMinutesSeconds(2, 3, 4);
+        assertEquals(offset1.equals(offset2), false);
+        assertEquals(offset2.equals(offset1), false);
+
+        assertEquals(offset1.equals(offset1), true);
+        assertEquals(offset2.equals(offset2), true);
+        assertEquals(offset2.equals(offset2b), true);
+
+        assertEquals(offset1.hashCode() == offset1.hashCode(), true);
+        assertEquals(offset2.hashCode() == offset2.hashCode(), true);
+        assertEquals(offset2.hashCode() == offset2b.hashCode(), true);
+    }
+
+    //-----------------------------------------------------------------------
+    // toString()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_toString() {
+        ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(1, 0, 0);
+        assertEquals(offset.toString(), "+01:00");
+        offset = ZoneOffset.ofHoursMinutesSeconds(1, 2, 3);
+        assertEquals(offset.toString(), "+01:02:03");
+        offset = ZoneOffset.UTC;
+        assertEquals(offset.toString(), "Z");
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    private void doTestOffset(ZoneOffset offset, int hours, int minutes, int seconds) {
+        assertEquals(offset.getTotalSeconds(), hours * 60 * 60 + minutes * 60 + seconds);
+        final String id;
+        if (hours == 0 && minutes == 0 && seconds == 0) {
+            id = "Z";
+        } else {
+            String str = (hours < 0 || minutes < 0 || seconds < 0) ? "-" : "+";
+            str += Integer.toString(Math.abs(hours) + 100).substring(1);
+            str += ":";
+            str += Integer.toString(Math.abs(minutes) + 100).substring(1);
+            if (seconds != 0) {
+                str += ":";
+                str += Integer.toString(Math.abs(seconds) + 100).substring(1);
+            }
+            id = str;
+        }
+        assertEquals(offset.getId(), id);
+        assertEquals(offset, ZoneOffset.ofHoursMinutesSeconds(hours, minutes, seconds));
+        if (seconds == 0) {
+            assertEquals(offset, ZoneOffset.ofHoursMinutes(hours, minutes));
+            if (minutes == 0) {
+                assertEquals(offset, ZoneOffset.ofHours(hours));
+            }
+        }
+        assertEquals(ZoneOffset.of(id), offset);
+        assertEquals(offset.toString(), id);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,2166 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time;
+
+import java.time.*;
+import test.java.time.MockSimplePeriod;
+
+import static java.time.Month.JANUARY;
+import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH;
+import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR;
+import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH;
+import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR;
+import static java.time.temporal.ChronoField.AMPM_OF_DAY;
+import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_AMPM;
+import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_DAY;
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.DAY_OF_WEEK;
+import static java.time.temporal.ChronoField.DAY_OF_YEAR;
+import static java.time.temporal.ChronoField.EPOCH_DAY;
+import static java.time.temporal.ChronoField.EPOCH_MONTH;
+import static java.time.temporal.ChronoField.ERA;
+import static java.time.temporal.ChronoField.HOUR_OF_AMPM;
+import static java.time.temporal.ChronoField.HOUR_OF_DAY;
+import static java.time.temporal.ChronoField.INSTANT_SECONDS;
+import static java.time.temporal.ChronoField.MICRO_OF_DAY;
+import static java.time.temporal.ChronoField.MICRO_OF_SECOND;
+import static java.time.temporal.ChronoField.MILLI_OF_DAY;
+import static java.time.temporal.ChronoField.MILLI_OF_SECOND;
+import static java.time.temporal.ChronoField.MINUTE_OF_DAY;
+import static java.time.temporal.ChronoField.MINUTE_OF_HOUR;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.NANO_OF_DAY;
+import static java.time.temporal.ChronoField.NANO_OF_SECOND;
+import static java.time.temporal.ChronoField.OFFSET_SECONDS;
+import static java.time.temporal.ChronoField.SECOND_OF_DAY;
+import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
+import static java.time.temporal.ChronoField.YEAR;
+import static java.time.temporal.ChronoField.YEAR_OF_ERA;
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.HOURS;
+import static java.time.temporal.ChronoUnit.MINUTES;
+import static java.time.temporal.ChronoUnit.NANOS;
+import static java.time.temporal.ChronoUnit.SECONDS;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Queries;
+import java.time.temporal.TemporalSubtractor;
+import java.time.temporal.TemporalAdder;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.TemporalField;
+import java.time.temporal.ISOChrono;
+import java.time.temporal.JulianFields;
+import test.java.time.temporal.MockFieldNoValue;
+
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatters;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.OffsetDateTime;
+import java.time.temporal.Year;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test ZonedDateTime.
+ */
+@Test
+public class TCKZonedDateTime extends AbstractDateTimeTest {
+
+    private static final ZoneOffset OFFSET_0100 = ZoneOffset.ofHours(1);
+    private static final ZoneOffset OFFSET_0200 = ZoneOffset.ofHours(2);
+    private static final ZoneOffset OFFSET_0130 = ZoneOffset.of("+01:30");
+    private static final ZoneOffset OFFSET_MAX = ZoneOffset.MAX;
+    private static final ZoneOffset OFFSET_MIN = ZoneOffset.MIN;
+
+    private static final ZoneId ZONE_0100 = OFFSET_0100;
+    private static final ZoneId ZONE_0200 = OFFSET_0200;
+    private static final ZoneId ZONE_M0100 = ZoneOffset.ofHours(-1);
+    private static final ZoneId ZONE_LONDON = ZoneId.of("Europe/London");
+    private static final ZoneId ZONE_PARIS = ZoneId.of("Europe/Paris");
+    private LocalDateTime TEST_PARIS_GAP_2008_03_30_02_30;
+    private LocalDateTime TEST_PARIS_OVERLAP_2008_10_26_02_30;
+    private LocalDateTime TEST_LOCAL_2008_06_30_11_30_59_500;
+    private ZonedDateTime TEST_DATE_TIME;
+    private ZonedDateTime TEST_DATE_TIME_PARIS;
+
+    @BeforeMethod(groups={"tck","implementation"})
+    public void setUp() {
+        TEST_LOCAL_2008_06_30_11_30_59_500 = LocalDateTime.of(2008, 6, 30, 11, 30, 59, 500);
+        TEST_DATE_TIME = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100);
+        TEST_DATE_TIME_PARIS = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_PARIS);
+        TEST_PARIS_OVERLAP_2008_10_26_02_30 = LocalDateTime.of(2008, 10, 26, 2, 30);
+        TEST_PARIS_GAP_2008_03_30_02_30 = LocalDateTime.of(2008, 3, 30, 2, 30);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    protected List<TemporalAccessor> samples() {
+        TemporalAccessor[] array = {TEST_DATE_TIME, };
+        return Arrays.asList(array);
+    }
+
+    @Override
+    protected List<TemporalField> validFields() {
+        TemporalField[] array = {
+            NANO_OF_SECOND,
+            NANO_OF_DAY,
+            MICRO_OF_SECOND,
+            MICRO_OF_DAY,
+            MILLI_OF_SECOND,
+            MILLI_OF_DAY,
+            SECOND_OF_MINUTE,
+            SECOND_OF_DAY,
+            MINUTE_OF_HOUR,
+            MINUTE_OF_DAY,
+            CLOCK_HOUR_OF_AMPM,
+            HOUR_OF_AMPM,
+            CLOCK_HOUR_OF_DAY,
+            HOUR_OF_DAY,
+            AMPM_OF_DAY,
+            DAY_OF_WEEK,
+            ALIGNED_DAY_OF_WEEK_IN_MONTH,
+            ALIGNED_DAY_OF_WEEK_IN_YEAR,
+            DAY_OF_MONTH,
+            DAY_OF_YEAR,
+            EPOCH_DAY,
+            ALIGNED_WEEK_OF_MONTH,
+            ALIGNED_WEEK_OF_YEAR,
+            MONTH_OF_YEAR,
+            EPOCH_MONTH,
+            YEAR_OF_ERA,
+            YEAR,
+            ERA,
+            OFFSET_SECONDS,
+            INSTANT_SECONDS,
+            JulianFields.JULIAN_DAY,
+            JulianFields.MODIFIED_JULIAN_DAY,
+            JulianFields.RATA_DIE,
+        };
+        return Arrays.asList(array);
+    }
+
+    @Override
+    protected List<TemporalField> invalidFields() {
+        List<TemporalField> list = new ArrayList<>(Arrays.<TemporalField>asList(ChronoField.values()));
+        list.removeAll(validFields());
+        return list;
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_serialization() throws ClassNotFoundException, IOException {
+        assertSerializable(TEST_DATE_TIME);
+    }
+
+    @Test
+    public void test_serialization_format_zoneId() throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try (DataOutputStream dos = new DataOutputStream(baos) ) {
+            dos.writeByte(6);
+            dos.writeInt(2012); // date
+            dos.writeByte(9);
+            dos.writeByte(16);
+            dos.writeByte(22);  // time
+            dos.writeByte(17);
+            dos.writeByte(59);
+            dos.writeInt(470_000_000);
+            dos.writeByte(4);  // offset
+            dos.writeByte(7);  // zoneId
+            dos.writeUTF("Europe/London");
+        }
+        byte[] bytes = baos.toByteArray();
+        ZonedDateTime zdt = LocalDateTime.of(2012, 9, 16, 22, 17, 59, 470_000_000).atZone(ZoneId.of("Europe/London"));
+        assertSerializedBySer(zdt, bytes);
+    }
+
+    @Test
+    public void test_serialization_format_zoneOffset() throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try (DataOutputStream dos = new DataOutputStream(baos) ) {
+            dos.writeByte(6);
+            dos.writeInt(2012); // date
+            dos.writeByte(9);
+            dos.writeByte(16);
+            dos.writeByte(22);  // time
+            dos.writeByte(17);
+            dos.writeByte(59);
+            dos.writeInt(470_000_000);
+            dos.writeByte(4);  // offset
+            dos.writeByte(8);  // zoneId
+            dos.writeByte(4);
+        }
+        byte[] bytes = baos.toByteArray();
+        ZonedDateTime zdt = LocalDateTime.of(2012, 9, 16, 22, 17, 59, 470_000_000).atZone(ZoneOffset.ofHours(1));
+        assertSerializedBySer(zdt, bytes);
+    }
+
+    //-----------------------------------------------------------------------
+    // now()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void now() {
+        ZonedDateTime expected = ZonedDateTime.now(Clock.systemDefaultZone());
+        ZonedDateTime test = ZonedDateTime.now();
+        long diff = Math.abs(test.getTime().toNanoOfDay() - expected.getTime().toNanoOfDay());
+        if (diff >= 100000000) {
+            // may be date change
+            expected = ZonedDateTime.now(Clock.systemDefaultZone());
+            test = ZonedDateTime.now();
+            diff = Math.abs(test.getTime().toNanoOfDay() - expected.getTime().toNanoOfDay());
+        }
+        assertTrue(diff < 100000000);  // less than 0.1 secs
+    }
+
+    //-----------------------------------------------------------------------
+    // now(ZoneId)
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void now_ZoneId_nullZoneId() {
+        ZonedDateTime.now((ZoneId) null);
+    }
+
+    @Test(groups={"tck"})
+    public void now_ZoneId() {
+        ZoneId zone = ZoneId.of("UTC+01:02:03");
+        ZonedDateTime expected = ZonedDateTime.now(Clock.system(zone));
+        ZonedDateTime test = ZonedDateTime.now(zone);
+        for (int i = 0; i < 100; i++) {
+            if (expected.equals(test)) {
+                return;
+            }
+            expected = ZonedDateTime.now(Clock.system(zone));
+            test = ZonedDateTime.now(zone);
+        }
+        assertEquals(test, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // now(Clock)
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void now_Clock_nullClock() {
+        ZonedDateTime.now((Clock)null);
+    }
+
+    @Test(groups={"tck"})
+    public void now_Clock_allSecsInDay_utc() {
+        for (int i = 0; i < (2 * 24 * 60 * 60); i++) {
+            Instant instant = Instant.ofEpochSecond(i).plusNanos(123456789L);
+            Clock clock = Clock.fixed(instant, ZoneOffset.UTC);
+            ZonedDateTime test = ZonedDateTime.now(clock);
+            assertEquals(test.getYear(), 1970);
+            assertEquals(test.getMonth(), Month.JANUARY);
+            assertEquals(test.getDayOfMonth(), (i < 24 * 60 * 60 ? 1 : 2));
+            assertEquals(test.getHour(), (i / (60 * 60)) % 24);
+            assertEquals(test.getMinute(), (i / 60) % 60);
+            assertEquals(test.getSecond(), i % 60);
+            assertEquals(test.getNano(), 123456789);
+            assertEquals(test.getOffset(), ZoneOffset.UTC);
+            assertEquals(test.getZone(), ZoneOffset.UTC);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void now_Clock_allSecsInDay_zone() {
+        ZoneId zone = ZoneId.of("Europe/London");
+        for (int i = 0; i < (2 * 24 * 60 * 60); i++) {
+            Instant instant = Instant.ofEpochSecond(i).plusNanos(123456789L);
+            ZonedDateTime expected = ZonedDateTime.ofInstant(instant, zone);
+            Clock clock = Clock.fixed(expected.toInstant(), zone);
+            ZonedDateTime test = ZonedDateTime.now(clock);
+            assertEquals(test, expected);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void now_Clock_allSecsInDay_beforeEpoch() {
+        LocalTime expected = LocalTime.MIDNIGHT.plusNanos(123456789L);
+        for (int i =-1; i >= -(24 * 60 * 60); i--) {
+            Instant instant = Instant.ofEpochSecond(i).plusNanos(123456789L);
+            Clock clock = Clock.fixed(instant, ZoneOffset.UTC);
+            ZonedDateTime test = ZonedDateTime.now(clock);
+            assertEquals(test.getYear(), 1969);
+            assertEquals(test.getMonth(), Month.DECEMBER);
+            assertEquals(test.getDayOfMonth(), 31);
+            expected = expected.minusSeconds(1);
+            assertEquals(test.getTime(), expected);
+            assertEquals(test.getOffset(), ZoneOffset.UTC);
+            assertEquals(test.getZone(), ZoneOffset.UTC);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void now_Clock_offsets() {
+        ZonedDateTime base = ZonedDateTime.of(LocalDateTime.of(1970, 1, 1, 12, 0), ZoneOffset.UTC);
+        for (int i = -9; i < 15; i++) {
+            ZoneOffset offset = ZoneOffset.ofHours(i);
+            Clock clock = Clock.fixed(base.toInstant(), offset);
+            ZonedDateTime test = ZonedDateTime.now(clock);
+            assertEquals(test.getHour(), (12 + i) % 24);
+            assertEquals(test.getMinute(), 0);
+            assertEquals(test.getSecond(), 0);
+            assertEquals(test.getNano(), 0);
+            assertEquals(test.getOffset(), offset);
+            assertEquals(test.getZone(), offset);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // dateTime factories
+    //-----------------------------------------------------------------------
+    void check(ZonedDateTime test, int y, int m, int d, int h, int min, int s, int n, ZoneOffset offset, ZoneId zone) {
+        assertEquals(test.getYear(), y);
+        assertEquals(test.getMonth().getValue(), m);
+        assertEquals(test.getDayOfMonth(), d);
+        assertEquals(test.getHour(), h);
+        assertEquals(test.getMinute(), min);
+        assertEquals(test.getSecond(), s);
+        assertEquals(test.getNano(), n);
+        assertEquals(test.getOffset(), offset);
+        assertEquals(test.getZone(), zone);
+    }
+
+    //-----------------------------------------------------------------------
+    // of(LocalDateTime, ZoneId)
+    //-----------------------------------------------------------------------
+    // TODO: tests of overlap/gap
+
+    @Test(groups={"tck"})
+    public void factory_of_LocalDateTime() {
+        LocalDateTime base = LocalDateTime.of(2008, 6, 30, 11, 30, 10, 500);
+        ZonedDateTime test = ZonedDateTime.of(base, ZONE_PARIS);
+        check(test, 2008, 6, 30, 11, 30, 10, 500, OFFSET_0200, ZONE_PARIS);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_of_LocalDateTime_nullDateTime() {
+        ZonedDateTime.of((LocalDateTime) null, ZONE_PARIS);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_of_LocalDateTime_nullZone() {
+        LocalDateTime base = LocalDateTime.of(2008, 6, 30, 11, 30, 10, 500);
+        ZonedDateTime.of(base, null);
+    }
+
+    //-----------------------------------------------------------------------
+    // ofInstant(Instant, ZoneId)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_ofInstant_Instant_ZR() {
+        Instant instant = LocalDateTime.of(2008, 6, 30, 11, 30, 10, 35).toInstant(OFFSET_0200);
+        ZonedDateTime test = ZonedDateTime.ofInstant(instant, ZONE_PARIS);
+        check(test, 2008, 6, 30, 11, 30, 10, 35, OFFSET_0200, ZONE_PARIS);
+    }
+
+    @Test(groups={"tck"})
+    public void factory_ofInstant_Instant_ZO() {
+        Instant instant = LocalDateTime.of(2008, 6, 30, 11, 30, 10, 45).toInstant(OFFSET_0200);
+        ZonedDateTime test = ZonedDateTime.ofInstant(instant, OFFSET_0200);
+        check(test, 2008, 6, 30, 11, 30, 10, 45, OFFSET_0200, OFFSET_0200);
+    }
+
+    @Test(groups={"tck"})
+    public void factory_ofInstant_Instant_inGap() {
+        Instant instant = TEST_PARIS_GAP_2008_03_30_02_30.toInstant(OFFSET_0100);
+        ZonedDateTime test = ZonedDateTime.ofInstant(instant, ZONE_PARIS);
+        check(test, 2008, 3, 30, 3, 30, 0, 0, OFFSET_0200, ZONE_PARIS);  // one hour later in summer offset
+    }
+
+    @Test(groups={"tck"})
+    public void factory_ofInstant_Instant_inOverlap_earlier() {
+        Instant instant = TEST_PARIS_OVERLAP_2008_10_26_02_30.toInstant(OFFSET_0200);
+        ZonedDateTime test = ZonedDateTime.ofInstant(instant, ZONE_PARIS);
+        check(test, 2008, 10, 26, 2, 30, 0, 0, OFFSET_0200, ZONE_PARIS);  // same time and offset
+    }
+
+    @Test(groups={"tck"})
+    public void factory_ofInstant_Instant_inOverlap_later() {
+        Instant instant = TEST_PARIS_OVERLAP_2008_10_26_02_30.toInstant(OFFSET_0100);
+        ZonedDateTime test = ZonedDateTime.ofInstant(instant, ZONE_PARIS);
+        check(test, 2008, 10, 26, 2, 30, 0, 0, OFFSET_0100, ZONE_PARIS);  // same time and offset
+    }
+
+    @Test(groups={"tck"})
+    public void factory_ofInstant_Instant_invalidOffset() {
+        Instant instant = LocalDateTime.of(2008, 6, 30, 11, 30, 10, 500).toInstant(OFFSET_0130);
+        ZonedDateTime test = ZonedDateTime.ofInstant(instant, ZONE_PARIS);
+        check(test, 2008, 6, 30, 12, 0, 10, 500, OFFSET_0200, ZONE_PARIS);  // corrected offset, thus altered time
+    }
+
+    @Test(groups={"tck"})
+    public void factory_ofInstant_allSecsInDay() {
+        for (int i = 0; i < (24 * 60 * 60); i++) {
+            Instant instant = Instant.ofEpochSecond(i);
+            ZonedDateTime test = ZonedDateTime.ofInstant(instant, OFFSET_0100);
+            assertEquals(test.getYear(), 1970);
+            assertEquals(test.getMonth(), Month.JANUARY);
+            assertEquals(test.getDayOfMonth(), 1 + (i >= 23 * 60 * 60 ? 1 : 0));
+            assertEquals(test.getHour(), ((i / (60 * 60)) + 1) % 24);
+            assertEquals(test.getMinute(), (i / 60) % 60);
+            assertEquals(test.getSecond(), i % 60);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void factory_ofInstant_allDaysInCycle() {
+        // sanity check using different algorithm
+        ZonedDateTime expected = LocalDateTime.of(1970, 1, 1, 0, 0, 0, 0).atZone(ZoneOffset.UTC);
+        for (long i = 0; i < 146097; i++) {
+            Instant instant = Instant.ofEpochSecond(i * 24L * 60L * 60L);
+            ZonedDateTime test = ZonedDateTime.ofInstant(instant, ZoneOffset.UTC);
+            assertEquals(test, expected);
+            expected = expected.plusDays(1);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void factory_ofInstant_minWithMinOffset() {
+        long days_0000_to_1970 = (146097 * 5) - (30 * 365 + 7);
+        int year = Year.MIN_VALUE;
+        long days = (year * 365L + (year / 4 - year / 100 + year / 400)) - days_0000_to_1970;
+        Instant instant = Instant.ofEpochSecond(days * 24L * 60L * 60L - OFFSET_MIN.getTotalSeconds());
+        ZonedDateTime test = ZonedDateTime.ofInstant(instant, OFFSET_MIN);
+        assertEquals(test.getYear(), Year.MIN_VALUE);
+        assertEquals(test.getMonth().getValue(), 1);
+        assertEquals(test.getDayOfMonth(), 1);
+        assertEquals(test.getOffset(), OFFSET_MIN);
+        assertEquals(test.getHour(), 0);
+        assertEquals(test.getMinute(), 0);
+        assertEquals(test.getSecond(), 0);
+        assertEquals(test.getNano(), 0);
+    }
+
+    @Test(groups={"tck"})
+    public void factory_ofInstant_minWithMaxOffset() {
+        long days_0000_to_1970 = (146097 * 5) - (30 * 365 + 7);
+        int year = Year.MIN_VALUE;
+        long days = (year * 365L + (year / 4 - year / 100 + year / 400)) - days_0000_to_1970;
+        Instant instant = Instant.ofEpochSecond(days * 24L * 60L * 60L - OFFSET_MAX.getTotalSeconds());
+        ZonedDateTime test = ZonedDateTime.ofInstant(instant, OFFSET_MAX);
+        assertEquals(test.getYear(), Year.MIN_VALUE);
+        assertEquals(test.getMonth().getValue(), 1);
+        assertEquals(test.getDayOfMonth(), 1);
+        assertEquals(test.getOffset(), OFFSET_MAX);
+        assertEquals(test.getHour(), 0);
+        assertEquals(test.getMinute(), 0);
+        assertEquals(test.getSecond(), 0);
+        assertEquals(test.getNano(), 0);
+    }
+
+    @Test(groups={"tck"})
+    public void factory_ofInstant_maxWithMinOffset() {
+        long days_0000_to_1970 = (146097 * 5) - (30 * 365 + 7);
+        int year = Year.MAX_VALUE;
+        long days = (year * 365L + (year / 4 - year / 100 + year / 400)) + 365 - days_0000_to_1970;
+        Instant instant = Instant.ofEpochSecond((days + 1) * 24L * 60L * 60L - 1 - OFFSET_MIN.getTotalSeconds());
+        ZonedDateTime test = ZonedDateTime.ofInstant(instant, OFFSET_MIN);
+        assertEquals(test.getYear(), Year.MAX_VALUE);
+        assertEquals(test.getMonth().getValue(), 12);
+        assertEquals(test.getDayOfMonth(), 31);
+        assertEquals(test.getOffset(), OFFSET_MIN);
+        assertEquals(test.getHour(), 23);
+        assertEquals(test.getMinute(), 59);
+        assertEquals(test.getSecond(), 59);
+        assertEquals(test.getNano(), 0);
+    }
+
+    @Test(groups={"tck"})
+    public void factory_ofInstant_maxWithMaxOffset() {
+        long days_0000_to_1970 = (146097 * 5) - (30 * 365 + 7);
+        int year = Year.MAX_VALUE;
+        long days = (year * 365L + (year / 4 - year / 100 + year / 400)) + 365 - days_0000_to_1970;
+        Instant instant = Instant.ofEpochSecond((days + 1) * 24L * 60L * 60L - 1 - OFFSET_MAX.getTotalSeconds());
+        ZonedDateTime test = ZonedDateTime.ofInstant(instant, OFFSET_MAX);
+        assertEquals(test.getYear(), Year.MAX_VALUE);
+        assertEquals(test.getMonth().getValue(), 12);
+        assertEquals(test.getDayOfMonth(), 31);
+        assertEquals(test.getOffset(), OFFSET_MAX);
+        assertEquals(test.getHour(), 23);
+        assertEquals(test.getMinute(), 59);
+        assertEquals(test.getSecond(), 59);
+        assertEquals(test.getNano(), 0);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_ofInstant_maxInstantWithMaxOffset() {
+        Instant instant = Instant.ofEpochSecond(Long.MAX_VALUE);
+        ZonedDateTime.ofInstant(instant, OFFSET_MAX);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_ofInstant_maxInstantWithMinOffset() {
+        Instant instant = Instant.ofEpochSecond(Long.MAX_VALUE);
+        ZonedDateTime.ofInstant(instant, OFFSET_MIN);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_ofInstant_tooBig() {
+        long days_0000_to_1970 = (146097 * 5) - (30 * 365 + 7);
+        long year = Year.MAX_VALUE + 1L;
+        long days = (year * 365L + (year / 4 - year / 100 + year / 400)) - days_0000_to_1970;
+        Instant instant = Instant.ofEpochSecond(days * 24L * 60L * 60L);
+        ZonedDateTime.ofInstant(instant, ZoneOffset.UTC);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_ofInstant_tooLow() {
+        long days_0000_to_1970 = (146097 * 5) - (30 * 365 + 7);
+        int year = Year.MIN_VALUE - 1;
+        long days = (year * 365L + (year / 4 - year / 100 + year / 400)) - days_0000_to_1970;
+        Instant instant = Instant.ofEpochSecond(days * 24L * 60L * 60L);
+        ZonedDateTime.ofInstant(instant, ZoneOffset.UTC);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_ofInstant_Instant_nullInstant() {
+        ZonedDateTime.ofInstant((Instant) null, ZONE_0100);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_ofInstant_Instant_nullZone() {
+        ZonedDateTime.ofInstant(Instant.EPOCH, null);
+    }
+
+    //-----------------------------------------------------------------------
+    // ofStrict(LocalDateTime, ZoneId, ZoneOffset)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_ofStrict_LDT_ZI_ZO() {
+        LocalDateTime normal = LocalDateTime.of(2008, 6, 30, 11, 30, 10, 500);
+        ZonedDateTime test = ZonedDateTime.ofStrict(normal, OFFSET_0200, ZONE_PARIS);
+        check(test, 2008, 6, 30, 11, 30, 10, 500, OFFSET_0200, ZONE_PARIS);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_ofStrict_LDT_ZI_ZO_inGap() {
+        try {
+            ZonedDateTime.ofStrict(TEST_PARIS_GAP_2008_03_30_02_30, OFFSET_0100, ZONE_PARIS);
+        } catch (DateTimeException ex) {
+            assertEquals(ex.getMessage().contains(" gap"), true);
+            throw ex;
+        }
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_ofStrict_LDT_ZI_ZO_inOverlap_invalidOfset() {
+        try {
+            ZonedDateTime.ofStrict(TEST_PARIS_OVERLAP_2008_10_26_02_30, OFFSET_0130, ZONE_PARIS);
+        } catch (DateTimeException ex) {
+            assertEquals(ex.getMessage().contains(" is not valid for "), true);
+            throw ex;
+        }
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_ofStrict_LDT_ZI_ZO_invalidOffset() {
+        try {
+            ZonedDateTime.ofStrict(TEST_LOCAL_2008_06_30_11_30_59_500, OFFSET_0130, ZONE_PARIS);
+        } catch (DateTimeException ex) {
+            assertEquals(ex.getMessage().contains(" is not valid for "), true);
+            throw ex;
+        }
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_ofStrict_LDT_ZI_ZO_nullLDT() {
+        ZonedDateTime.ofStrict((LocalDateTime) null, OFFSET_0100, ZONE_PARIS);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_ofStrict_LDT_ZI_ZO_nullZO() {
+        ZonedDateTime.ofStrict(TEST_LOCAL_2008_06_30_11_30_59_500, null, ZONE_PARIS);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_ofStrict_LDT_ZI_ZO_nullZI() {
+        ZonedDateTime.ofStrict(TEST_LOCAL_2008_06_30_11_30_59_500, OFFSET_0100, null);
+    }
+
+    //-----------------------------------------------------------------------
+    // from(TemporalAccessor)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_from_TemporalAccessor_ZDT() {
+        assertEquals(ZonedDateTime.from(TEST_DATE_TIME_PARIS), TEST_DATE_TIME_PARIS);
+    }
+
+    @Test(groups={"tck"})
+    public void factory_from_TemporalAccessor_LDT_ZoneId() {
+        assertEquals(ZonedDateTime.from(new TemporalAccessor() {
+            @Override
+            public boolean isSupported(TemporalField field) {
+                return TEST_DATE_TIME_PARIS.getDateTime().isSupported(field);
+            }
+            @Override
+            public long getLong(TemporalField field) {
+                return TEST_DATE_TIME_PARIS.getDateTime().getLong(field);
+            }
+            @SuppressWarnings("unchecked")
+            @Override
+            public <R> R query(TemporalQuery<R> query) {
+                if (query == Queries.zoneId()) {
+                    return (R) TEST_DATE_TIME_PARIS.getZone();
+                }
+                return TemporalAccessor.super.query(query);
+            }
+        }), TEST_DATE_TIME_PARIS);
+    }
+
+    @Test(groups={"tck"})
+    public void factory_from_TemporalAccessor_Instant_ZoneId() {
+        assertEquals(ZonedDateTime.from(new TemporalAccessor() {
+            @Override
+            public boolean isSupported(TemporalField field) {
+                return field == INSTANT_SECONDS || field == NANO_OF_SECOND;
+            }
+
+            @Override
+            public long getLong(TemporalField field) {
+                return TEST_DATE_TIME_PARIS.toInstant().getLong(field);
+            }
+
+            @SuppressWarnings("unchecked")
+            @Override
+            public <R> R query(TemporalQuery<R> query) {
+                if (query == Queries.zoneId()) {
+                    return (R) TEST_DATE_TIME_PARIS.getZone();
+                }
+                return TemporalAccessor.super.query(query);
+            }
+        }), TEST_DATE_TIME_PARIS);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_from_TemporalAccessor_invalid_noDerive() {
+        ZonedDateTime.from(LocalTime.of(12, 30));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_from_TemporalAccessor_null() {
+        ZonedDateTime.from((TemporalAccessor) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // parse()
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="sampleToString", groups={"tck"})
+    public void test_parse(int y, int month, int d, int h, int m, int s, int n, String zoneId, String text) {
+        ZonedDateTime t = ZonedDateTime.parse(text);
+        assertEquals(t.getYear(), y);
+        assertEquals(t.getMonth().getValue(), month);
+        assertEquals(t.getDayOfMonth(), d);
+        assertEquals(t.getHour(), h);
+        assertEquals(t.getMinute(), m);
+        assertEquals(t.getSecond(), s);
+        assertEquals(t.getNano(), n);
+        assertEquals(t.getZone().getId(), zoneId);
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"})
+    public void factory_parse_illegalValue() {
+        ZonedDateTime.parse("2008-06-32T11:15+01:00[Europe/Paris]");
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"})
+    public void factory_parse_invalidValue() {
+        ZonedDateTime.parse("2008-06-31T11:15+01:00[Europe/Paris]");
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_parse_nullText() {
+        ZonedDateTime.parse((String) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // parse(DateTimeFormatter)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_parse_formatter() {
+        DateTimeFormatter f = DateTimeFormatters.pattern("y M d H m s I");
+        ZonedDateTime test = ZonedDateTime.parse("2010 12 3 11 30 0 Europe/London", f);
+        assertEquals(test, ZonedDateTime.of(LocalDateTime.of(2010, 12, 3, 11, 30), ZoneId.of("Europe/London")));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_parse_formatter_nullText() {
+        DateTimeFormatter f = DateTimeFormatters.pattern("y M d H m s");
+        ZonedDateTime.parse((String) null, f);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_parse_formatter_nullFormatter() {
+        ZonedDateTime.parse("ANY", null);
+    }
+
+    //-----------------------------------------------------------------------
+    // basics
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sampleTimes")
+    Object[][] provider_sampleTimes() {
+        return new Object[][] {
+            {2008, 6, 30, 11, 30, 20, 500, ZONE_0100},
+            {2008, 6, 30, 11, 0, 0, 0, ZONE_0100},
+            {2008, 6, 30, 11, 30, 20, 500, ZONE_PARIS},
+            {2008, 6, 30, 11, 0, 0, 0, ZONE_PARIS},
+            {2008, 6, 30, 23, 59, 59, 999999999, ZONE_0100},
+            {-1, 1, 1, 0, 0, 0, 0, ZONE_0100},
+        };
+    }
+
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_get(int y, int o, int d, int h, int m, int s, int n, ZoneId zone) {
+        LocalDate localDate = LocalDate.of(y, o, d);
+        LocalTime localTime = LocalTime.of(h, m, s, n);
+        LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);
+        ZoneOffset offset = zone.getRules().getOffset(localDateTime);
+        ZonedDateTime a = ZonedDateTime.of(localDateTime, zone);
+
+        assertEquals(a.getYear(), localDate.getYear());
+        assertEquals(a.getMonth(), localDate.getMonth());
+        assertEquals(a.getDayOfMonth(), localDate.getDayOfMonth());
+        assertEquals(a.getDayOfYear(), localDate.getDayOfYear());
+        assertEquals(a.getDayOfWeek(), localDate.getDayOfWeek());
+
+        assertEquals(a.getHour(), localTime.getHour());
+        assertEquals(a.getMinute(), localTime.getMinute());
+        assertEquals(a.getSecond(), localTime.getSecond());
+        assertEquals(a.getNano(), localTime.getNano());
+
+        assertEquals(a.getDate(), localDate);
+        assertEquals(a.getTime(), localTime);
+        assertEquals(a.getDateTime(), localDateTime);
+        if (zone instanceof ZoneOffset) {
+            assertEquals(a.toString(), localDateTime.toString() + offset.toString());
+        } else {
+            assertEquals(a.toString(), localDateTime.toString() + offset.toString() + "[" + zone.toString() + "]");
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // get(TemporalField)
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_get_TemporalField() {
+        ZonedDateTime test = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 12, 30, 40, 987654321), ZONE_0100);
+        assertEquals(test.get(ChronoField.YEAR), 2008);
+        assertEquals(test.get(ChronoField.MONTH_OF_YEAR), 6);
+        assertEquals(test.get(ChronoField.DAY_OF_MONTH), 30);
+        assertEquals(test.get(ChronoField.DAY_OF_WEEK), 1);
+        assertEquals(test.get(ChronoField.DAY_OF_YEAR), 182);
+
+        assertEquals(test.get(ChronoField.HOUR_OF_DAY), 12);
+        assertEquals(test.get(ChronoField.MINUTE_OF_HOUR), 30);
+        assertEquals(test.get(ChronoField.SECOND_OF_MINUTE), 40);
+        assertEquals(test.get(ChronoField.NANO_OF_SECOND), 987654321);
+        assertEquals(test.get(ChronoField.HOUR_OF_AMPM), 0);
+        assertEquals(test.get(ChronoField.AMPM_OF_DAY), 1);
+
+        assertEquals(test.get(ChronoField.OFFSET_SECONDS), 3600);
+    }
+
+    @Test
+    public void test_getLong_TemporalField() {
+        ZonedDateTime test = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 12, 30, 40, 987654321), ZONE_0100);
+        assertEquals(test.getLong(ChronoField.YEAR), 2008);
+        assertEquals(test.getLong(ChronoField.MONTH_OF_YEAR), 6);
+        assertEquals(test.getLong(ChronoField.DAY_OF_MONTH), 30);
+        assertEquals(test.getLong(ChronoField.DAY_OF_WEEK), 1);
+        assertEquals(test.getLong(ChronoField.DAY_OF_YEAR), 182);
+
+        assertEquals(test.getLong(ChronoField.HOUR_OF_DAY), 12);
+        assertEquals(test.getLong(ChronoField.MINUTE_OF_HOUR), 30);
+        assertEquals(test.getLong(ChronoField.SECOND_OF_MINUTE), 40);
+        assertEquals(test.getLong(ChronoField.NANO_OF_SECOND), 987654321);
+        assertEquals(test.getLong(ChronoField.HOUR_OF_AMPM), 0);
+        assertEquals(test.getLong(ChronoField.AMPM_OF_DAY), 1);
+
+        assertEquals(test.getLong(ChronoField.OFFSET_SECONDS), 3600);
+        assertEquals(test.getLong(ChronoField.INSTANT_SECONDS), test.toEpochSecond());
+    }
+
+    //-----------------------------------------------------------------------
+    // query(TemporalQuery)
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_query_chrono() {
+        assertEquals(TEST_DATE_TIME.query(Queries.chrono()), ISOChrono.INSTANCE);
+        assertEquals(Queries.chrono().queryFrom(TEST_DATE_TIME), ISOChrono.INSTANCE);
+    }
+
+    @Test
+    public void test_query_zoneId() {
+        assertEquals(TEST_DATE_TIME.query(Queries.zoneId()), TEST_DATE_TIME.getZone());
+        assertEquals(Queries.zoneId().queryFrom(TEST_DATE_TIME), TEST_DATE_TIME.getZone());
+    }
+
+    @Test
+    public void test_query_precision() {
+        assertEquals(TEST_DATE_TIME.query(Queries.precision()), NANOS);
+        assertEquals(Queries.precision().queryFrom(TEST_DATE_TIME), NANOS);
+    }
+
+    @Test
+    public void test_query_offset() {
+        assertEquals(TEST_DATE_TIME.query(Queries.offset()), TEST_DATE_TIME.getOffset());
+        assertEquals(Queries.offset().queryFrom(TEST_DATE_TIME), TEST_DATE_TIME.getOffset());
+    }
+
+    @Test
+    public void test_query_zone() {
+        assertEquals(TEST_DATE_TIME.query(Queries.zone()), TEST_DATE_TIME.getZone());
+        assertEquals(Queries.zone().queryFrom(TEST_DATE_TIME), TEST_DATE_TIME.getZone());
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_query_null() {
+        TEST_DATE_TIME.query(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // withEarlierOffsetAtOverlap()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withEarlierOffsetAtOverlap_notAtOverlap() {
+        ZonedDateTime base = ZonedDateTime.ofStrict(TEST_LOCAL_2008_06_30_11_30_59_500, OFFSET_0200, ZONE_PARIS);
+        ZonedDateTime test = base.withEarlierOffsetAtOverlap();
+        assertEquals(test, base);  // not changed
+    }
+
+    @Test(groups={"tck"})
+    public void test_withEarlierOffsetAtOverlap_atOverlap() {
+        ZonedDateTime base = ZonedDateTime.ofStrict(TEST_PARIS_OVERLAP_2008_10_26_02_30, OFFSET_0100, ZONE_PARIS);
+        ZonedDateTime test = base.withEarlierOffsetAtOverlap();
+        assertEquals(test.getOffset(), OFFSET_0200);  // offset changed to earlier
+        assertEquals(test.getDateTime(), base.getDateTime());  // date-time not changed
+    }
+
+    @Test(groups={"tck"})
+    public void test_withEarlierOffsetAtOverlap_atOverlap_noChange() {
+        ZonedDateTime base = ZonedDateTime.ofStrict(TEST_PARIS_OVERLAP_2008_10_26_02_30, OFFSET_0200, ZONE_PARIS);
+        ZonedDateTime test = base.withEarlierOffsetAtOverlap();
+        assertEquals(test, base);  // not changed
+    }
+
+    //-----------------------------------------------------------------------
+    // withLaterOffsetAtOverlap()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withLaterOffsetAtOverlap_notAtOverlap() {
+        ZonedDateTime base = ZonedDateTime.ofStrict(TEST_LOCAL_2008_06_30_11_30_59_500, OFFSET_0200, ZONE_PARIS);
+        ZonedDateTime test = base.withLaterOffsetAtOverlap();
+        assertEquals(test, base);  // not changed
+    }
+
+    @Test(groups={"tck"})
+    public void test_withLaterOffsetAtOverlap_atOverlap() {
+        ZonedDateTime base = ZonedDateTime.ofStrict(TEST_PARIS_OVERLAP_2008_10_26_02_30, OFFSET_0200, ZONE_PARIS);
+        ZonedDateTime test = base.withLaterOffsetAtOverlap();
+        assertEquals(test.getOffset(), OFFSET_0100);  // offset changed to later
+        assertEquals(test.getDateTime(), base.getDateTime());  // date-time not changed
+    }
+
+    @Test(groups={"tck"})
+    public void test_withLaterOffsetAtOverlap_atOverlap_noChange() {
+        ZonedDateTime base = ZonedDateTime.ofStrict(TEST_PARIS_OVERLAP_2008_10_26_02_30, OFFSET_0100, ZONE_PARIS);
+        ZonedDateTime test = base.withLaterOffsetAtOverlap();
+        assertEquals(test, base);  // not changed
+    }
+
+    //-----------------------------------------------------------------------
+    // withZoneSameLocal(ZoneId)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withZoneSameLocal() {
+        LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0);
+        ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100);
+        ZonedDateTime test = base.withZoneSameLocal(ZONE_0200);
+        assertEquals(test.getDateTime(), base.getDateTime());
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withZoneSameLocal_noChange() {
+        LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0);
+        ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100);
+        ZonedDateTime test = base.withZoneSameLocal(ZONE_0100);
+        assertEquals(test, base);
+    }
+
+    @Test(groups={"tck"})
+    public void test_withZoneSameLocal_retainOffset1() {
+        LocalDateTime ldt = LocalDateTime.of(2008, 11, 2, 1, 30, 59, 0);  // overlap
+        ZonedDateTime base = ZonedDateTime.of(ldt, ZoneId.of("UTC-04:00") );
+        ZonedDateTime test = base.withZoneSameLocal(ZoneId.of("America/New_York"));
+        assertEquals(base.getOffset(), ZoneOffset.ofHours(-4));
+        assertEquals(test.getOffset(), ZoneOffset.ofHours(-4));
+    }
+
+    @Test(groups={"tck"})
+    public void test_withZoneSameLocal_retainOffset2() {
+        LocalDateTime ldt = LocalDateTime.of(2008, 11, 2, 1, 30, 59, 0);  // overlap
+        ZonedDateTime base = ZonedDateTime.of(ldt, ZoneId.of("UTC-05:00") );
+        ZonedDateTime test = base.withZoneSameLocal(ZoneId.of("America/New_York"));
+        assertEquals(base.getOffset(), ZoneOffset.ofHours(-5));
+        assertEquals(test.getOffset(), ZoneOffset.ofHours(-5));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_withZoneSameLocal_null() {
+        LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0);
+        ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100);
+        base.withZoneSameLocal(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // withZoneSameInstant()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withZoneSameInstant() {
+        ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100);
+        ZonedDateTime test = base.withZoneSameInstant(ZONE_0200);
+        ZonedDateTime expected = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500.plusHours(1), ZONE_0200);
+        assertEquals(test, expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_withZoneSameInstant_noChange() {
+        ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100);
+        ZonedDateTime test = base.withZoneSameInstant(ZONE_0100);
+        assertEquals(test, base);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_withZoneSameInstant_null() {
+        ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100);
+        base.withZoneSameInstant(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // withFixedOffsetZone()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withZoneLocked() {
+        ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_PARIS);
+        ZonedDateTime test = base.withFixedOffsetZone();
+        ZonedDateTime expected = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0200);
+        assertEquals(test, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // with(WithAdjuster)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_with_WithAdjuster_LocalDateTime_sameOffset() {
+        ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_PARIS);
+        ZonedDateTime test = base.with(LocalDateTime.of(2012, 7, 15, 14, 30));
+        check(test, 2012, 7, 15, 14, 30, 0, 0, OFFSET_0200, ZONE_PARIS);
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_WithAdjuster_LocalDateTime_adjustedOffset() {
+        ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_PARIS);
+        ZonedDateTime test = base.with(LocalDateTime.of(2012, 1, 15, 14, 30));
+        check(test, 2012, 1, 15, 14, 30, 0, 0, OFFSET_0100, ZONE_PARIS);
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_WithAdjuster_LocalDate() {
+        ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_PARIS);
+        ZonedDateTime test = base.with(LocalDate.of(2012, 7, 28));
+        check(test, 2012, 7, 28, 11, 30, 59, 500, OFFSET_0200, ZONE_PARIS);
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_WithAdjuster_LocalTime() {
+        ZonedDateTime base = ZonedDateTime.of(TEST_PARIS_OVERLAP_2008_10_26_02_30, ZONE_PARIS);
+        ZonedDateTime test = base.with(LocalTime.of(2, 29));
+        check(test, 2008, 10, 26, 2, 29, 0, 0, OFFSET_0200, ZONE_PARIS);
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_WithAdjuster_Year() {
+        LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0);
+        ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100);
+        ZonedDateTime test = base.with(Year.of(2007));
+        assertEquals(test, ZonedDateTime.of(ldt.withYear(2007), ZONE_0100));
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_WithAdjuster_Month_adjustedDayOfMonth() {
+        ZonedDateTime base = ZonedDateTime.of(LocalDateTime.of(2012, 7, 31, 0, 0), ZONE_PARIS);
+        ZonedDateTime test = base.with(Month.JUNE);
+        check(test, 2012, 6, 30, 0, 0, 0, 0, OFFSET_0200, ZONE_PARIS);
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_WithAdjuster_Offset_same() {
+        ZonedDateTime base = ZonedDateTime.of(LocalDateTime.of(2012, 7, 31, 0, 0), ZONE_PARIS);
+        ZonedDateTime test = base.with(ZoneOffset.ofHours(2));
+        check(test, 2012, 7, 31, 0, 0, 0, 0, OFFSET_0200, ZONE_PARIS);
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_WithAdjuster_Offset_timeAdjust() {
+        ZonedDateTime base = ZonedDateTime.of(LocalDateTime.of(2012, 7, 31, 0, 0), ZONE_PARIS);
+        ZonedDateTime test = base.with(ZoneOffset.ofHours(1));
+        check(test, 2012, 7, 31, 1, 0, 0, 0, OFFSET_0200, ZONE_PARIS);  // time adjusted
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_WithAdjuster_LocalDate_retainOffset1() {
+        ZoneId newYork = ZoneId.of("America/New_York");
+        LocalDateTime ldt = LocalDateTime.of(2008, 11, 1, 1, 30);
+        ZonedDateTime base = ZonedDateTime.of(ldt, newYork);
+        assertEquals(base.getOffset(), ZoneOffset.ofHours(-4));
+        ZonedDateTime test = base.with(LocalDate.of(2008, 11, 2));
+        assertEquals(test.getOffset(), ZoneOffset.ofHours(-4));
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_WithAdjuster_LocalDate_retainOffset2() {
+        ZoneId newYork = ZoneId.of("America/New_York");
+        LocalDateTime ldt = LocalDateTime.of(2008, 11, 3, 1, 30);
+        ZonedDateTime base = ZonedDateTime.of(ldt, newYork);
+        assertEquals(base.getOffset(), ZoneOffset.ofHours(-5));
+        ZonedDateTime test = base.with(LocalDate.of(2008, 11, 2));
+        assertEquals(test.getOffset(), ZoneOffset.ofHours(-5));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_with_WithAdjuster_null() {
+        ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100);
+        base.with((TemporalAdjuster) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // withYear()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withYear_normal() {
+        ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100);
+        ZonedDateTime test = base.withYear(2007);
+        assertEquals(test, ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500.withYear(2007), ZONE_0100));
+    }
+
+    @Test(groups={"tck"})
+    public void test_withYear_noChange() {
+        ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100);
+        ZonedDateTime test = base.withYear(2008);
+        assertEquals(test, base);
+    }
+
+    //-----------------------------------------------------------------------
+    // with(Month)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withMonth_Month_normal() {
+        ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100);
+        ZonedDateTime test = base.with(JANUARY);
+        assertEquals(test, ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500.withMonth(1), ZONE_0100));
+    }
+
+    @Test(expectedExceptions = NullPointerException.class, groups={"tck"})
+    public void test_withMonth_Month_null() {
+        ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100);
+        base.with((Month) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // withMonth()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withMonth_normal() {
+        ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100);
+        ZonedDateTime test = base.withMonth(1);
+        assertEquals(test, ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500.withMonth(1), ZONE_0100));
+    }
+
+    @Test(groups={"tck"})
+    public void test_withMonth_noChange() {
+        ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100);
+        ZonedDateTime test = base.withMonth(6);
+        assertEquals(test, base);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withMonth_tooBig() {
+        TEST_DATE_TIME.withMonth(13);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withMonth_tooSmall() {
+        TEST_DATE_TIME.withMonth(0);
+    }
+
+    //-----------------------------------------------------------------------
+    // withDayOfMonth()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withDayOfMonth_normal() {
+        ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100);
+        ZonedDateTime test = base.withDayOfMonth(15);
+        assertEquals(test, ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500.withDayOfMonth(15), ZONE_0100));
+    }
+
+    @Test(groups={"tck"})
+    public void test_withDayOfMonth_noChange() {
+        ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100);
+        ZonedDateTime test = base.withDayOfMonth(30);
+        assertEquals(test, base);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withDayOfMonth_tooBig() {
+        LocalDateTime.of(2007, 7, 2, 11, 30).atZone(ZONE_PARIS).withDayOfMonth(32);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withDayOfMonth_tooSmall() {
+        TEST_DATE_TIME.withDayOfMonth(0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withDayOfMonth_invalid31() {
+        LocalDateTime.of(2007, 6, 2, 11, 30).atZone(ZONE_PARIS).withDayOfMonth(31);
+    }
+
+    //-----------------------------------------------------------------------
+    // withDayOfYear()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withDayOfYear_normal() {
+        ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100);
+        ZonedDateTime test = base.withDayOfYear(33);
+        assertEquals(test, ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500.withDayOfYear(33), ZONE_0100));
+    }
+
+    @Test(groups={"tck"})
+    public void test_withDayOfYear_noChange() {
+        LocalDateTime ldt = LocalDateTime.of(2008, 2, 5, 23, 30, 59, 0);
+        ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100);
+        ZonedDateTime test = base.withDayOfYear(36);
+        assertEquals(test, base);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withDayOfYear_tooBig() {
+        TEST_DATE_TIME.withDayOfYear(367);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withDayOfYear_tooSmall() {
+        TEST_DATE_TIME.withDayOfYear(0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withDayOfYear_invalid366() {
+        LocalDateTime.of(2007, 2, 2, 11, 30).atZone(ZONE_PARIS).withDayOfYear(366);
+    }
+
+    //-----------------------------------------------------------------------
+    // withHour()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withHour_normal() {
+        ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100);
+        ZonedDateTime test = base.withHour(15);
+        assertEquals(test, ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500.withHour(15), ZONE_0100));
+    }
+
+    @Test(groups={"tck"})
+    public void test_withHour_noChange() {
+        ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100);
+        ZonedDateTime test = base.withHour(11);
+        assertEquals(test, base);
+    }
+
+    //-----------------------------------------------------------------------
+    // withMinute()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withMinute_normal() {
+        ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100);
+        ZonedDateTime test = base.withMinute(15);
+        assertEquals(test, ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500.withMinute(15), ZONE_0100));
+    }
+
+    @Test(groups={"tck"})
+    public void test_withMinute_noChange() {
+        ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100);
+        ZonedDateTime test = base.withMinute(30);
+        assertEquals(test, base);
+    }
+
+    //-----------------------------------------------------------------------
+    // withSecond()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withSecond_normal() {
+        ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100);
+        ZonedDateTime test = base.withSecond(12);
+        assertEquals(test, ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500.withSecond(12), ZONE_0100));
+    }
+
+    @Test(groups={"tck"})
+    public void test_withSecond_noChange() {
+        ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100);
+        ZonedDateTime test = base.withSecond(59);
+        assertEquals(test, base);
+    }
+
+    //-----------------------------------------------------------------------
+    // withNano()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withNanoOfSecond_normal() {
+        ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100);
+        ZonedDateTime test = base.withNano(15);
+        assertEquals(test, ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500.withNano(15), ZONE_0100));
+    }
+
+    @Test(groups={"tck"})
+    public void test_withNanoOfSecond_noChange() {
+        ZonedDateTime base = ZonedDateTime.of(TEST_LOCAL_2008_06_30_11_30_59_500, ZONE_0100);
+        ZonedDateTime test = base.withNano(500);
+        assertEquals(test, base);
+    }
+
+    //-----------------------------------------------------------------------
+    // truncatedTo(TemporalUnit)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_truncatedTo_normal() {
+        assertEquals(TEST_DATE_TIME.truncatedTo(NANOS), TEST_DATE_TIME);
+        assertEquals(TEST_DATE_TIME.truncatedTo(SECONDS), TEST_DATE_TIME.withNano(0));
+        assertEquals(TEST_DATE_TIME.truncatedTo(DAYS), TEST_DATE_TIME.with(LocalTime.MIDNIGHT));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_truncatedTo_null() {
+        TEST_DATE_TIME.truncatedTo(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // plus/minus
+    //-----------------------------------------------------------------------
+    @DataProvider(name="plusDays")
+    Object[][] data_plusDays() {
+        return new Object[][] {
+            // normal
+            {dateTime(2008, 6, 30, 23, 30, 59, 0, OFFSET_0100, ZONE_0100), 0, dateTime(2008, 6, 30, 23, 30, 59, 0, OFFSET_0100, ZONE_0100)},
+            {dateTime(2008, 6, 30, 23, 30, 59, 0, OFFSET_0100, ZONE_0100), 1, dateTime(2008, 7, 1, 23, 30, 59, 0, OFFSET_0100, ZONE_0100)},
+            {dateTime(2008, 6, 30, 23, 30, 59, 0, OFFSET_0100, ZONE_0100), -1, dateTime(2008, 6, 29, 23, 30, 59, 0, OFFSET_0100, ZONE_0100)},
+            // skip over gap
+            {dateTime(2008, 3, 30, 1, 30, 0, 0, OFFSET_0100, ZONE_PARIS), 1, dateTime(2008, 3, 31, 1, 30, 0, 0, OFFSET_0200, ZONE_PARIS)},
+            {dateTime(2008, 3, 30, 3, 30, 0, 0, OFFSET_0200, ZONE_PARIS), -1, dateTime(2008, 3, 29, 3, 30, 0, 0, OFFSET_0100, ZONE_PARIS)},
+            // land in gap
+            {dateTime(2008, 3, 29, 2, 30, 0, 0, OFFSET_0100, ZONE_PARIS), 1, dateTime(2008, 3, 30, 3, 30, 0, 0, OFFSET_0200, ZONE_PARIS)},
+            {dateTime(2008, 3, 31, 2, 30, 0, 0, OFFSET_0200, ZONE_PARIS), -1, dateTime(2008, 3, 30, 3, 30, 0, 0, OFFSET_0200, ZONE_PARIS)},
+            // skip over overlap
+            {dateTime(2008, 10, 26, 1, 30, 0, 0, OFFSET_0200, ZONE_PARIS), 1, dateTime(2008, 10, 27, 1, 30, 0, 0, OFFSET_0100, ZONE_PARIS)},
+            {dateTime(2008, 10, 25, 3, 30, 0, 0, OFFSET_0200, ZONE_PARIS), 1, dateTime(2008, 10, 26, 3, 30, 0, 0, OFFSET_0100, ZONE_PARIS)},
+            // land in overlap
+            {dateTime(2008, 10, 25, 2, 30, 0, 0, OFFSET_0200, ZONE_PARIS), 1, dateTime(2008, 10, 26, 2, 30, 0, 0, OFFSET_0200, ZONE_PARIS)},
+            {dateTime(2008, 10, 27, 2, 30, 0, 0, OFFSET_0100, ZONE_PARIS), -1, dateTime(2008, 10, 26, 2, 30, 0, 0, OFFSET_0100, ZONE_PARIS)},
+        };
+    }
+
+    @DataProvider(name="plusTime")
+    Object[][] data_plusTime() {
+        return new Object[][] {
+            // normal
+            {dateTime(2008, 6, 30, 23, 30, 59, 0, OFFSET_0100, ZONE_0100), 0, dateTime(2008, 6, 30, 23, 30, 59, 0, OFFSET_0100, ZONE_0100)},
+            {dateTime(2008, 6, 30, 23, 30, 59, 0, OFFSET_0100, ZONE_0100), 1, dateTime(2008, 7, 1, 0, 30, 59, 0, OFFSET_0100, ZONE_0100)},
+            {dateTime(2008, 6, 30, 23, 30, 59, 0, OFFSET_0100, ZONE_0100), -1, dateTime(2008, 6, 30, 22, 30, 59, 0, OFFSET_0100, ZONE_0100)},
+            // gap
+            {dateTime(2008, 3, 30, 1, 30, 0, 0, OFFSET_0100, ZONE_PARIS), 1, dateTime(2008, 3, 30, 3, 30, 0, 0, OFFSET_0200, ZONE_PARIS)},
+            {dateTime(2008, 3, 30, 3, 30, 0, 0, OFFSET_0200, ZONE_PARIS), -1, dateTime(2008, 3, 30, 1, 30, 0, 0, OFFSET_0100, ZONE_PARIS)},
+            // overlap
+            {dateTime(2008, 10, 26, 1, 30, 0, 0, OFFSET_0200, ZONE_PARIS), 1, dateTime(2008, 10, 26, 2, 30, 0, 0, OFFSET_0200, ZONE_PARIS)},
+            {dateTime(2008, 10, 26, 1, 30, 0, 0, OFFSET_0200, ZONE_PARIS), 2, dateTime(2008, 10, 26, 2, 30, 0, 0, OFFSET_0100, ZONE_PARIS)},
+            {dateTime(2008, 10, 26, 1, 30, 0, 0, OFFSET_0200, ZONE_PARIS), 3, dateTime(2008, 10, 26, 3, 30, 0, 0, OFFSET_0100, ZONE_PARIS)},
+            {dateTime(2008, 10, 26, 2, 30, 0, 0, OFFSET_0200, ZONE_PARIS), 1, dateTime(2008, 10, 26, 2, 30, 0, 0, OFFSET_0100, ZONE_PARIS)},
+            {dateTime(2008, 10, 26, 2, 30, 0, 0, OFFSET_0200, ZONE_PARIS), 2, dateTime(2008, 10, 26, 3, 30, 0, 0, OFFSET_0100, ZONE_PARIS)},
+        };
+    }
+
+    //-----------------------------------------------------------------------
+    // plus(adjuster)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"}, dataProvider="plusDays")
+    public void test_plus_adjuster_Period_days(ZonedDateTime base, long amount, ZonedDateTime expected) {
+        assertEquals(base.plus(Period.of(amount, DAYS)), expected);
+    }
+
+    @Test(groups={"tck"}, dataProvider="plusTime")
+    public void test_plus_adjuster_Period_hours(ZonedDateTime base, long amount, ZonedDateTime expected) {
+        assertEquals(base.plus(Period.of(amount, HOURS)), expected);
+    }
+
+    @Test(groups={"tck"}, dataProvider="plusTime")
+    public void test_plus_adjuster_Duration_hours(ZonedDateTime base, long amount, ZonedDateTime expected) {
+        assertEquals(base.plus(Duration.ofHours(amount)), expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plus_adjuster() {
+        MockSimplePeriod period = MockSimplePeriod.of(7, ChronoUnit.MONTHS);
+        ZonedDateTime t = ZonedDateTime.of(LocalDateTime.of(2008, 6, 1, 12, 30, 59, 500), ZONE_0100);
+        ZonedDateTime expected = ZonedDateTime.of(LocalDateTime.of(2009, 1, 1, 12, 30, 59, 500), ZONE_0100);
+        assertEquals(t.plus(period), expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plus_adjuster_Duration() {
+        Duration duration = Duration.ofSeconds(4L * 60 * 60 + 5L * 60 + 6L);
+        ZonedDateTime t = ZonedDateTime.of(LocalDateTime.of(2008, 6, 1, 12, 30, 59, 500), ZONE_0100);
+        ZonedDateTime expected = ZonedDateTime.of(LocalDateTime.of(2008, 6, 1, 16, 36, 5, 500), ZONE_0100);
+        assertEquals(t.plus(duration), expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plus_adjuster_Period_zero() {
+        ZonedDateTime t = TEST_DATE_TIME.plus(MockSimplePeriod.ZERO_DAYS);
+        assertEquals(t, TEST_DATE_TIME);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plus_adjuster_Duration_zero() {
+        ZonedDateTime t = TEST_DATE_TIME.plus(Duration.ZERO);
+        assertEquals(t, TEST_DATE_TIME);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_plus_adjuster_null() {
+        TEST_DATE_TIME.plus((TemporalAdder) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // plus(long,TemporalUnit)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"}, dataProvider="plusDays")
+    public void test_plus_longUnit_days(ZonedDateTime base, long amount, ZonedDateTime expected) {
+        assertEquals(base.plus(amount, DAYS), expected);
+    }
+
+    @Test(groups={"tck"}, dataProvider="plusTime")
+    public void test_plus_longUnit_hours(ZonedDateTime base, long amount, ZonedDateTime expected) {
+        assertEquals(base.plus(amount, HOURS), expected);
+    }
+
+    @Test(groups={"tck"}, dataProvider="plusTime")
+    public void test_plus_longUnit_minutes(ZonedDateTime base, long amount, ZonedDateTime expected) {
+        assertEquals(base.plus(amount * 60, MINUTES), expected);
+    }
+
+    @Test(groups={"tck"}, dataProvider="plusTime")
+    public void test_plus_longUnit_seconds(ZonedDateTime base, long amount, ZonedDateTime expected) {
+        assertEquals(base.plus(amount * 3600, SECONDS), expected);
+    }
+
+    @Test(groups={"tck"}, dataProvider="plusTime")
+    public void test_plus_longUnit_nanos(ZonedDateTime base, long amount, ZonedDateTime expected) {
+        assertEquals(base.plus(amount * 3600_000_000_000L, NANOS), expected);
+    }
+
+    @Test(groups={"tck"}, expectedExceptions=NullPointerException.class)
+    public void test_plus_longUnit_null() {
+        TEST_DATE_TIME_PARIS.plus(0, null);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusYears()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusYears() {
+        LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0);
+        ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100);
+        ZonedDateTime test = base.plusYears(1);
+        assertEquals(test, ZonedDateTime.of(ldt.plusYears(1), ZONE_0100));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusYears_zero() {
+        LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0);
+        ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100);
+        ZonedDateTime test = base.plusYears(0);
+        assertEquals(test, base);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusMonths()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusMonths() {
+        LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0);
+        ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100);
+        ZonedDateTime test = base.plusMonths(1);
+        assertEquals(test, ZonedDateTime.of(ldt.plusMonths(1), ZONE_0100));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMonths_zero() {
+        LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0);
+        ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100);
+        ZonedDateTime test = base.plusMonths(0);
+        assertEquals(test, base);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusWeeks()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusWeeks() {
+        LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0);
+        ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100);
+        ZonedDateTime test = base.plusWeeks(1);
+        assertEquals(test, ZonedDateTime.of(ldt.plusWeeks(1), ZONE_0100));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusWeeks_zero() {
+        LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0);
+        ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100);
+        ZonedDateTime test = base.plusWeeks(0);
+        assertEquals(test, base);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusDays()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"}, dataProvider="plusDays")
+    public void test_plusDays(ZonedDateTime base, long amount, ZonedDateTime expected) {
+        assertEquals(base.plusDays(amount), expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusHours()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"}, dataProvider="plusTime")
+    public void test_plusHours(ZonedDateTime base, long amount, ZonedDateTime expected) {
+        assertEquals(base.plusHours(amount), expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusMinutes()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"}, dataProvider="plusTime")
+    public void test_plusMinutes(ZonedDateTime base, long amount, ZonedDateTime expected) {
+        assertEquals(base.plusMinutes(amount * 60), expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMinutes_minutes() {
+        LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0);
+        ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100);
+        ZonedDateTime test = base.plusMinutes(30);
+        assertEquals(test, ZonedDateTime.of(ldt.plusMinutes(30), ZONE_0100));
+    }
+
+    //-----------------------------------------------------------------------
+    // plusSeconds()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"}, dataProvider="plusTime")
+    public void test_plusSeconds(ZonedDateTime base, long amount, ZonedDateTime expected) {
+        assertEquals(base.plusSeconds(amount * 3600), expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusSeconds_seconds() {
+        LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0);
+        ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100);
+        ZonedDateTime test = base.plusSeconds(1);
+        assertEquals(test, ZonedDateTime.of(ldt.plusSeconds(1), ZONE_0100));
+    }
+
+    //-----------------------------------------------------------------------
+    // plusNanos()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"}, dataProvider="plusTime")
+    public void test_plusNanos(ZonedDateTime base, long amount, ZonedDateTime expected) {
+        assertEquals(base.plusNanos(amount * 3600_000_000_000L), expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusNanos_nanos() {
+        LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0);
+        ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100);
+        ZonedDateTime test = base.plusNanos(1);
+        assertEquals(test, ZonedDateTime.of(ldt.plusNanos(1), ZONE_0100));
+    }
+
+    //-----------------------------------------------------------------------
+    // minus(adjuster)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"}, dataProvider="plusDays")
+    public void test_minus_adjuster_Period_days(ZonedDateTime base, long amount, ZonedDateTime expected) {
+        assertEquals(base.minus(Period.of(-amount, DAYS)), expected);
+    }
+
+    @Test(groups={"tck"}, dataProvider="plusTime")
+    public void test_minus_adjuster_Period_hours(ZonedDateTime base, long amount, ZonedDateTime expected) {
+        assertEquals(base.minus(Period.of(-amount, HOURS)), expected);
+    }
+
+    @Test(groups={"tck"}, dataProvider="plusTime")
+    public void test_minus_adjuster_Duration_hours(ZonedDateTime base, long amount, ZonedDateTime expected) {
+        assertEquals(base.minus(Duration.ofHours(-amount)), expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minus_adjuster() {
+        MockSimplePeriod period = MockSimplePeriod.of(7, ChronoUnit.MONTHS);
+        ZonedDateTime t = ZonedDateTime.of(LocalDateTime.of(2008, 6, 1, 12, 30, 59, 500), ZONE_0100);
+        ZonedDateTime expected = ZonedDateTime.of(LocalDateTime.of(2007, 11, 1, 12, 30, 59, 500), ZONE_0100);
+        assertEquals(t.minus(period), expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minus_adjuster_Duration() {
+        Duration duration = Duration.ofSeconds(4L * 60 * 60 + 5L * 60 + 6L);
+        ZonedDateTime t = ZonedDateTime.of(LocalDateTime.of(2008, 6, 1, 12, 30, 59, 500), ZONE_0100);
+        ZonedDateTime expected = ZonedDateTime.of(LocalDateTime.of(2008, 6, 1, 8, 25, 53, 500), ZONE_0100);
+        assertEquals(t.minus(duration), expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minus_adjuster_Period_zero() {
+        ZonedDateTime t = TEST_DATE_TIME.minus(MockSimplePeriod.ZERO_DAYS);
+        assertEquals(t, TEST_DATE_TIME);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minus_adjuster_Duration_zero() {
+        ZonedDateTime t = TEST_DATE_TIME.minus(Duration.ZERO);
+        assertEquals(t, TEST_DATE_TIME);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_minus_adjuster_null() {
+        TEST_DATE_TIME.minus((TemporalSubtractor) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusYears()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusYears() {
+        LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0);
+        ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100);
+        ZonedDateTime test = base.minusYears(1);
+        assertEquals(test, ZonedDateTime.of(ldt.minusYears(1), ZONE_0100));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusYears_zero() {
+        LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0);
+        ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100);
+        ZonedDateTime test = base.minusYears(0);
+        assertEquals(test, base);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusMonths()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusMonths() {
+        LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0);
+        ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100);
+        ZonedDateTime test = base.minusMonths(1);
+        assertEquals(test, ZonedDateTime.of(ldt.minusMonths(1), ZONE_0100));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMonths_zero() {
+        LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0);
+        ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100);
+        ZonedDateTime test = base.minusMonths(0);
+        assertEquals(test, base);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusWeeks()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusWeeks() {
+        LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0);
+        ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100);
+        ZonedDateTime test = base.minusWeeks(1);
+        assertEquals(test, ZonedDateTime.of(ldt.minusWeeks(1), ZONE_0100));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusWeeks_zero() {
+        LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0);
+        ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100);
+        ZonedDateTime test = base.minusWeeks(0);
+        assertEquals(test, base);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusDays()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"}, dataProvider="plusDays")
+    public void test_minusDays(ZonedDateTime base, long amount, ZonedDateTime expected) {
+        assertEquals(base.minusDays(-amount), expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusHours()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"}, dataProvider="plusTime")
+    public void test_minusHours(ZonedDateTime base, long amount, ZonedDateTime expected) {
+        assertEquals(base.minusHours(-amount), expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusMinutes()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"}, dataProvider="plusTime")
+    public void test_minusMinutes(ZonedDateTime base, long amount, ZonedDateTime expected) {
+        assertEquals(base.minusMinutes(-amount * 60), expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMinutes_minutes() {
+        LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0);
+        ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100);
+        ZonedDateTime test = base.minusMinutes(30);
+        assertEquals(test, ZonedDateTime.of(ldt.minusMinutes(30), ZONE_0100));
+    }
+
+    //-----------------------------------------------------------------------
+    // minusSeconds()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"}, dataProvider="plusTime")
+    public void test_minusSeconds(ZonedDateTime base, long amount, ZonedDateTime expected) {
+        assertEquals(base.minusSeconds(-amount * 3600), expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusSeconds_seconds() {
+        LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0);
+        ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100);
+        ZonedDateTime test = base.minusSeconds(1);
+        assertEquals(test, ZonedDateTime.of(ldt.minusSeconds(1), ZONE_0100));
+    }
+
+    //-----------------------------------------------------------------------
+    // minusNanos()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"}, dataProvider="plusTime")
+    public void test_minusNanos(ZonedDateTime base, long amount, ZonedDateTime expected) {
+        assertEquals(base.minusNanos(-amount * 3600_000_000_000L), expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusNanos_nanos() {
+        LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0);
+        ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100);
+        ZonedDateTime test = base.minusNanos(1);
+        assertEquals(test, ZonedDateTime.of(ldt.minusNanos(1), ZONE_0100));
+    }
+
+    //-----------------------------------------------------------------------
+    // periodUntil(Temporal,TemporalUnit)
+    //-----------------------------------------------------------------------
+    // TODO: more tests for period between two different zones
+    // compare results to OffsetDateTime.periodUntil, especially wrt dates
+
+    @Test(groups={"tck"}, dataProvider="plusDays")
+    public void test_periodUntil_days(ZonedDateTime base, long expected, ZonedDateTime end) {
+        assertEquals(base.periodUntil(end, DAYS), expected);
+    }
+
+    @Test(groups={"tck"}, dataProvider="plusTime")
+    public void test_periodUntil_hours(ZonedDateTime base, long expected, ZonedDateTime end) {
+        assertEquals(base.periodUntil(end, HOURS), expected);
+    }
+
+    @Test(groups={"tck"}, dataProvider="plusTime")
+    public void test_periodUntil_minutes(ZonedDateTime base, long expected, ZonedDateTime end) {
+        assertEquals(base.periodUntil(end, MINUTES), expected * 60);
+    }
+
+    @Test(groups={"tck"}, dataProvider="plusTime")
+    public void test_periodUntil_seconds(ZonedDateTime base, long expected, ZonedDateTime end) {
+        assertEquals(base.periodUntil(end, SECONDS), expected * 3600);
+    }
+
+    @Test(groups={"tck"}, dataProvider="plusTime")
+    public void test_periodUntil_nanos(ZonedDateTime base, long expected, ZonedDateTime end) {
+        assertEquals(base.periodUntil(end, NANOS), expected * 3600_000_000_000L);
+    }
+
+    @Test(groups={"tck"})
+    public void test_periodUntil_parisLondon() {
+        ZonedDateTime midnightLondon = LocalDate.of(2012, 6, 28).atStartOfDay(ZONE_LONDON);
+        ZonedDateTime midnightParis1 = LocalDate.of(2012, 6, 29).atStartOfDay(ZONE_PARIS);
+        ZonedDateTime oneAm1 = LocalDateTime.of(2012, 6, 29, 1, 0).atZone(ZONE_PARIS);
+        ZonedDateTime midnightParis2 = LocalDate.of(2012, 6, 30).atStartOfDay(ZONE_PARIS);
+
+        assertEquals(midnightLondon.periodUntil(midnightParis1, HOURS), 23);
+        assertEquals(midnightLondon.periodUntil(oneAm1, HOURS), 24);
+        assertEquals(midnightLondon.periodUntil(midnightParis2, HOURS), 23 + 24);
+
+        assertEquals(midnightLondon.periodUntil(midnightParis1, DAYS), 0);
+        assertEquals(midnightLondon.periodUntil(oneAm1, DAYS), 1);
+        assertEquals(midnightLondon.periodUntil(midnightParis2, DAYS), 1);
+    }
+
+    @Test(groups={"tck"})
+    public void test_periodUntil_gap() {
+        ZonedDateTime before = TEST_PARIS_GAP_2008_03_30_02_30.withHour(0).withMinute(0).atZone(ZONE_PARIS);
+        ZonedDateTime after = TEST_PARIS_GAP_2008_03_30_02_30.withHour(0).withMinute(0).plusDays(1).atZone(ZONE_PARIS);
+
+        assertEquals(before.periodUntil(after, HOURS), 23);
+        assertEquals(before.periodUntil(after, DAYS), 1);
+    }
+
+    @Test(groups={"tck"})
+    public void test_periodUntil_overlap() {
+        ZonedDateTime before = TEST_PARIS_OVERLAP_2008_10_26_02_30.withHour(0).withMinute(0).atZone(ZONE_PARIS);
+        ZonedDateTime after = TEST_PARIS_OVERLAP_2008_10_26_02_30.withHour(0).withMinute(0).plusDays(1).atZone(ZONE_PARIS);
+
+        assertEquals(before.periodUntil(after, HOURS), 25);
+        assertEquals(before.periodUntil(after, DAYS), 1);
+    }
+
+    @Test(groups={"tck"}, expectedExceptions=DateTimeException.class)
+    public void test_periodUntil_differentType() {
+        TEST_DATE_TIME_PARIS.periodUntil(TEST_LOCAL_2008_06_30_11_30_59_500, DAYS);
+    }
+
+    @Test(groups={"tck"}, expectedExceptions=NullPointerException.class)
+    public void test_periodUntil_nullTemporal() {
+        TEST_DATE_TIME_PARIS.periodUntil(null, DAYS);
+    }
+
+    @Test(groups={"tck"}, expectedExceptions=NullPointerException.class)
+    public void test_periodUntil_nullUnit() {
+        TEST_DATE_TIME_PARIS.periodUntil(TEST_DATE_TIME_PARIS, null);
+    }
+
+    //-----------------------------------------------------------------------
+    // toOffsetDateTime()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_toOffsetDateTime() {
+        assertEquals(TEST_DATE_TIME.toOffsetDateTime(), OffsetDateTime.of(TEST_DATE_TIME.getDateTime(), TEST_DATE_TIME.getOffset()));
+    }
+
+    //-----------------------------------------------------------------------
+    // toInstant()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="toInstant")
+    Object[][] data_toInstant() {
+        return new Object[][] {
+            {LocalDateTime.of(1970, 1, 1, 0, 0, 0, 0), 0L, 0},
+            {LocalDateTime.of(1970, 1, 1, 0, 0, 0, 1), 0L, 1},
+            {LocalDateTime.of(1970, 1, 1, 0, 0, 0, 999_999_999), 0L, 999_999_999},
+            {LocalDateTime.of(1970, 1, 1, 0, 0, 1, 0), 1L, 0},
+            {LocalDateTime.of(1970, 1, 1, 0, 0, 1, 1), 1L, 1},
+            {LocalDateTime.of(1969, 12, 31, 23, 59, 59, 999999999), -1L, 999_999_999},
+            {LocalDateTime.of(1970, 1, 2, 0, 0), 24L * 60L * 60L, 0},
+            {LocalDateTime.of(1969, 12, 31, 0, 0), -24L * 60L * 60L, 0},
+        };
+    }
+
+    @Test(groups={"tck"}, dataProvider="toInstant")
+    public void test_toInstant_UTC(LocalDateTime ldt, long expectedEpSec, int expectedNos) {
+        ZonedDateTime dt = ldt.atZone(ZoneOffset.UTC);
+        Instant test = dt.toInstant();
+        assertEquals(test.getEpochSecond(), expectedEpSec);
+        assertEquals(test.getNano(), expectedNos);
+    }
+
+    @Test(groups={"tck"}, dataProvider="toInstant")
+    public void test_toInstant_P0100(LocalDateTime ldt, long expectedEpSec, int expectedNos) {
+        ZonedDateTime dt = ldt.atZone(ZONE_0100);
+        Instant test = dt.toInstant();
+        assertEquals(test.getEpochSecond(), expectedEpSec - 3600);
+        assertEquals(test.getNano(), expectedNos);
+    }
+
+    @Test(groups={"tck"}, dataProvider="toInstant")
+    public void test_toInstant_M0100(LocalDateTime ldt, long expectedEpSec, int expectedNos) {
+        ZonedDateTime dt = ldt.atZone(ZONE_M0100);
+        Instant test = dt.toInstant();
+        assertEquals(test.getEpochSecond(), expectedEpSec + 3600);
+        assertEquals(test.getNano(), expectedNos);
+    }
+
+    //-----------------------------------------------------------------------
+    // toEpochSecond()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_toEpochSecond_afterEpoch() {
+        LocalDateTime ldt = LocalDateTime.of(1970, 1, 1, 0, 0).plusHours(1);
+        for (int i = 0; i < 100000; i++) {
+            ZonedDateTime a = ZonedDateTime.of(ldt, ZONE_PARIS);
+            assertEquals(a.toEpochSecond(), i);
+            ldt = ldt.plusSeconds(1);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_toEpochSecond_beforeEpoch() {
+        LocalDateTime ldt = LocalDateTime.of(1970, 1, 1, 0, 0).plusHours(1);
+        for (int i = 0; i < 100000; i++) {
+            ZonedDateTime a = ZonedDateTime.of(ldt, ZONE_PARIS);
+            assertEquals(a.toEpochSecond(), -i);
+            ldt = ldt.minusSeconds(1);
+        }
+    }
+
+    @Test(groups={"tck"}, dataProvider="toInstant")
+    public void test_toEpochSecond_UTC(LocalDateTime ldt, long expectedEpSec, int expectedNos) {
+        ZonedDateTime dt = ldt.atZone(ZoneOffset.UTC);
+        assertEquals(dt.toEpochSecond(), expectedEpSec);
+    }
+
+    @Test(groups={"tck"}, dataProvider="toInstant")
+    public void test_toEpochSecond_P0100(LocalDateTime ldt, long expectedEpSec, int expectedNos) {
+        ZonedDateTime dt = ldt.atZone(ZONE_0100);
+        assertEquals(dt.toEpochSecond(), expectedEpSec - 3600);
+    }
+
+    @Test(groups={"tck"}, dataProvider="toInstant")
+    public void test_toEpochSecond_M0100(LocalDateTime ldt, long expectedEpSec, int expectedNos) {
+        ZonedDateTime dt = ldt.atZone(ZONE_M0100);
+        assertEquals(dt.toEpochSecond(), expectedEpSec + 3600);
+    }
+
+    //-----------------------------------------------------------------------
+    // compareTo()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_compareTo_time1() {
+        ZonedDateTime a = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 30, 39), ZONE_0100);
+        ZonedDateTime b = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 30, 41), ZONE_0100);  // a is before b due to time
+        assertEquals(a.compareTo(b) < 0, true);
+        assertEquals(b.compareTo(a) > 0, true);
+        assertEquals(a.compareTo(a) == 0, true);
+        assertEquals(b.compareTo(b) == 0, true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_compareTo_time2() {
+        ZonedDateTime a = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 30, 40, 4), ZONE_0100);
+        ZonedDateTime b = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 30, 40, 5), ZONE_0100);  // a is before b due to time
+        assertEquals(a.compareTo(b) < 0, true);
+        assertEquals(b.compareTo(a) > 0, true);
+        assertEquals(a.compareTo(a) == 0, true);
+        assertEquals(b.compareTo(b) == 0, true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_compareTo_offset1() {
+        ZonedDateTime a = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 30, 41), ZONE_0200);
+        ZonedDateTime b = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 30, 39), ZONE_0100);  // a is before b due to offset
+        assertEquals(a.compareTo(b) < 0, true);
+        assertEquals(b.compareTo(a) > 0, true);
+        assertEquals(a.compareTo(a) == 0, true);
+        assertEquals(b.compareTo(b) == 0, true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_compareTo_offset2() {
+        ZonedDateTime a = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 30, 40, 5), ZoneId.of("UTC+01:01"));
+        ZonedDateTime b = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 30, 40, 4), ZONE_0100);  // a is before b due to offset
+        assertEquals(a.compareTo(b) < 0, true);
+        assertEquals(b.compareTo(a) > 0, true);
+        assertEquals(a.compareTo(a) == 0, true);
+        assertEquals(b.compareTo(b) == 0, true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_compareTo_both() {
+        ZonedDateTime a = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 50), ZONE_0200);
+        ZonedDateTime b = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 20), ZONE_0100);  // a is before b on instant scale
+        assertEquals(a.compareTo(b) < 0, true);
+        assertEquals(b.compareTo(a) > 0, true);
+        assertEquals(a.compareTo(a) == 0, true);
+        assertEquals(b.compareTo(b) == 0, true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_compareTo_bothNanos() {
+        ZonedDateTime a = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 20, 40, 5), ZONE_0200);
+        ZonedDateTime b = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 10, 20, 40, 6), ZONE_0100);  // a is before b on instant scale
+        assertEquals(a.compareTo(b) < 0, true);
+        assertEquals(b.compareTo(a) > 0, true);
+        assertEquals(a.compareTo(a) == 0, true);
+        assertEquals(b.compareTo(b) == 0, true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_compareTo_hourDifference() {
+        ZonedDateTime a = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 10, 0), ZONE_0100);
+        ZonedDateTime b = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 0), ZONE_0200);  // a is before b despite being same time-line time
+        assertEquals(a.compareTo(b) < 0, true);
+        assertEquals(b.compareTo(a) > 0, true);
+        assertEquals(a.compareTo(a) == 0, true);
+        assertEquals(b.compareTo(b) == 0, true);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_compareTo_null() {
+        LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0);
+        ZonedDateTime a = ZonedDateTime.of(ldt, ZONE_0100);
+        a.compareTo(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // isBefore()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="IsBefore")
+    Object[][] data_isBefore() {
+        return new Object[][] {
+            {11, 30, ZONE_0100, 11, 31, ZONE_0100, true}, // a is before b due to time
+            {11, 30, ZONE_0200, 11, 30, ZONE_0100, true}, // a is before b due to offset
+            {11, 30, ZONE_0200, 10, 30, ZONE_0100, false}, // a is equal b due to same instant
+        };
+    }
+
+    @Test(dataProvider="IsBefore", groups={"tck"})
+    public void test_isBefore(int hour1, int minute1, ZoneId zone1, int hour2, int minute2, ZoneId zone2, boolean expected) {
+        ZonedDateTime a = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, hour1, minute1), zone1);
+        ZonedDateTime b = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, hour2, minute2), zone2);
+        assertEquals(a.isBefore(b), expected);
+        assertEquals(b.isBefore(a), false);
+        assertEquals(a.isBefore(a), false);
+        assertEquals(b.isBefore(b), false);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_isBefore_null() {
+        LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0);
+        ZonedDateTime a = ZonedDateTime.of(ldt, ZONE_0100);
+        a.isBefore(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // isAfter()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="IsAfter")
+    Object[][] data_isAfter() {
+        return new Object[][] {
+            {11, 31, ZONE_0100, 11, 30, ZONE_0100, true}, // a is after b due to time
+            {11, 30, ZONE_0100, 11, 30, ZONE_0200, true}, // a is after b due to offset
+            {11, 30, ZONE_0200, 10, 30, ZONE_0100, false}, // a is equal b due to same instant
+        };
+    }
+
+    @Test(dataProvider="IsAfter", groups={"tck"})
+    public void test_isAfter(int hour1, int minute1, ZoneId zone1, int hour2, int minute2, ZoneId zone2, boolean expected) {
+        ZonedDateTime a = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, hour1, minute1), zone1);
+        ZonedDateTime b = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, hour2, minute2), zone2);
+        assertEquals(a.isAfter(b), expected);
+        assertEquals(b.isAfter(a), false);
+        assertEquals(a.isAfter(a), false);
+        assertEquals(b.isAfter(b), false);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_isAfter_null() {
+        LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0);
+        ZonedDateTime a = ZonedDateTime.of(ldt, ZONE_0100);
+        a.isAfter(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // equals() / hashCode()
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_equals_true(int y, int o, int d, int h, int m, int s, int n, ZoneId ignored) {
+        ZonedDateTime a = ZonedDateTime.of(dateTime(y, o, d, h, m, s, n), ZONE_0100);
+        ZonedDateTime b = ZonedDateTime.of(dateTime(y, o, d, h, m, s, n), ZONE_0100);
+        assertEquals(a.equals(b), true);
+        assertEquals(a.hashCode() == b.hashCode(), true);
+    }
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_equals_false_year_differs(int y, int o, int d, int h, int m, int s, int n, ZoneId ignored) {
+        ZonedDateTime a = ZonedDateTime.of(dateTime(y, o, d, h, m, s, n), ZONE_0100);
+        ZonedDateTime b = ZonedDateTime.of(dateTime(y + 1, o, d, h, m, s, n), ZONE_0100);
+        assertEquals(a.equals(b), false);
+    }
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_equals_false_hour_differs(int y, int o, int d, int h, int m, int s, int n, ZoneId ignored) {
+        h = (h == 23 ? 22 : h);
+        ZonedDateTime a = ZonedDateTime.of(dateTime(y, o, d, h, m, s, n), ZONE_0100);
+        ZonedDateTime b = ZonedDateTime.of(dateTime(y, o, d, h + 1, m, s, n), ZONE_0100);
+        assertEquals(a.equals(b), false);
+    }
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_equals_false_minute_differs(int y, int o, int d, int h, int m, int s, int n, ZoneId ignored) {
+        m = (m == 59 ? 58 : m);
+        ZonedDateTime a = ZonedDateTime.of(dateTime(y, o, d, h, m, s, n), ZONE_0100);
+        ZonedDateTime b = ZonedDateTime.of(dateTime(y, o, d, h, m + 1, s, n), ZONE_0100);
+        assertEquals(a.equals(b), false);
+    }
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_equals_false_second_differs(int y, int o, int d, int h, int m, int s, int n, ZoneId ignored) {
+        s = (s == 59 ? 58 : s);
+        ZonedDateTime a = ZonedDateTime.of(dateTime(y, o, d, h, m, s, n), ZONE_0100);
+        ZonedDateTime b = ZonedDateTime.of(dateTime(y, o, d, h, m, s + 1, n), ZONE_0100);
+        assertEquals(a.equals(b), false);
+    }
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_equals_false_nano_differs(int y, int o, int d, int h, int m, int s, int n, ZoneId ignored) {
+        n = (n == 999999999 ? 999999998 : n);
+        ZonedDateTime a = ZonedDateTime.of(dateTime(y, o, d, h, m, s, n), ZONE_0100);
+        ZonedDateTime b = ZonedDateTime.of(dateTime(y, o, d, h, m, s, n + 1), ZONE_0100);
+        assertEquals(a.equals(b), false);
+    }
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_equals_false_offset_differs(int y, int o, int d, int h, int m, int s, int n, ZoneId ignored) {
+        ZonedDateTime a = ZonedDateTime.of(dateTime(y, o, d, h, m, s, n), ZONE_0100);
+        ZonedDateTime b = ZonedDateTime.of(dateTime(y, o, d, h, m, s, n), ZONE_0200);
+        assertEquals(a.equals(b), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_itself_true() {
+        assertEquals(TEST_DATE_TIME.equals(TEST_DATE_TIME), true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_string_false() {
+        assertEquals(TEST_DATE_TIME.equals("2007-07-15"), false);
+    }
+
+    //-----------------------------------------------------------------------
+    // toString()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sampleToString")
+    Object[][] provider_sampleToString() {
+        return new Object[][] {
+            {2008, 6, 30, 11, 30, 59, 0, "Z", "2008-06-30T11:30:59Z"},
+            {2008, 6, 30, 11, 30, 59, 0, "+01:00", "2008-06-30T11:30:59+01:00"},
+            {2008, 6, 30, 11, 30, 59, 999000000, "Z", "2008-06-30T11:30:59.999Z"},
+            {2008, 6, 30, 11, 30, 59, 999000000, "+01:00", "2008-06-30T11:30:59.999+01:00"},
+            {2008, 6, 30, 11, 30, 59, 999000, "Z", "2008-06-30T11:30:59.000999Z"},
+            {2008, 6, 30, 11, 30, 59, 999000, "+01:00", "2008-06-30T11:30:59.000999+01:00"},
+            {2008, 6, 30, 11, 30, 59, 999, "Z", "2008-06-30T11:30:59.000000999Z"},
+            {2008, 6, 30, 11, 30, 59, 999, "+01:00", "2008-06-30T11:30:59.000000999+01:00"},
+
+            {2008, 6, 30, 11, 30, 59, 999, "Europe/London", "2008-06-30T11:30:59.000000999+01:00[Europe/London]"},
+            {2008, 6, 30, 11, 30, 59, 999, "Europe/Paris", "2008-06-30T11:30:59.000000999+02:00[Europe/Paris]"},
+        };
+    }
+
+    @Test(dataProvider="sampleToString", groups={"tck"})
+    public void test_toString(int y, int o, int d, int h, int m, int s, int n, String zoneId, String expected) {
+        ZonedDateTime t = ZonedDateTime.of(dateTime(y, o, d, h, m, s, n), ZoneId.of(zoneId));
+        String str = t.toString();
+        assertEquals(str, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // toString(DateTimeFormatter)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_toString_formatter() {
+        DateTimeFormatter f = DateTimeFormatters.pattern("y M d H m s");
+        String t = ZonedDateTime.of(dateTime(2010, 12, 3, 11, 30), ZONE_PARIS).toString(f);
+        assertEquals(t, "2010 12 3 11 30 0");
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_toString_formatter_null() {
+        ZonedDateTime.of(dateTime(2010, 12, 3, 11, 30), ZONE_PARIS).toString(null);
+    }
+
+    //-------------------------------------------------------------------------
+    private static LocalDateTime dateTime(
+            int year, int month, int dayOfMonth,
+            int hour, int minute) {
+        return LocalDateTime.of(year, month, dayOfMonth, hour, minute);
+    }
+
+    private static LocalDateTime dateTime(
+                    int year, int month, int dayOfMonth,
+                    int hour, int minute, int second, int nanoOfSecond) {
+                return LocalDateTime.of(year, month, dayOfMonth, hour, minute, second, nanoOfSecond);
+            }
+
+    private static ZonedDateTime dateTime(
+            int year, int month, int dayOfMonth,
+            int hour, int minute, int second, int nanoOfSecond, ZoneOffset offset, ZoneId zoneId) {
+        return ZonedDateTime.ofStrict(LocalDateTime.of(year, month, dayOfMonth, hour, minute, second, nanoOfSecond), offset, zoneId);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/calendar/CopticChrono.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,251 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package tck.java.time.calendar;
+
+import static java.time.temporal.ChronoField.EPOCH_DAY;
+
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+
+import java.time.DateTimeException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.ValueRange;
+import java.time.temporal.Chrono;
+import java.time.temporal.ChronoLocalDate;
+import java.time.temporal.Era;
+
+/**
+ * The Coptic calendar system.
+ * <p>
+ * This chronology defines the rules of the Coptic calendar system.
+ * This calendar system is primarily used in Christian Egypt.
+ * Dates are aligned such that {@code 0001AM-01-01 (Coptic)} is {@code 0284-08-29 (ISO)}.
+ * <p>
+ * The fields are defined as follows:
+ * <p><ul>
+ * <li>era - There are two eras, the current 'Era of the Martyrs' (AM) and the previous era (ERA_ERA_BEFORE_AM).
+ * <li>year-of-era - The year-of-era for the current era increases uniformly from the epoch at year one.
+ *  For the previous era the year increases from one as time goes backwards.
+ * <li>proleptic-year - The proleptic year is the same as the year-of-era for the
+ *  current era. For the previous era, years have zero, then negative values.
+ * <li>month-of-year - There are 13 months in a Coptic year, numbered from 1 to 13.
+ * <li>day-of-month - There are 30 days in each of the first 12 Coptic months, numbered 1 to 30.
+ *  The 13th month has 5 days, or 6 in a leap year, numbered 1 to 5 or 1 to 6.
+ * <li>day-of-year - There are 365 days in a standard Coptic year and 366 in a leap year.
+ *  The days are numbered from 1 to 365 or 1 to 366.
+ * <li>leap-year - Leap years occur every 4 years.
+ * </ul><p>
+ *
+ * <h4>Implementation notes</h4>
+ * This class is immutable and thread-safe.
+ */
+public final class CopticChrono extends Chrono<CopticChrono> implements Serializable {
+
+    /**
+     * Singleton instance of the Coptic chronology.
+     */
+    public static final CopticChrono INSTANCE = new CopticChrono();
+    /**
+     * The singleton instance for the era BEFORE_AM.
+     * This has the numeric value of {@code 0}.
+     */
+    public static final Era<CopticChrono> ERA_BEFORE_AM = CopticEra.BEFORE_AM;
+    /**
+     * The singleton instance for the era AM - 'Era of the Martyrs'.
+     * This has the numeric value of {@code 1}.
+     */
+    public static final Era<CopticChrono> ERA_AM = CopticEra.AM;
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 7291205177830286973L;
+    /**
+     * Range of months.
+     */
+    static final ValueRange MOY_RANGE = ValueRange.of(1, 13);
+    /**
+     * Range of days.
+     */
+    static final ValueRange DOM_RANGE = ValueRange.of(1, 5, 30);
+    /**
+     * Range of days.
+     */
+    static final ValueRange DOM_RANGE_NONLEAP = ValueRange.of(1, 5);
+    /**
+     * Range of days.
+     */
+    static final ValueRange DOM_RANGE_LEAP = ValueRange.of(1, 6);
+
+    /**
+     * Public Constructor to be instantiated by the ServiceLoader
+     */
+    public CopticChrono() {
+    }
+
+    /**
+     * Resolve singleton.
+     *
+     * @return the singleton instance, not null
+     */
+    private Object readResolve() {
+        return INSTANCE;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the ID of the chronology - 'Coptic'.
+     * <p>
+     * The ID uniquely identifies the {@code Chrono}.
+     * It can be used to lookup the {@code Chrono} using {@link #of(String)}.
+     *
+     * @return the chronology ID - 'Coptic'
+     * @see #getCalendarType()
+     */
+    @Override
+    public String getId() {
+        return "Coptic";
+    }
+
+    /**
+     * Gets the calendar type of the underlying calendar system - 'coptic'.
+     * <p>
+     * The calendar type is an identifier defined by the
+     * <em>Unicode Locale Data Markup Language (LDML)</em> specification.
+     * It can be used to lookup the {@code Chrono} using {@link #of(String)}.
+     * It can also be used as part of a locale, accessible via
+     * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
+     *
+     * @return the calendar system type - 'coptic'
+     * @see #getId()
+     */
+    @Override
+    public String getCalendarType() {
+        return "coptic";
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ChronoLocalDate<CopticChrono> date(int prolepticYear, int month, int dayOfMonth) {
+        return new CopticDate(prolepticYear, month, dayOfMonth);
+    }
+
+    @Override
+    public ChronoLocalDate<CopticChrono> dateYearDay(int prolepticYear, int dayOfYear) {
+        return new CopticDate(prolepticYear, (dayOfYear - 1) / 30 + 1, (dayOfYear - 1) % 30 + 1);
+    }
+
+    @Override
+    public ChronoLocalDate<CopticChrono> date(TemporalAccessor dateTime) {
+        if (dateTime instanceof CopticDate) {
+            return (CopticDate) dateTime;
+        }
+        return CopticDate.ofEpochDay(dateTime.getLong(EPOCH_DAY));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified year is a leap year.
+     * <p>
+     * A Coptic proleptic-year is leap if the remainder after division by four equals three.
+     * This method does not validate the year passed in, and only has a
+     * well-defined result for years in the supported range.
+     *
+     * @param prolepticYear  the proleptic-year to check, not validated for range
+     * @return true if the year is a leap year
+     */
+    @Override
+    public boolean isLeapYear(long prolepticYear) {
+        return Math.floorMod(prolepticYear, 4) == 3;
+    }
+
+    @Override
+    public int prolepticYear(Era<CopticChrono> era, int yearOfEra) {
+        if (era instanceof CopticEra == false) {
+            throw new DateTimeException("Era must be CopticEra");
+        }
+        return (era == CopticEra.AM ? yearOfEra : 1 - yearOfEra);
+    }
+
+    @Override
+    public Era<CopticChrono> eraOf(int eraValue) {
+        return CopticEra.of(eraValue);
+    }
+
+    @Override
+    public List<Era<CopticChrono>> eras() {
+        return Arrays.<Era<CopticChrono>>asList(CopticEra.values());
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ValueRange range(ChronoField field) {
+        switch (field) {
+            case DAY_OF_MONTH: return ValueRange.of(1, 5, 30);
+            case ALIGNED_WEEK_OF_MONTH: return ValueRange.of(1, 1, 5);
+            case MONTH_OF_YEAR: return ValueRange.of(1, 13);
+            case EPOCH_MONTH: return ValueRange.of(-1000, 1000);  // TODO
+            case YEAR_OF_ERA: return ValueRange.of(1, 999, 1000);  // TODO
+            case YEAR: return ValueRange.of(-1000, 1000);  // TODO
+        }
+        return field.range();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/calendar/CopticDate.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,340 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.calendar;
+
+import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH;
+import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR;
+import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH;
+import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR;
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.YEAR_OF_ERA;
+
+import java.io.Serializable;
+
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoLocalDate;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Era;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalAdder;
+import java.time.temporal.TemporalSubtractor;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.ValueRange;
+import java.time.temporal.Year;
+
+/**
+ * A date in the Coptic calendar system.
+ * <p>
+ * This implements {@code ChronoLocalDate} for the {@link CopticChrono Coptic calendar}.
+ *
+ * <h4>Implementation notes</h4>
+ * This class is immutable and thread-safe.
+ */
+final class CopticDate
+        implements ChronoLocalDate<CopticChrono>, Serializable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -7920528871688876868L;
+    /**
+     * The difference between the Coptic and Coptic epoch day count.
+     */
+    private static final int EPOCH_DAY_DIFFERENCE = 574971 + 40587;
+
+    /**
+     * The proleptic year.
+     */
+    private final int prolepticYear;
+    /**
+     * The month.
+     */
+    private final short month;
+    /**
+     * The day.
+     */
+    private final short day;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Creates an instance.
+     *
+     * @param epochDay  the epoch day to convert based on 1970-01-01 (ISO)
+     * @return the Coptic date, not null
+     * @throws DateTimeException if the date is invalid
+     */
+    static CopticDate ofEpochDay(long epochDay) {
+        epochDay += EPOCH_DAY_DIFFERENCE;
+        int prolepticYear = (int) (((epochDay * 4) + 1463) / 1461);
+        int startYearEpochDay = (prolepticYear - 1) * 365 + (prolepticYear / 4);
+        int doy0 = (int) (epochDay - startYearEpochDay);
+        int month = doy0 / 30 + 1;
+        int dom = doy0 % 30 + 1;
+        return new CopticDate(prolepticYear, month, dom);
+    }
+
+    private static CopticDate resolvePreviousValid(int prolepticYear, int month, int day) {
+        if (month == 13 && day > 5) {
+            day = CopticChrono.INSTANCE.isLeapYear(prolepticYear) ? 6 : 5;
+        }
+        return new CopticDate(prolepticYear, month, day);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Creates an instance.
+     *
+     * @param prolepticYear  the Coptic proleptic-year
+     * @param month  the Coptic month, from 1 to 13
+     * @param dayOfMonth  the Coptic day-of-month, from 1 to 30
+     * @throws DateTimeException if the date is invalid
+     */
+    CopticDate(int prolepticYear, int month, int dayOfMonth) {
+        CopticChrono.MOY_RANGE.checkValidValue(month, MONTH_OF_YEAR);
+        ValueRange range;
+        if (month == 13) {
+            range = CopticChrono.INSTANCE.isLeapYear(prolepticYear) ? CopticChrono.DOM_RANGE_LEAP : CopticChrono.DOM_RANGE_NONLEAP;
+        } else {
+            range = CopticChrono.DOM_RANGE;
+        }
+        range.checkValidValue(dayOfMonth, DAY_OF_MONTH);
+
+        this.prolepticYear = prolepticYear;
+        this.month = (short) month;
+        this.day = (short) dayOfMonth;
+    }
+
+    /**
+     * Validates the object.
+     *
+     * @return the resolved date, not null
+     */
+    private Object readResolve() {
+        // TODO: validate
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public CopticChrono getChrono() {
+        return CopticChrono.INSTANCE;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public int lengthOfMonth() {
+        switch (month) {
+            case 13:
+                return (isLeapYear() ? 6 : 5);
+            default:
+                return 30;
+        }
+    }
+
+    @Override
+    public ValueRange range(TemporalField field) {
+        if (field instanceof ChronoField) {
+            if (isSupported(field)) {
+                ChronoField f = (ChronoField) field;
+                switch (f) {
+                    case DAY_OF_MONTH: return ValueRange.of(1, lengthOfMonth());
+                    case DAY_OF_YEAR: return ValueRange.of(1, lengthOfYear());
+                    case ALIGNED_WEEK_OF_MONTH: return ValueRange.of(1, month == 13 ? 1 : 5);
+                    case YEAR:
+                    case YEAR_OF_ERA: return (prolepticYear <= 0 ?
+                            ValueRange.of(1, Year.MAX_VALUE + 1) : ValueRange.of(1, Year.MAX_VALUE));  // TODO
+                }
+                return getChrono().range(f);
+            }
+            throw new DateTimeException("Unsupported field: " + field.getName());
+        }
+        return field.doRange(this);
+    }
+
+    @Override
+    public long getLong(TemporalField field) {
+        if (field instanceof ChronoField) {
+            switch ((ChronoField) field) {
+                case DAY_OF_WEEK: return Math.floorMod(toEpochDay() + 3, 7) + 1;
+                case ALIGNED_DAY_OF_WEEK_IN_MONTH: return ((day - 1) % 7) + 1;
+                case ALIGNED_DAY_OF_WEEK_IN_YEAR: return ((get(ChronoField.DAY_OF_YEAR) - 1) % 7) + 1;
+                case DAY_OF_MONTH: return day;
+                case DAY_OF_YEAR: return (month - 1) * 30 + day;
+                case EPOCH_DAY: return toEpochDay();
+                case ALIGNED_WEEK_OF_MONTH: return ((day - 1) / 7) + 1;
+                case ALIGNED_WEEK_OF_YEAR: return ((get(ChronoField.DAY_OF_YEAR) - 1) / 7) + 1;
+                case MONTH_OF_YEAR: return month;
+                case YEAR_OF_ERA: return (prolepticYear >= 1 ? prolepticYear : 1 - prolepticYear);
+                case YEAR: return prolepticYear;
+                case ERA: return (prolepticYear >= 1 ? 1 : 0);
+            }
+            throw new DateTimeException("Unsupported field: " + field.getName());
+        }
+        return field.doGet(this);
+    }
+
+    @Override
+    public CopticDate with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            f.checkValidValue(newValue);        // TODO: validate value
+            int nvalue = (int) newValue;
+            switch (f) {
+                case DAY_OF_WEEK: return plusDays(newValue - get(ChronoField.DAY_OF_WEEK));
+                case ALIGNED_DAY_OF_WEEK_IN_MONTH: return plusDays(newValue - getLong(ALIGNED_DAY_OF_WEEK_IN_MONTH));
+                case ALIGNED_DAY_OF_WEEK_IN_YEAR: return plusDays(newValue - getLong(ALIGNED_DAY_OF_WEEK_IN_YEAR));
+                case DAY_OF_MONTH: return resolvePreviousValid(prolepticYear, month, nvalue);
+                case DAY_OF_YEAR: return resolvePreviousValid(prolepticYear, ((nvalue - 1) / 30) + 1, ((nvalue - 1) % 30) + 1);
+                case EPOCH_DAY: return ofEpochDay(nvalue);
+                case ALIGNED_WEEK_OF_MONTH: return plusDays((newValue - getLong(ALIGNED_WEEK_OF_MONTH)) * 7);
+                case ALIGNED_WEEK_OF_YEAR: return plusDays((newValue - getLong(ALIGNED_WEEK_OF_YEAR)) * 7);
+                case MONTH_OF_YEAR: return resolvePreviousValid(prolepticYear, nvalue, day);
+                case YEAR_OF_ERA: return resolvePreviousValid(prolepticYear >= 1 ? nvalue : 1 - nvalue, month, day);
+                case YEAR: return resolvePreviousValid(nvalue, month, day);
+                case ERA: return resolvePreviousValid(1 - prolepticYear, month, day);
+            }
+            throw new DateTimeException("Unsupported field: " + field.getName());
+        }
+        return field.doWith(this, newValue);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public CopticDate plus(long amountToAdd, TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            ChronoUnit f = (ChronoUnit) unit;
+            switch (f) {
+                case DAYS: return plusDays(amountToAdd);
+                case WEEKS: return plusDays(Math.multiplyExact(amountToAdd, 7));
+                case MONTHS: return plusMonths(amountToAdd);
+                case YEARS: return plusYears(amountToAdd);
+                case DECADES: return plusYears(Math.multiplyExact(amountToAdd, 10));
+                case CENTURIES: return plusYears(Math.multiplyExact(amountToAdd, 100));
+                case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000));
+            }
+            throw new DateTimeException(unit.getName() + " not valid for CopticDate");
+        }
+        return unit.doPlus(this, amountToAdd);
+    }
+
+    //-----------------------------------------------------------------------
+    private CopticDate plusYears(long years) {
+        return plusMonths(Math.multiplyExact(years, 13));
+    }
+
+    private CopticDate plusMonths(long months) {
+        if (months == 0) {
+            return this;
+        }
+        long curEm = prolepticYear * 13L + (month - 1);
+        long calcEm = Math.addExact(curEm, months);
+        int newYear = Math.toIntExact(Math.floorDiv(calcEm, 13));
+        int newMonth = (int)Math.floorMod(calcEm, 13) + 1;
+        return resolvePreviousValid(newYear, newMonth, day);
+    }
+
+    private CopticDate plusDays(long days) {
+        if (days == 0) {
+            return this;
+        }
+        return CopticDate.ofEpochDay(Math.addExact(toEpochDay(), days));
+    }
+
+    @Override
+    public long periodUntil(Temporal endDateTime, TemporalUnit unit) {
+        if (endDateTime instanceof ChronoLocalDate == false) {
+            throw new DateTimeException("Unable to calculate period between objects of two different types");
+        }
+        ChronoLocalDate<?> end = (ChronoLocalDate<?>) endDateTime;
+        if (getChrono().equals(end.getChrono()) == false) {
+            throw new DateTimeException("Unable to calculate period between two different chronologies");
+        }
+        if (unit instanceof ChronoUnit) {
+            return LocalDate.from(this).periodUntil(end, unit);  // TODO: this is wrong
+        }
+        return unit.between(this, endDateTime).getAmount();
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public long toEpochDay() {
+        long year = (long) prolepticYear;
+        long copticEpochDay = ((year - 1) * 365) + Math.floorDiv(year, 4) + (get(ChronoField.DAY_OF_YEAR) - 1);
+        return copticEpochDay - EPOCH_DAY_DIFFERENCE;
+    }
+
+    @Override
+    public String toString() {
+        // getLong() reduces chances of exceptions in toString()
+        long yoe = getLong(YEAR_OF_ERA);
+        long moy = getLong(MONTH_OF_YEAR);
+        long dom = getLong(DAY_OF_MONTH);
+        StringBuilder buf = new StringBuilder(30);
+        buf.append(getChrono().toString())
+                .append(" ")
+                .append(getEra())
+                .append(" ")
+                .append(yoe)
+                .append(moy < 10 ? "-0" : "-").append(moy)
+                .append(dom < 10 ? "-0" : "-").append(dom);
+        return buf.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/calendar/CopticEra.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,210 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.calendar;
+
+import static java.time.temporal.ChronoField.ERA;
+
+import java.util.Locale;
+
+import java.time.DateTimeException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.Queries;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.ValueRange;
+import java.time.temporal.ChronoLocalDate;
+import java.time.temporal.Era;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.TextStyle;
+
+/**
+ * An era in the Coptic calendar system.
+ * <p>
+ * The Coptic calendar system uses the 'Era of the Martyrs'.
+ * The start of the Coptic epoch {@code 0001-01-01 (Coptic)} is {@code 0284-08-29 (ISO)}.
+ * <p>
+ * <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code CopticEra}.
+ * Use {@code getValue()} instead.</b>
+ *
+ * <h4>Implementation notes</h4>
+ * This is an immutable and thread-safe enum.
+ */
+enum CopticEra implements Era<CopticChrono> {
+
+    /**
+     * The singleton instance for the era BEFORE_AM, 'Before Era of the Martyrs'.
+     * This has the numeric value of {@code 0}.
+     */
+    BEFORE_AM,
+    /**
+     * The singleton instance for the era AM, 'Era of the Martyrs'.
+     * This has the numeric value of {@code 1}.
+     */
+    AM;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code CopticEra} from an {@code int} value.
+     * <p>
+     * {@code CopticEra} is an enum representing the Coptic eras of BEFORE_AM/AM.
+     * This factory allows the enum to be obtained from the {@code int} value.
+     *
+     * @param era  the BEFORE_AM/AM value to represent, from 0 (BEFORE_AM) to 1 (AM)
+     * @return the era singleton, not null
+     * @throws DateTimeException if the value is invalid
+     */
+    public static CopticEra of(int era) {
+        switch (era) {
+            case 0:
+                return BEFORE_AM;
+            case 1:
+                return AM;
+            default:
+                throw new DateTimeException("Invalid era: " + era);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the numeric era {@code int} value.
+     * <p>
+     * The era BEFORE_AM has the value 0, while the era AM has the value 1.
+     *
+     * @return the era value, from 0 (BEFORE_AM) to 1 (AM)
+     */
+    public int getValue() {
+        return ordinal();
+    }
+
+    @Override
+    public CopticChrono getChrono() {
+        return CopticChrono.INSTANCE;
+    }
+
+    // JDK8 default methods:
+    //-----------------------------------------------------------------------
+    @Override
+    public ChronoLocalDate<CopticChrono> date(int year, int month, int day) {
+        return getChrono().date(this, year, month, day);
+    }
+
+    @Override
+    public ChronoLocalDate<CopticChrono> dateYearDay(int year, int dayOfYear) {
+        return getChrono().dateYearDay(this, year, dayOfYear);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public boolean isSupported(TemporalField field) {
+        if (field instanceof ChronoField) {
+            return field == ERA;
+        }
+        return field != null && field.doIsSupported(this);
+    }
+
+    @Override
+    public ValueRange range(TemporalField field) {
+        if (field == ERA) {
+            return field.range();
+        } else if (field instanceof ChronoField) {
+            throw new DateTimeException("Unsupported field: " + field.getName());
+        }
+        return field.doRange(this);
+    }
+
+    @Override
+    public int get(TemporalField field) {
+        if (field == ERA) {
+            return getValue();
+        }
+        return range(field).checkValidIntValue(getLong(field), field);
+    }
+
+    @Override
+    public long getLong(TemporalField field) {
+        if (field == ERA) {
+            return getValue();
+        } else if (field instanceof ChronoField) {
+            throw new DateTimeException("Unsupported field: " + field.getName());
+        }
+        return field.doGet(this);
+    }
+
+    //-------------------------------------------------------------------------
+    @Override
+    public Temporal adjustInto(Temporal dateTime) {
+        return dateTime.with(ERA, getValue());
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <R> R query(TemporalQuery<R> query) {
+        if (query == Queries.zoneId()) {
+            return null;
+        } else if (query == Queries.chrono()) {
+            return (R) getChrono();
+        }
+        return query.queryFrom(this);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public String getText(TextStyle style, Locale locale) {
+        return new DateTimeFormatterBuilder().appendText(ERA, style).toFormatter(locale).print(this);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/calendar/TestChronoLocalDate.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,461 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.calendar;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import java.time.Duration;
+import java.time.LocalDate;
+import java.time.calendar.HijrahChrono;
+import java.time.calendar.JapaneseChrono;
+import java.time.calendar.MinguoChrono;
+import java.time.calendar.ThaiBuddhistChrono;
+import java.time.temporal.Chrono;
+import java.time.temporal.ChronoLocalDate;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.SimplePeriod;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.format.DateTimeBuilder;
+import java.time.temporal.TemporalAdder;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalSubtractor;
+import java.time.temporal.ValueRange;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.ISOChrono;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test assertions that must be true for all built-in chronologies.
+ */
+@Test
+public class TestChronoLocalDate {
+
+    //-----------------------------------------------------------------------
+    // regular data factory for names and descriptions of available calendars
+    //-----------------------------------------------------------------------
+    @DataProvider(name = "calendars")
+    Chrono<?>[][] data_of_calendars() {
+        return new Chrono<?>[][]{
+                    {HijrahChrono.INSTANCE},
+                    {ISOChrono.INSTANCE},
+                    {JapaneseChrono.INSTANCE},
+                    {MinguoChrono.INSTANCE},
+                    {ThaiBuddhistChrono.INSTANCE}};
+    }
+
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_badWithAdjusterChrono(Chrono<?> chrono) {
+        LocalDate refDate = LocalDate.of(1900, 1, 1);
+        ChronoLocalDate<?> date = chrono.date(refDate);
+        for (Chrono<?>[] clist : data_of_calendars()) {
+            Chrono<?> chrono2 = clist[0];
+            ChronoLocalDate<?> date2 = chrono2.date(refDate);
+            TemporalAdjuster adjuster = new FixedAdjuster(date2);
+            if (chrono != chrono2) {
+                try {
+                    date.with(adjuster);
+                    Assert.fail("WithAdjuster should have thrown a ClassCastException");
+                } catch (ClassCastException cce) {
+                    // Expected exception; not an error
+                }
+            } else {
+                // Same chronology,
+                ChronoLocalDate<?> result = date.with(adjuster);
+                assertEquals(result, date2, "WithAdjuster failed to replace date");
+            }
+        }
+    }
+
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_badPlusAdjusterChrono(Chrono<?> chrono) {
+        LocalDate refDate = LocalDate.of(1900, 1, 1);
+        ChronoLocalDate<?> date = chrono.date(refDate);
+        for (Chrono<?>[] clist : data_of_calendars()) {
+            Chrono<?> chrono2 = clist[0];
+            ChronoLocalDate<?> date2 = chrono2.date(refDate);
+            TemporalAdder adjuster = new FixedAdjuster(date2);
+            if (chrono != chrono2) {
+                try {
+                    date.plus(adjuster);
+                    Assert.fail("WithAdjuster should have thrown a ClassCastException");
+                } catch (ClassCastException cce) {
+                    // Expected exception; not an error
+                }
+            } else {
+                // Same chronology,
+                ChronoLocalDate<?> result = date.plus(adjuster);
+                assertEquals(result, date2, "WithAdjuster failed to replace date");
+            }
+        }
+    }
+
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_badMinusAdjusterChrono(Chrono<?> chrono) {
+        LocalDate refDate = LocalDate.of(1900, 1, 1);
+        ChronoLocalDate<?> date = chrono.date(refDate);
+        for (Chrono<?>[] clist : data_of_calendars()) {
+            Chrono<?> chrono2 = clist[0];
+            ChronoLocalDate<?> date2 = chrono2.date(refDate);
+            TemporalSubtractor adjuster = new FixedAdjuster(date2);
+            if (chrono != chrono2) {
+                try {
+                    date.minus(adjuster);
+                    Assert.fail("WithAdjuster should have thrown a ClassCastException");
+                } catch (ClassCastException cce) {
+                    // Expected exception; not an error
+                }
+            } else {
+                // Same chronology,
+                ChronoLocalDate<?> result = date.minus(adjuster);
+                assertEquals(result, date2, "WithAdjuster failed to replace date");
+            }
+        }
+    }
+
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_badPlusTemporalUnitChrono(Chrono<?> chrono) {
+        LocalDate refDate = LocalDate.of(1900, 1, 1);
+        ChronoLocalDate<?> date = chrono.date(refDate);
+        for (Chrono<?>[] clist : data_of_calendars()) {
+            Chrono<?> chrono2 = clist[0];
+            ChronoLocalDate<?> date2 = chrono2.date(refDate);
+            TemporalUnit adjuster = new FixedTemporalUnit(date2);
+            if (chrono != chrono2) {
+                try {
+                    date.plus(1, adjuster);
+                    Assert.fail("TemporalUnit.doAdd plus should have thrown a ClassCastException" + date.getClass()
+                            + ", can not be cast to " + date2.getClass());
+                } catch (ClassCastException cce) {
+                    // Expected exception; not an error
+                }
+            } else {
+                // Same chronology,
+                ChronoLocalDate<?> result = date.plus(1, adjuster);
+                assertEquals(result, date2, "WithAdjuster failed to replace date");
+            }
+        }
+    }
+
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_badMinusTemporalUnitChrono(Chrono<?> chrono) {
+        LocalDate refDate = LocalDate.of(1900, 1, 1);
+        ChronoLocalDate<?> date = chrono.date(refDate);
+        for (Chrono<?>[] clist : data_of_calendars()) {
+            Chrono<?> chrono2 = clist[0];
+            ChronoLocalDate<?> date2 = chrono2.date(refDate);
+            TemporalUnit adjuster = new FixedTemporalUnit(date2);
+            if (chrono != chrono2) {
+                try {
+                    date.minus(1, adjuster);
+                    Assert.fail("TemporalUnit.doAdd minus should have thrown a ClassCastException" + date.getClass()
+                            + ", can not be cast to " + date2.getClass());
+                } catch (ClassCastException cce) {
+                    // Expected exception; not an error
+                }
+            } else {
+                // Same chronology,
+                ChronoLocalDate<?> result = date.minus(1, adjuster);
+                assertEquals(result, date2, "WithAdjuster failed to replace date");
+            }
+        }
+    }
+
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_badTemporalFieldChrono(Chrono<?> chrono) {
+        LocalDate refDate = LocalDate.of(1900, 1, 1);
+        ChronoLocalDate<?> date = chrono.date(refDate);
+        for (Chrono<?>[] clist : data_of_calendars()) {
+            Chrono<?> chrono2 = clist[0];
+            ChronoLocalDate<?> date2 = chrono2.date(refDate);
+            TemporalField adjuster = new FixedTemporalField(date2);
+            if (chrono != chrono2) {
+                try {
+                    date.with(adjuster, 1);
+                    Assert.fail("TemporalField doSet should have thrown a ClassCastException" + date.getClass()
+                            + ", can not be cast to " + date2.getClass());
+                } catch (ClassCastException cce) {
+                    // Expected exception; not an error
+                }
+            } else {
+                // Same chronology,
+                ChronoLocalDate<?> result = date.with(adjuster, 1);
+                assertEquals(result, date2, "TemporalField doSet failed to replace date");
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // isBefore, isAfter, isEqual, DATE_COMPARATOR
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_date_comparisons(Chrono<?> chrono) {
+        List<ChronoLocalDate<?>> dates = new ArrayList<>();
+
+        ChronoLocalDate<?> date = chrono.date(LocalDate.of(1900, 1, 1));
+
+        // Insert dates in order, no duplicates
+        dates.add(date.minus(1000, ChronoUnit.YEARS));
+        dates.add(date.minus(100, ChronoUnit.YEARS));
+        dates.add(date.minus(10, ChronoUnit.YEARS));
+        dates.add(date.minus(1, ChronoUnit.YEARS));
+        dates.add(date.minus(1, ChronoUnit.MONTHS));
+        dates.add(date.minus(1, ChronoUnit.WEEKS));
+        dates.add(date.minus(1, ChronoUnit.DAYS));
+        dates.add(date);
+        dates.add(date.plus(1, ChronoUnit.DAYS));
+        dates.add(date.plus(1, ChronoUnit.WEEKS));
+        dates.add(date.plus(1, ChronoUnit.MONTHS));
+        dates.add(date.plus(1, ChronoUnit.YEARS));
+        dates.add(date.plus(10, ChronoUnit.YEARS));
+        dates.add(date.plus(100, ChronoUnit.YEARS));
+        dates.add(date.plus(1000, ChronoUnit.YEARS));
+
+        // Check these dates against the corresponding dates for every calendar
+        for (Chrono<?>[] clist : data_of_calendars()) {
+            List<ChronoLocalDate<?>> otherDates = new ArrayList<>();
+            Chrono<?> chrono2 = clist[0];
+            for (ChronoLocalDate<?> d : dates) {
+                otherDates.add(chrono2.date(d));
+            }
+
+            // Now compare  the sequence of original dates with the sequence of converted dates
+            for (int i = 0; i < dates.size(); i++) {
+                ChronoLocalDate<?> a = dates.get(i);
+                for (int j = 0; j < otherDates.size(); j++) {
+                    ChronoLocalDate<?> b = otherDates.get(j);
+                    int cmp = ChronoLocalDate.DATE_COMPARATOR.compare(a, b);
+                    if (i < j) {
+                        assertTrue(cmp < 0, a + " compare " + b);
+                        assertEquals(a.isBefore(b), true, a + " isBefore " + b);
+                        assertEquals(a.isAfter(b), false, a + " isAfter " + b);
+                        assertEquals(a.isEqual(b), false, a + " isEqual " + b);
+                    } else if (i > j) {
+                        assertTrue(cmp > 0, a + " compare " + b);
+                        assertEquals(a.isBefore(b), false, a + " isBefore " + b);
+                        assertEquals(a.isAfter(b), true, a + " isAfter " + b);
+                        assertEquals(a.isEqual(b), false, a + " isEqual " + b);
+                    } else {
+                        assertTrue(cmp == 0, a + " compare " + b);
+                        assertEquals(a.isBefore(b), false, a + " isBefore " + b);
+                        assertEquals(a.isAfter(b), false, a + " isAfter " + b);
+                        assertEquals(a.isEqual(b), true, a + " isEqual " + b);
+                    }
+                }
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // Test Serialization of Calendars
+    //-----------------------------------------------------------------------
+    @Test( groups={"tck"}, dataProvider="calendars")
+    public <C extends Chrono<C>> void test_ChronoSerialization(C chrono) throws Exception {
+        LocalDate ref = LocalDate.of(1900, 1, 5);
+        ChronoLocalDate<C> orginal = chrono.date(ref);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream(baos);
+        out.writeObject(orginal);
+        out.close();
+        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+        ObjectInputStream in = new ObjectInputStream(bais);
+        @SuppressWarnings("unchecked")
+        ChronoLocalDate<C> ser = (ChronoLocalDate<C>) in.readObject();
+        assertEquals(ser, orginal, "deserialized date is wrong");
+    }
+
+    /**
+     * FixedAdjusted returns a fixed Temporal in all adjustments.
+     * Construct an adjuster with the Temporal that should be returned from adjust.
+     */
+    static class FixedAdjuster implements TemporalAdjuster, TemporalAdder, TemporalSubtractor {
+        private Temporal datetime;
+
+        FixedAdjuster(Temporal datetime) {
+            this.datetime = datetime;
+        }
+
+        @Override
+        public Temporal adjustInto(Temporal ignore) {
+            return datetime;
+        }
+
+        @Override
+        public Temporal addTo(Temporal ignore) {
+            return datetime;
+        }
+
+        @Override
+        public Temporal subtractFrom(Temporal ignore) {
+            return datetime;
+        }
+
+    }
+
+    /**
+     * FixedTemporalUnit returns a fixed Temporal in all adjustments.
+     * Construct an FixedTemporalUnit with the Temporal that should be returned from doAdd.
+     */
+    static class FixedTemporalUnit implements TemporalUnit {
+        private Temporal temporal;
+
+        FixedTemporalUnit(Temporal temporal) {
+            this.temporal = temporal;
+        }
+
+        @Override
+        public String getName() {
+            return "FixedTemporalUnit";
+        }
+
+        @Override
+        public Duration getDuration() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public boolean isDurationEstimated() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public boolean isSupported(Temporal temporal) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public <R extends Temporal> R doPlus(R dateTime, long periodToAdd) {
+            return (R) this.temporal;
+        }
+
+        @Override
+        public <R extends Temporal> SimplePeriod between(R dateTime1, R dateTime2) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+    }
+
+    /**
+     * FixedTemporalField returns a fixed Temporal in all adjustments.
+     * Construct an FixedTemporalField with the Temporal that should be returned from doSet.
+     */
+    static class FixedTemporalField implements TemporalField {
+        private Temporal temporal;
+        FixedTemporalField(Temporal temporal) {
+            this.temporal = temporal;
+        }
+
+        @Override
+        public String getName() {
+            return "FixedTemporalField";
+        }
+
+        @Override
+        public TemporalUnit getBaseUnit() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public TemporalUnit getRangeUnit() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public ValueRange range() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public boolean doIsSupported(TemporalAccessor temporal) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public ValueRange doRange(TemporalAccessor temporal) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public long doGet(TemporalAccessor temporal) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public <R extends Temporal> R doWith(R temporal, long newValue) {
+            return (R) this.temporal;
+        }
+
+        @Override
+        public boolean resolve(DateTimeBuilder builder, long value) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/calendar/TestChronoLocalDateTime.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,469 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.calendar;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import java.time.Duration;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.calendar.HijrahChrono;
+import java.time.calendar.JapaneseChrono;
+import java.time.calendar.MinguoChrono;
+import java.time.calendar.ThaiBuddhistChrono;
+import java.time.temporal.Chrono;
+import java.time.temporal.ChronoLocalDateTime;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.SimplePeriod;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.format.DateTimeBuilder;
+import java.time.temporal.TemporalAdder;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalSubtractor;
+import java.time.temporal.ValueRange;
+import java.time.temporal.ISOChrono;
+import java.time.temporal.TemporalUnit;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test assertions that must be true for all built-in chronologies.
+ */
+@Test
+public class TestChronoLocalDateTime {
+    //-----------------------------------------------------------------------
+    // regular data factory for names and descriptions of available calendars
+    //-----------------------------------------------------------------------
+    @DataProvider(name = "calendars")
+    Chrono[][] data_of_calendars() {
+        return new Chrono[][]{
+                    {HijrahChrono.INSTANCE},
+                    {ISOChrono.INSTANCE},
+                    {JapaneseChrono.INSTANCE},
+                    {MinguoChrono.INSTANCE},
+                    {ThaiBuddhistChrono.INSTANCE}};
+    }
+
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_badWithAdjusterChrono(Chrono chrono) {
+        LocalDate refDate = LocalDate.of(1900, 1, 1);
+        ChronoLocalDateTime cdt = chrono.date(refDate).atTime(LocalTime.NOON);
+        for (Chrono[] clist : data_of_calendars()) {
+            Chrono chrono2 = clist[0];
+            ChronoLocalDateTime<?> cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON);
+            TemporalAdjuster adjuster = new FixedAdjuster(cdt2);
+            if (chrono != chrono2) {
+                try {
+                    ChronoLocalDateTime<?> notreached = cdt.with(adjuster);
+                    Assert.fail("WithAdjuster should have thrown a ClassCastException, "
+                            + "required: " + cdt + ", supplied: " + cdt2);
+                } catch (ClassCastException cce) {
+                    // Expected exception; not an error
+                }
+            } else {
+                // Same chronology,
+                ChronoLocalDateTime<?> result = cdt.with(adjuster);
+                assertEquals(result, cdt2, "WithAdjuster failed to replace date");
+            }
+        }
+    }
+
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_badPlusAdjusterChrono(Chrono chrono) {
+        LocalDate refDate = LocalDate.of(1900, 1, 1);
+        ChronoLocalDateTime cdt = chrono.date(refDate).atTime(LocalTime.NOON);
+        for (Chrono[] clist : data_of_calendars()) {
+            Chrono chrono2 = clist[0];
+            ChronoLocalDateTime<?> cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON);
+            TemporalAdder adjuster = new FixedAdjuster(cdt2);
+            if (chrono != chrono2) {
+                try {
+                    ChronoLocalDateTime<?> notreached = cdt.plus(adjuster);
+                    Assert.fail("WithAdjuster should have thrown a ClassCastException, "
+                            + "required: " + cdt + ", supplied: " + cdt2);
+                } catch (ClassCastException cce) {
+                    // Expected exception; not an error
+                }
+            } else {
+                // Same chronology,
+                ChronoLocalDateTime<?> result = cdt.plus(adjuster);
+                assertEquals(result, cdt2, "WithAdjuster failed to replace date time");
+            }
+        }
+    }
+
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_badMinusAdjusterChrono(Chrono chrono) {
+        LocalDate refDate = LocalDate.of(1900, 1, 1);
+        ChronoLocalDateTime cdt = chrono.date(refDate).atTime(LocalTime.NOON);
+        for (Chrono[] clist : data_of_calendars()) {
+            Chrono chrono2 = clist[0];
+            ChronoLocalDateTime<?> cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON);
+            TemporalSubtractor adjuster = new FixedAdjuster(cdt2);
+            if (chrono != chrono2) {
+                try {
+                    ChronoLocalDateTime<?> notreached = cdt.minus(adjuster);
+                    Assert.fail("WithAdjuster should have thrown a ClassCastException, "
+                            + "required: " + cdt + ", supplied: " + cdt2);
+                } catch (ClassCastException cce) {
+                    // Expected exception; not an error
+                }
+            } else {
+                // Same chronology,
+                ChronoLocalDateTime<?> result = cdt.minus(adjuster);
+                assertEquals(result, cdt2, "WithAdjuster failed to replace date");
+            }
+        }
+    }
+
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_badPlusTemporalUnitChrono(Chrono chrono) {
+        LocalDate refDate = LocalDate.of(1900, 1, 1);
+        ChronoLocalDateTime cdt = chrono.date(refDate).atTime(LocalTime.NOON);
+        for (Chrono[] clist : data_of_calendars()) {
+            Chrono chrono2 = clist[0];
+            ChronoLocalDateTime<?> cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON);
+            TemporalUnit adjuster = new FixedTemporalUnit(cdt2);
+            if (chrono != chrono2) {
+                try {
+                    ChronoLocalDateTime<?> notreached = cdt.plus(1, adjuster);
+                    Assert.fail("TemporalUnit.doAdd plus should have thrown a ClassCastException" + cdt
+                            + ", can not be cast to " + cdt2);
+                } catch (ClassCastException cce) {
+                    // Expected exception; not an error
+                }
+            } else {
+                // Same chronology,
+                ChronoLocalDateTime<?> result = cdt.plus(1, adjuster);
+                assertEquals(result, cdt2, "WithAdjuster failed to replace date");
+            }
+        }
+    }
+
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_badMinusTemporalUnitChrono(Chrono chrono) {
+        LocalDate refDate = LocalDate.of(1900, 1, 1);
+        ChronoLocalDateTime cdt = chrono.date(refDate).atTime(LocalTime.NOON);
+        for (Chrono[] clist : data_of_calendars()) {
+            Chrono chrono2 = clist[0];
+            ChronoLocalDateTime<?> cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON);
+            TemporalUnit adjuster = new FixedTemporalUnit(cdt2);
+            if (chrono != chrono2) {
+                try {
+                    ChronoLocalDateTime<?> notreached = cdt.minus(1, adjuster);
+                    Assert.fail("TemporalUnit.doAdd minus should have thrown a ClassCastException" + cdt.getClass()
+                            + ", can not be cast to " + cdt2.getClass());
+                } catch (ClassCastException cce) {
+                    // Expected exception; not an error
+                }
+            } else {
+                // Same chronology,
+                ChronoLocalDateTime<?> result = cdt.minus(1, adjuster);
+                assertEquals(result, cdt2, "WithAdjuster failed to replace date");
+            }
+        }
+    }
+
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_badTemporalFieldChrono(Chrono chrono) {
+        LocalDate refDate = LocalDate.of(1900, 1, 1);
+        ChronoLocalDateTime cdt = chrono.date(refDate).atTime(LocalTime.NOON);
+        for (Chrono[] clist : data_of_calendars()) {
+            Chrono chrono2 = clist[0];
+            ChronoLocalDateTime<?> cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON);
+            TemporalField adjuster = new FixedTemporalField(cdt2);
+            if (chrono != chrono2) {
+                try {
+                    ChronoLocalDateTime<?> notreached = cdt.with(adjuster, 1);
+                    Assert.fail("TemporalField doSet should have thrown a ClassCastException" + cdt.getClass()
+                            + ", can not be cast to " + cdt2.getClass());
+                } catch (ClassCastException cce) {
+                    // Expected exception; not an error
+                }
+            } else {
+                // Same chronology,
+                ChronoLocalDateTime<?> result = cdt.with(adjuster, 1);
+                assertEquals(result, cdt2, "TemporalField doSet failed to replace date");
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // isBefore, isAfter, isEqual
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_datetime_comparisons(Chrono chrono) {
+        List<ChronoLocalDateTime<?>> dates = new ArrayList<>();
+
+        ChronoLocalDateTime<?> date = chrono.date(LocalDate.of(1900, 1, 1)).atTime(LocalTime.MIN);
+
+        // Insert dates in order, no duplicates
+        dates.add(date.minus(100, ChronoUnit.YEARS));
+        dates.add(date.minus(1, ChronoUnit.YEARS));
+        dates.add(date.minus(1, ChronoUnit.MONTHS));
+        dates.add(date.minus(1, ChronoUnit.WEEKS));
+        dates.add(date.minus(1, ChronoUnit.DAYS));
+        dates.add(date.minus(1, ChronoUnit.HOURS));
+        dates.add(date.minus(1, ChronoUnit.MINUTES));
+        dates.add(date.minus(1, ChronoUnit.SECONDS));
+        dates.add(date.minus(1, ChronoUnit.NANOS));
+        dates.add(date);
+        dates.add(date.plus(1, ChronoUnit.NANOS));
+        dates.add(date.plus(1, ChronoUnit.SECONDS));
+        dates.add(date.plus(1, ChronoUnit.MINUTES));
+        dates.add(date.plus(1, ChronoUnit.HOURS));
+        dates.add(date.plus(1, ChronoUnit.DAYS));
+        dates.add(date.plus(1, ChronoUnit.WEEKS));
+        dates.add(date.plus(1, ChronoUnit.MONTHS));
+        dates.add(date.plus(1, ChronoUnit.YEARS));
+        dates.add(date.plus(100, ChronoUnit.YEARS));
+
+        // Check these dates against the corresponding dates for every calendar
+        for (Chrono[] clist : data_of_calendars()) {
+            List<ChronoLocalDateTime<?>> otherDates = new ArrayList<>();
+            Chrono chrono2 = clist[0];
+            for (ChronoLocalDateTime<?> d : dates) {
+                otherDates.add(chrono2.date(d).atTime(d.getTime()));
+            }
+
+            // Now compare  the sequence of original dates with the sequence of converted dates
+            for (int i = 0; i < dates.size(); i++) {
+                ChronoLocalDateTime<?> a = dates.get(i);
+                for (int j = 0; j < otherDates.size(); j++) {
+                    ChronoLocalDateTime<?> b = otherDates.get(j);
+                    int cmp = ChronoLocalDateTime.DATE_TIME_COMPARATOR.compare(a, b);
+                    if (i < j) {
+                        assertTrue(cmp < 0, a + " compare " + b);
+                        assertEquals(a.isBefore(b), true, a + " isBefore " + b);
+                        assertEquals(a.isAfter(b), false, a + " isAfter " + b);
+                        assertEquals(a.isEqual(b), false, a + " isEqual " + b);
+                    } else if (i > j) {
+                        assertTrue(cmp > 0, a + " compare " + b);
+                        assertEquals(a.isBefore(b), false, a + " isBefore " + b);
+                        assertEquals(a.isAfter(b), true, a + " isAfter " + b);
+                        assertEquals(a.isEqual(b), false, a + " isEqual " + b);
+                    } else {
+                        assertTrue(cmp == 0, a + " compare " + b);
+                        assertEquals(a.isBefore(b), false, a + " isBefore " + b);
+                        assertEquals(a.isAfter(b), false, a + " isAfter " + b);
+                        assertEquals(a.isEqual(b), true, a + " isEqual " + b);
+                    }
+                }
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // Test Serialization of ISO via chrono API
+    //-----------------------------------------------------------------------
+    @Test( groups={"tck"}, dataProvider="calendars")
+    public <C extends Chrono<C>> void test_ChronoLocalDateTimeSerialization(C chrono) throws Exception {
+        LocalDateTime ref = LocalDate.of(2000, 1, 5).atTime(12, 1, 2, 3);
+        ChronoLocalDateTime<C> orginal = chrono.date(ref).atTime(ref.getTime());
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream(baos);
+        out.writeObject(orginal);
+        out.close();
+        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+        ObjectInputStream in = new ObjectInputStream(bais);
+        ChronoLocalDateTime<C> ser = (ChronoLocalDateTime<C>) in.readObject();
+        assertEquals(ser, orginal, "deserialized date is wrong");
+    }
+
+
+    /**
+     * FixedAdjusted returns a fixed Temporal in all adjustments.
+     * Construct an adjuster with the Temporal that should be returned from adjust.
+     */
+    static class FixedAdjuster implements TemporalAdjuster, TemporalAdder, TemporalSubtractor {
+        private Temporal datetime;
+
+        FixedAdjuster(Temporal datetime) {
+            this.datetime = datetime;
+        }
+
+        @Override
+        public Temporal adjustInto(Temporal ignore) {
+            return datetime;
+        }
+
+        @Override
+        public Temporal addTo(Temporal ignore) {
+            return datetime;
+        }
+
+        @Override
+        public Temporal subtractFrom(Temporal ignore) {
+            return datetime;
+        }
+
+    }
+
+    /**
+     * FixedTemporalUnit returns a fixed Temporal in all adjustments.
+     * Construct an FixedTemporalUnit with the Temporal that should be returned from doAdd.
+     */
+    static class FixedTemporalUnit implements TemporalUnit {
+        private Temporal temporal;
+
+        FixedTemporalUnit(Temporal temporal) {
+            this.temporal = temporal;
+        }
+
+        @Override
+        public String getName() {
+            return "FixedTemporalUnit";
+        }
+
+        @Override
+        public Duration getDuration() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public boolean isDurationEstimated() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public boolean isSupported(Temporal temporal) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public <R extends Temporal> R doPlus(R dateTime, long periodToAdd) {
+            return (R) this.temporal;
+        }
+
+        @Override
+        public <R extends Temporal> SimplePeriod between(R dateTime1, R dateTime2) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+    }
+
+    /**
+     * FixedTemporalField returns a fixed Temporal in all adjustments.
+     * Construct an FixedTemporalField with the Temporal that should be returned from doSet.
+     */
+    static class FixedTemporalField implements TemporalField {
+        private Temporal temporal;
+        FixedTemporalField(Temporal temporal) {
+            this.temporal = temporal;
+        }
+
+        @Override
+        public String getName() {
+            return "FixedTemporalField";
+        }
+
+        @Override
+        public TemporalUnit getBaseUnit() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public TemporalUnit getRangeUnit() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public ValueRange range() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public boolean doIsSupported(TemporalAccessor temporal) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public ValueRange doRange(TemporalAccessor temporal) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public long doGet(TemporalAccessor temporal) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public <R extends Temporal> R doWith(R temporal, long newValue) {
+            return (R) this.temporal;
+        }
+
+        @Override
+        public boolean resolve(DateTimeBuilder builder, long value) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/calendar/TestHijrahChrono.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.calendar;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.Month;
+import java.time.calendar.HijrahChrono;
+import java.time.temporal.ChronoLocalDate;
+import java.time.temporal.Adjusters;
+import java.time.temporal.Chrono;
+import java.time.temporal.ISOChrono;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test.
+ */
+@Test
+public class TestHijrahChrono {
+
+    //-----------------------------------------------------------------------
+    // Chrono.ofName("Hijrah")  Lookup by name
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_chrono_byName() {
+        Chrono<HijrahChrono> c = HijrahChrono.INSTANCE;
+        Chrono<?> test = Chrono.of("Hijrah");
+        Assert.assertNotNull(test, "The Hijrah calendar could not be found byName");
+        Assert.assertEquals(test.getId(), "Hijrah", "ID mismatch");
+        Assert.assertEquals(test.getCalendarType(), "islamicc", "Type mismatch");
+        Assert.assertEquals(test, c);
+    }
+
+    //-----------------------------------------------------------------------
+    // creation, toLocalDate()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="samples")
+    Object[][] data_samples() {
+        return new Object[][] {
+            {HijrahChrono.INSTANCE.date(1, 1, 1), LocalDate.of(622, 7, 19)},
+            {HijrahChrono.INSTANCE.date(1, 1, 2), LocalDate.of(622, 7, 20)},
+            {HijrahChrono.INSTANCE.date(1, 1, 3), LocalDate.of(622, 7, 21)},
+
+            {HijrahChrono.INSTANCE.date(2, 1, 1), LocalDate.of(623, 7, 8)},
+            {HijrahChrono.INSTANCE.date(3, 1, 1), LocalDate.of(624, 6, 27)},
+            {HijrahChrono.INSTANCE.date(3, 12, 6), LocalDate.of(625, 5, 23)},
+            {HijrahChrono.INSTANCE.date(4, 1, 1), LocalDate.of(625, 6, 16)},
+            {HijrahChrono.INSTANCE.date(4, 7, 3), LocalDate.of(625, 12, 12)},
+            {HijrahChrono.INSTANCE.date(4, 7, 4), LocalDate.of(625, 12, 13)},
+            {HijrahChrono.INSTANCE.date(5, 1, 1), LocalDate.of(626, 6, 5)},
+            {HijrahChrono.INSTANCE.date(1662, 3, 3), LocalDate.of(2234, 4, 3)},
+            {HijrahChrono.INSTANCE.date(1728, 10, 28), LocalDate.of(2298, 12, 03)},
+            {HijrahChrono.INSTANCE.date(1728, 10, 29), LocalDate.of(2298, 12, 04)},
+        };
+    }
+
+    @Test(dataProvider="samples", groups={"tck"})
+    public void test_toLocalDate(ChronoLocalDate<?> hijrahDate, LocalDate iso) {
+        assertEquals(LocalDate.from(hijrahDate), iso);
+    }
+
+    @Test(dataProvider="samples", groups={"tck"})
+    public void test_fromCalendrical(ChronoLocalDate<?> hijrahDate, LocalDate iso) {
+        assertEquals(HijrahChrono.INSTANCE.date(iso), hijrahDate);
+    }
+
+    @DataProvider(name="badDates")
+    Object[][] data_badDates() {
+        return new Object[][] {
+            {1728, 0, 0},
+
+            {1728, -1, 1},
+            {1728, 0, 1},
+            {1728, 14, 1},
+            {1728, 15, 1},
+
+            {1728, 1, -1},
+            {1728, 1, 0},
+            {1728, 1, 32},
+
+            {1728, 12, -1},
+            {1728, 12, 0},
+            {1728, 12, 32},
+        };
+    }
+
+    @Test(dataProvider="badDates", groups={"tck"}, expectedExceptions=DateTimeException.class)
+    public void test_badDates(int year, int month, int dom) {
+        HijrahChrono.INSTANCE.date(year, month, dom);
+    }
+
+    //-----------------------------------------------------------------------
+    // with(WithAdjuster)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_adjust1() {
+        ChronoLocalDate<?> base = HijrahChrono.INSTANCE.date(1728, 10, 28);
+        ChronoLocalDate<?> test = base.with(Adjusters.lastDayOfMonth());
+        assertEquals(test, HijrahChrono.INSTANCE.date(1728, 10, 29));
+    }
+
+    @Test(groups={"tck"})
+    public void test_adjust2() {
+        ChronoLocalDate<?> base = HijrahChrono.INSTANCE.date(1728, 12, 2);
+        ChronoLocalDate<?> test = base.with(Adjusters.lastDayOfMonth());
+        assertEquals(test, HijrahChrono.INSTANCE.date(1728, 12, 30));
+    }
+
+    //-----------------------------------------------------------------------
+    // HijrahDate.with(Local*)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_adjust_toLocalDate() {
+        ChronoLocalDate<?> hijrahDate = HijrahChrono.INSTANCE.date(1726, 1, 4);
+        ChronoLocalDate<?> test = hijrahDate.with(LocalDate.of(2012, 7, 6));
+        assertEquals(test, HijrahChrono.INSTANCE.date(1433, 8, 16));
+    }
+
+    @Test(groups={"tck"}, expectedExceptions=DateTimeException.class)
+    public void test_adjust_toMonth() {
+        ChronoLocalDate<?> hijrahDate = HijrahChrono.INSTANCE.date(1726, 1, 4);
+        hijrahDate.with(Month.APRIL);
+    }
+
+    //-----------------------------------------------------------------------
+    // LocalDate.with(HijrahDate)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_LocalDate_adjustToHijrahDate() {
+        ChronoLocalDate<?> hijrahDate = HijrahChrono.INSTANCE.date(1728, 10, 29);
+        LocalDate test = LocalDate.MIN.with(hijrahDate);
+        assertEquals(test, LocalDate.of(2298, 12, 4));
+    }
+
+    @Test(groups={"tck"})
+    public void test_LocalDateTime_adjustToHijrahDate() {
+        ChronoLocalDate<?> hijrahDate = HijrahChrono.INSTANCE.date(1728, 10, 29);
+        LocalDateTime test = LocalDateTime.MIN.with(hijrahDate);
+        assertEquals(test, LocalDateTime.of(2298, 12, 4, 0, 0));
+    }
+
+    //-----------------------------------------------------------------------
+    // toString()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="toString")
+    Object[][] data_toString() {
+        return new Object[][] {
+            {HijrahChrono.INSTANCE.date(1, 1, 1), "Hijrah AH 1-01-01"},
+            {HijrahChrono.INSTANCE.date(1728, 10, 28), "Hijrah AH 1728-10-28"},
+            {HijrahChrono.INSTANCE.date(1728, 10, 29), "Hijrah AH 1728-10-29"},
+            {HijrahChrono.INSTANCE.date(1727, 12, 5), "Hijrah AH 1727-12-05"},
+            {HijrahChrono.INSTANCE.date(1727, 12, 6), "Hijrah AH 1727-12-06"},
+        };
+    }
+
+    @Test(dataProvider="toString", groups={"tck"})
+    public void test_toString(ChronoLocalDate<?> hijrahDate, String expected) {
+        assertEquals(hijrahDate.toString(), expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // equals()
+    //-----------------------------------------------------------------------
+    @Test(groups="tck")
+    public void test_equals_true() {
+        assertTrue(HijrahChrono.INSTANCE.equals(HijrahChrono.INSTANCE));
+    }
+
+    @Test(groups="tck")
+    public void test_equals_false() {
+        assertFalse(HijrahChrono.INSTANCE.equals(ISOChrono.INSTANCE));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/calendar/TestJapaneseChrono.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.calendar;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.util.List;
+
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.Month;
+import java.time.calendar.JapaneseChrono;
+import java.time.temporal.Adjusters;
+import java.time.temporal.Chrono;
+import java.time.temporal.ChronoLocalDate;
+import java.time.temporal.Era;
+import java.time.temporal.ISOChrono;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test.
+ */
+@Test
+public class TestJapaneseChrono {
+
+    //-----------------------------------------------------------------------
+    // Chrono.ofName("Japanese")  Lookup by name
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_chrono_byName() {
+        Chrono<JapaneseChrono> c = JapaneseChrono.INSTANCE;
+        Chrono<?> test = Chrono.of("Japanese");
+        Assert.assertNotNull(test, "The Japanese calendar could not be found byName");
+        Assert.assertEquals(test.getId(), "Japanese", "ID mismatch");
+        Assert.assertEquals(test.getCalendarType(), "japanese", "Type mismatch");
+        Assert.assertEquals(test, c);
+    }
+
+    //-----------------------------------------------------------------------
+    // creation, toLocalDate()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="samples")
+    Object[][] data_samples() {
+        return new Object[][] {
+            {JapaneseChrono.INSTANCE.date(1, 1, 1), LocalDate.of(1, 1, 1)},
+            {JapaneseChrono.INSTANCE.date(1, 1, 2), LocalDate.of(1, 1, 2)},
+            {JapaneseChrono.INSTANCE.date(1, 1, 3), LocalDate.of(1, 1, 3)},
+
+            {JapaneseChrono.INSTANCE.date(2, 1, 1), LocalDate.of(2, 1, 1)},
+            {JapaneseChrono.INSTANCE.date(3, 1, 1), LocalDate.of(3, 1, 1)},
+            {JapaneseChrono.INSTANCE.date(3, 12, 6), LocalDate.of(3, 12, 6)},
+            {JapaneseChrono.INSTANCE.date(4, 1, 1), LocalDate.of(4, 1, 1)},
+            {JapaneseChrono.INSTANCE.date(4, 7, 3), LocalDate.of(4, 7, 3)},
+            {JapaneseChrono.INSTANCE.date(4, 7, 4), LocalDate.of(4, 7, 4)},
+            {JapaneseChrono.INSTANCE.date(5, 1, 1), LocalDate.of(5, 1, 1)},
+            {JapaneseChrono.INSTANCE.date(1662, 3, 3), LocalDate.of(1662, 3, 3)},
+            {JapaneseChrono.INSTANCE.date(1728, 10, 28), LocalDate.of(1728, 10, 28)},
+            {JapaneseChrono.INSTANCE.date(1728, 10, 29), LocalDate.of(1728, 10, 29)},
+        };
+    }
+
+    @Test(dataProvider="samples", groups={"tck"})
+    public void test_toLocalDate(ChronoLocalDate<JapaneseChrono> jdate, LocalDate iso) {
+        assertEquals(LocalDate.from(jdate), iso);
+    }
+
+    @Test(dataProvider="samples", groups={"tck"})
+    public void test_fromCalendrical(ChronoLocalDate<JapaneseChrono> jdate, LocalDate iso) {
+        assertEquals(JapaneseChrono.INSTANCE.date(iso), jdate);
+    }
+
+    @DataProvider(name="badDates")
+    Object[][] data_badDates() {
+        return new Object[][] {
+            {1728, 0, 0},
+
+            {1728, -1, 1},
+            {1728, 0, 1},
+            {1728, 14, 1},
+            {1728, 15, 1},
+
+            {1728, 1, -1},
+            {1728, 1, 0},
+            {1728, 1, 32},
+
+            {1728, 12, -1},
+            {1728, 12, 0},
+            {1728, 12, 32},
+        };
+    }
+
+    @Test(dataProvider="badDates", groups={"tck"}, expectedExceptions=DateTimeException.class)
+    public void test_badDates(int year, int month, int dom) {
+        JapaneseChrono.INSTANCE.date(year, month, dom);
+    }
+
+    //-----------------------------------------------------------------------
+    // with(WithAdjuster)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_adjust1() {
+        ChronoLocalDate<JapaneseChrono> base = JapaneseChrono.INSTANCE.date(1728, 10, 29);
+        ChronoLocalDate<JapaneseChrono> test = base.with(Adjusters.lastDayOfMonth());
+        assertEquals(test, JapaneseChrono.INSTANCE.date(1728, 10, 31));
+    }
+
+    @Test(groups={"tck"})
+    public void test_adjust2() {
+        ChronoLocalDate<JapaneseChrono> base = JapaneseChrono.INSTANCE.date(1728, 12, 2);
+        ChronoLocalDate<JapaneseChrono> test = base.with(Adjusters.lastDayOfMonth());
+        assertEquals(test, JapaneseChrono.INSTANCE.date(1728, 12, 31));
+    }
+
+    //-----------------------------------------------------------------------
+    // JapaneseDate.with(Local*)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_adjust_toLocalDate() {
+        ChronoLocalDate<JapaneseChrono> jdate = JapaneseChrono.INSTANCE.date(1726, 1, 4);
+        ChronoLocalDate<JapaneseChrono> test = jdate.with(LocalDate.of(2012, 7, 6));
+        assertEquals(test, JapaneseChrono.INSTANCE.date(2012, 7, 6));
+    }
+
+    @Test(groups={"tck"}, expectedExceptions=DateTimeException.class)
+    public void test_adjust_toMonth() {
+        ChronoLocalDate<?> jdate = JapaneseChrono.INSTANCE.date(1726, 1, 4);
+        jdate.with(Month.APRIL);
+    }
+
+    //-----------------------------------------------------------------------
+    // LocalDate.with(JapaneseDate)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_LocalDate_adjustToJapaneseDate() {
+        ChronoLocalDate<JapaneseChrono> jdate = JapaneseChrono.INSTANCE.date(1728, 10, 29);
+        LocalDate test = LocalDate.MIN.with(jdate);
+        assertEquals(test, LocalDate.of(1728, 10, 29));
+    }
+
+    @Test(groups={"tck"})
+    public void test_LocalDateTime_adjustToJapaneseDate() {
+        ChronoLocalDate<JapaneseChrono> jdate = JapaneseChrono.INSTANCE.date(1728, 10, 29);
+        LocalDateTime test = LocalDateTime.MIN.with(jdate);
+        assertEquals(test, LocalDateTime.of(1728, 10, 29, 0, 0));
+    }
+
+    //-----------------------------------------------------------------------
+    // Check Japanese Eras
+    //-----------------------------------------------------------------------
+    @DataProvider(name="japaneseEras")
+    Object[][] data_japanseseEras() {
+        return new Object[][] {
+            { JapaneseChrono.ERA_SEIREKI, -999, "Seireki"},
+            { JapaneseChrono.ERA_MEIJI, -1, "Meiji"},
+            { JapaneseChrono.ERA_TAISHO, 0, "Taisho"},
+            { JapaneseChrono.ERA_SHOWA, 1, "Showa"},
+            { JapaneseChrono.ERA_HEISEI, 2, "Heisei"},
+        };
+    }
+
+    @Test(groups={"tck"}, dataProvider="japaneseEras")
+    public void test_Japanese_Eras(Era era, int eraValue, String name) {
+        assertEquals(era.getValue(), eraValue, "EraValue");
+        assertEquals(era.toString(), name, "Era Name");
+        assertEquals(era, JapaneseChrono.INSTANCE.eraOf(eraValue), "JapaneseChrono.eraOf()");
+        List<Era<JapaneseChrono>> eras = JapaneseChrono.INSTANCE.eras();
+        assertTrue(eras.contains(era), "Era is not present in JapaneseChrono.INSTANCE.eras()");
+    }
+
+    @Test(groups="tck")
+    public void test_Japanese_badEras() {
+        int badEras[] = {-1000, -998, -997, -2, 3, 4, 1000};
+        for (int badEra : badEras) {
+            try {
+                Era<JapaneseChrono> era = JapaneseChrono.INSTANCE.eraOf(badEra);
+                fail("JapaneseChrono.eraOf returned " + era + " + for invalid eraValue " + badEra);
+            } catch (DateTimeException ex) {
+                // ignore expected exception
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // toString()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="toString")
+    Object[][] data_toString() {
+        return new Object[][] {
+            {JapaneseChrono.INSTANCE.date(0001,  1,  1), "Japanese 0001-01-01"},
+            {JapaneseChrono.INSTANCE.date(1728, 10, 28), "Japanese 1728-10-28"},
+            {JapaneseChrono.INSTANCE.date(1728, 10, 29), "Japanese 1728-10-29"},
+            {JapaneseChrono.INSTANCE.date(1727, 12,  5), "Japanese 1727-12-05"},
+            {JapaneseChrono.INSTANCE.date(1727, 12,  6), "Japanese 1727-12-06"},
+            {JapaneseChrono.INSTANCE.date(1868,  9,  8), "Japanese Meiji 1-09-08"},
+            {JapaneseChrono.INSTANCE.date(1912,  7, 29), "Japanese Meiji 45-07-29"},
+            {JapaneseChrono.INSTANCE.date(1912,  7, 30), "Japanese Taisho 1-07-30"},
+            {JapaneseChrono.INSTANCE.date(1926, 12, 24), "Japanese Taisho 15-12-24"},
+            {JapaneseChrono.INSTANCE.date(1926, 12, 25), "Japanese Showa 1-12-25"},
+            {JapaneseChrono.INSTANCE.date(1989,  1,  7), "Japanese Showa 64-01-07"},
+            {JapaneseChrono.INSTANCE.date(1989,  1,  8), "Japanese Heisei 1-01-08"},
+            {JapaneseChrono.INSTANCE.date(2012, 12,  6), "Japanese Heisei 24-12-06"},
+        };
+    }
+
+    @Test(dataProvider="toString", groups={"tck"})
+    public void test_toString(ChronoLocalDate<JapaneseChrono> jdate, String expected) {
+        assertEquals(jdate.toString(), expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // equals()
+    //-----------------------------------------------------------------------
+    @Test(groups="tck")
+    public void test_equals_true() {
+        assertTrue(JapaneseChrono.INSTANCE.equals(JapaneseChrono.INSTANCE));
+    }
+
+    @Test(groups="tck")
+    public void test_equals_false() {
+        assertFalse(JapaneseChrono.INSTANCE.equals(ISOChrono.INSTANCE));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/calendar/TestMinguoChrono.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.calendar;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.Month;
+import java.time.ZoneOffset;
+import java.time.calendar.MinguoChrono;
+import java.time.temporal.Adjusters;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.ChronoZonedDateTime;
+import java.time.temporal.Chrono;
+import java.time.temporal.ChronoLocalDate;
+import java.time.temporal.ChronoLocalDateTime;
+import java.time.temporal.ISOChrono;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test.
+ */
+@Test
+public class TestMinguoChrono {
+
+    //-----------------------------------------------------------------------
+    // Chrono.ofName("Minguo")  Lookup by name
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_chrono_byName() {
+        Chrono<MinguoChrono> c = MinguoChrono.INSTANCE;
+        Chrono<?> test = Chrono.of("Minguo");
+        Assert.assertNotNull(test, "The Minguo calendar could not be found byName");
+        Assert.assertEquals(test.getId(), "Minguo", "ID mismatch");
+        Assert.assertEquals(test.getCalendarType(), "roc", "Type mismatch");
+        Assert.assertEquals(test, c);
+    }
+
+    //-----------------------------------------------------------------------
+    // creation, toLocalDate()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="samples")
+    Object[][] data_samples() {
+        return new Object[][] {
+            {MinguoChrono.INSTANCE.date(1, 1, 1), LocalDate.of(1912, 1, 1)},
+            {MinguoChrono.INSTANCE.date(1, 1, 2), LocalDate.of(1912, 1, 2)},
+            {MinguoChrono.INSTANCE.date(1, 1, 3), LocalDate.of(1912, 1, 3)},
+
+            {MinguoChrono.INSTANCE.date(2, 1, 1), LocalDate.of(1913, 1, 1)},
+            {MinguoChrono.INSTANCE.date(3, 1, 1), LocalDate.of(1914, 1, 1)},
+            {MinguoChrono.INSTANCE.date(3, 12, 6), LocalDate.of(1914, 12, 6)},
+            {MinguoChrono.INSTANCE.date(4, 1, 1), LocalDate.of(1915, 1, 1)},
+            {MinguoChrono.INSTANCE.date(4, 7, 3), LocalDate.of(1915, 7, 3)},
+            {MinguoChrono.INSTANCE.date(4, 7, 4), LocalDate.of(1915, 7, 4)},
+            {MinguoChrono.INSTANCE.date(5, 1, 1), LocalDate.of(1916, 1, 1)},
+            {MinguoChrono.INSTANCE.date(100, 3, 3), LocalDate.of(2011, 3, 3)},
+            {MinguoChrono.INSTANCE.date(101, 10, 28), LocalDate.of(2012, 10, 28)},
+            {MinguoChrono.INSTANCE.date(101, 10, 29), LocalDate.of(2012, 10, 29)},
+        };
+    }
+
+    @Test(dataProvider="samples", groups={"tck"})
+    public void test_toLocalDate(ChronoLocalDate<MinguoChrono> minguo, LocalDate iso) {
+        assertEquals(LocalDate.from(minguo), iso);
+    }
+
+    @Test(dataProvider="samples", groups={"tck"})
+    public void test_fromCalendrical(ChronoLocalDate<MinguoChrono> minguo, LocalDate iso) {
+        assertEquals(MinguoChrono.INSTANCE.date(iso), minguo);
+    }
+
+    @SuppressWarnings("unused")
+    @Test(dataProvider="samples", groups={"implementation"})
+    public void test_MinguoDate(ChronoLocalDate<MinguoChrono> minguoDate, LocalDate iso) {
+        ChronoLocalDate<MinguoChrono> hd = minguoDate;
+        ChronoLocalDateTime<MinguoChrono> hdt = hd.atTime(LocalTime.NOON);
+        ZoneOffset zo = ZoneOffset.ofHours(1);
+        ChronoZonedDateTime<MinguoChrono> hzdt = hdt.atZone(zo);
+        hdt = hdt.plus(1, ChronoUnit.YEARS);
+        hdt = hdt.plus(1, ChronoUnit.MONTHS);
+        hdt = hdt.plus(1, ChronoUnit.DAYS);
+        hdt = hdt.plus(1, ChronoUnit.HOURS);
+        hdt = hdt.plus(1, ChronoUnit.MINUTES);
+        hdt = hdt.plus(1, ChronoUnit.SECONDS);
+        hdt = hdt.plus(1, ChronoUnit.NANOS);
+        ChronoLocalDateTime<MinguoChrono> a2 = hzdt.getDateTime();
+        ChronoLocalDate<MinguoChrono> a3 = a2.getDate();
+        ChronoLocalDate<MinguoChrono> a5 = hzdt.getDate();
+        //System.out.printf(" d: %s, dt: %s; odt: %s; zodt: %s; a4: %s%n", date, hdt, hodt, hzdt, a5);
+    }
+
+    @Test()
+    public void test_MinguoChrono() {
+        ChronoLocalDate<MinguoChrono> h1 = MinguoChrono.ERA_ROC.date(1, 2, 3);
+        ChronoLocalDate<MinguoChrono> h2 = h1;
+        ChronoLocalDateTime<MinguoChrono> h3 = h2.atTime(LocalTime.NOON);
+        @SuppressWarnings("unused")
+        ChronoZonedDateTime<MinguoChrono> h4 = h3.atZone(ZoneOffset.UTC);
+    }
+
+    @DataProvider(name="badDates")
+    Object[][] data_badDates() {
+        return new Object[][] {
+            {1912, 0, 0},
+
+            {1912, -1, 1},
+            {1912, 0, 1},
+            {1912, 14, 1},
+            {1912, 15, 1},
+
+            {1912, 1, -1},
+            {1912, 1, 0},
+            {1912, 1, 32},
+            {1912, 2, 29},
+            {1912, 2, 30},
+
+            {1912, 12, -1},
+            {1912, 12, 0},
+            {1912, 12, 32},
+            };
+    }
+
+    @Test(dataProvider="badDates", groups={"tck"}, expectedExceptions=DateTimeException.class)
+    public void test_badDates(int year, int month, int dom) {
+        MinguoChrono.INSTANCE.date(year, month, dom);
+    }
+
+    //-----------------------------------------------------------------------
+    // with(DateTimeAdjuster)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_adjust1() {
+        ChronoLocalDate<MinguoChrono> base = MinguoChrono.INSTANCE.date(2012, 10, 29);
+        ChronoLocalDate<MinguoChrono> test = base.with(Adjusters.lastDayOfMonth());
+        assertEquals(test, MinguoChrono.INSTANCE.date(2012, 10, 31));
+    }
+
+    @Test(groups={"tck"})
+    public void test_adjust2() {
+        ChronoLocalDate<MinguoChrono> base = MinguoChrono.INSTANCE.date(1728, 12, 2);
+        ChronoLocalDate<MinguoChrono> test = base.with(Adjusters.lastDayOfMonth());
+        assertEquals(test, MinguoChrono.INSTANCE.date(1728, 12, 31));
+    }
+
+    //-----------------------------------------------------------------------
+    // MinguoDate.with(Local*)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_adjust_toLocalDate() {
+        ChronoLocalDate<MinguoChrono> minguo = MinguoChrono.INSTANCE.date(99, 1, 4);
+        ChronoLocalDate<MinguoChrono> test = minguo.with(LocalDate.of(2012, 7, 6));
+        assertEquals(test, MinguoChrono.INSTANCE.date(101, 7, 6));
+    }
+
+    @Test(groups={"tck"}, expectedExceptions=DateTimeException.class)
+    public void test_adjust_toMonth() {
+        ChronoLocalDate<MinguoChrono> minguo = MinguoChrono.INSTANCE.date(1726, 1, 4);
+        minguo.with(Month.APRIL);
+    }
+
+    //-----------------------------------------------------------------------
+    // LocalDate.with(MinguoDate)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_LocalDate_adjustToMinguoDate() {
+        ChronoLocalDate<MinguoChrono> minguo = MinguoChrono.INSTANCE.date(101, 10, 29);
+        LocalDate test = LocalDate.MIN.with(minguo);
+        assertEquals(test, LocalDate.of(2012, 10, 29));
+    }
+
+    @Test(groups={"tck"})
+    public void test_LocalDateTime_adjustToMinguoDate() {
+        ChronoLocalDate<MinguoChrono> minguo = MinguoChrono.INSTANCE.date(101, 10, 29);
+        LocalDateTime test = LocalDateTime.MIN.with(minguo);
+        assertEquals(test, LocalDateTime.of(2012, 10, 29, 0, 0));
+    }
+
+    //-----------------------------------------------------------------------
+    // toString()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="toString")
+    Object[][] data_toString() {
+        return new Object[][] {
+            {MinguoChrono.INSTANCE.date(1, 1, 1), "Minguo ROC 1-01-01"},
+            {MinguoChrono.INSTANCE.date(1728, 10, 28), "Minguo ROC 1728-10-28"},
+            {MinguoChrono.INSTANCE.date(1728, 10, 29), "Minguo ROC 1728-10-29"},
+            {MinguoChrono.INSTANCE.date(1727, 12, 5), "Minguo ROC 1727-12-05"},
+            {MinguoChrono.INSTANCE.date(1727, 12, 6), "Minguo ROC 1727-12-06"},
+        };
+    }
+
+    @Test(dataProvider="toString", groups={"tck"})
+    public void test_toString(ChronoLocalDate<MinguoChrono> minguo, String expected) {
+        assertEquals(minguo.toString(), expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // equals()
+    //-----------------------------------------------------------------------
+    @Test(groups="tck")
+    public void test_equals_true() {
+        assertTrue(MinguoChrono.INSTANCE.equals(MinguoChrono.INSTANCE));
+    }
+
+    @Test(groups="tck")
+    public void test_equals_false() {
+        assertFalse(MinguoChrono.INSTANCE.equals(ISOChrono.INSTANCE));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/calendar/TestServiceLoader.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,106 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.calendar;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.fail;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.ServiceLoader;
+import java.time.LocalDate;
+import java.time.temporal.Chrono;
+import java.time.temporal.ChronoLocalDate;
+import java.time.temporal.ISOChrono;
+import java.time.DateTimeException;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ * Tests that a custom Chronology is available via the ServiceLoader.
+ * The CopticChrono is configured via META-INF/services/java.time.temporal.Chrono.
+ */
+@Test
+public class TestServiceLoader {
+
+     @Test(groups={"tck"})
+     public void test_CopticServiceLoader() {
+        Chrono chrono = Chrono.of("Coptic");
+        ChronoLocalDate<?> copticDate = chrono.date(1729, 4, 27);
+        LocalDate ld = LocalDate.from(copticDate);
+        assertEquals(ld, LocalDate.of(2013, 1, 5), "CopticDate does not match LocalDate");
+    }
+
+    @Test(groups="implementation")
+    public void test_copticServiceLoader() {
+        Map<String, Chrono> chronos = new HashMap<>();
+        ServiceLoader<Chrono> loader = ServiceLoader.load(Chrono.class, null);
+        for (Chrono<?> chrono : loader) {
+            chronos.put(chrono.getId(), chrono);
+        }
+        assertNotNull(chronos.get("Coptic"), "CopticChrono not found");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/calendar/TestThaiBuddhistChrono.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.calendar;
+
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.DAY_OF_YEAR;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.YEAR;
+import static java.time.temporal.ChronoField.YEAR_OF_ERA;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.Month;
+import java.time.calendar.ThaiBuddhistChrono;
+import java.time.temporal.Chrono;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoLocalDate;
+import java.time.temporal.Adjusters;
+import java.time.temporal.ValueRange;
+import java.time.temporal.ISOChrono;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test.
+ */
+@Test
+public class TestThaiBuddhistChrono {
+
+    private static final int YDIFF = 543;
+
+    //-----------------------------------------------------------------------
+    // Chrono.ofName("ThaiBuddhist")  Lookup by name
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_chrono_byName() {
+        Chrono<ThaiBuddhistChrono> c = ThaiBuddhistChrono.INSTANCE;
+        Chrono<?> test = Chrono.of("ThaiBuddhist");
+        Assert.assertNotNull(test, "The ThaiBuddhist calendar could not be found byName");
+        Assert.assertEquals(test.getId(), "ThaiBuddhist", "ID mismatch");
+        Assert.assertEquals(test.getCalendarType(), "buddhist", "Type mismatch");
+        Assert.assertEquals(test, c);
+    }
+
+    //-----------------------------------------------------------------------
+    // creation, toLocalDate()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="samples")
+    Object[][] data_samples() {
+        return new Object[][] {
+            {ThaiBuddhistChrono.INSTANCE.date(1 + YDIFF, 1, 1), LocalDate.of(1, 1, 1)},
+            {ThaiBuddhistChrono.INSTANCE.date(1 + YDIFF, 1, 2), LocalDate.of(1, 1, 2)},
+            {ThaiBuddhistChrono.INSTANCE.date(1 + YDIFF, 1, 3), LocalDate.of(1, 1, 3)},
+
+            {ThaiBuddhistChrono.INSTANCE.date(2 + YDIFF, 1, 1), LocalDate.of(2, 1, 1)},
+            {ThaiBuddhistChrono.INSTANCE.date(3 + YDIFF, 1, 1), LocalDate.of(3, 1, 1)},
+            {ThaiBuddhistChrono.INSTANCE.date(3 + YDIFF, 12, 6), LocalDate.of(3, 12, 6)},
+            {ThaiBuddhistChrono.INSTANCE.date(4 + YDIFF, 1, 1), LocalDate.of(4, 1, 1)},
+            {ThaiBuddhistChrono.INSTANCE.date(4 + YDIFF, 7, 3), LocalDate.of(4, 7, 3)},
+            {ThaiBuddhistChrono.INSTANCE.date(4 + YDIFF, 7, 4), LocalDate.of(4, 7, 4)},
+            {ThaiBuddhistChrono.INSTANCE.date(5 + YDIFF, 1, 1), LocalDate.of(5, 1, 1)},
+            {ThaiBuddhistChrono.INSTANCE.date(1662 + YDIFF, 3, 3), LocalDate.of(1662, 3, 3)},
+            {ThaiBuddhistChrono.INSTANCE.date(1728 + YDIFF, 10, 28), LocalDate.of(1728, 10, 28)},
+            {ThaiBuddhistChrono.INSTANCE.date(1728 + YDIFF, 10, 29), LocalDate.of(1728, 10, 29)},
+            {ThaiBuddhistChrono.INSTANCE.date(2555, 8, 29), LocalDate.of(2012, 8, 29)},
+        };
+    }
+
+    @Test(dataProvider="samples", groups={"tck"})
+    public void test_toLocalDate(ChronoLocalDate<ThaiBuddhistChrono> jdate, LocalDate iso) {
+        assertEquals(LocalDate.from(jdate), iso);
+    }
+
+    @Test(dataProvider="samples", groups={"tck"})
+    public void test_fromCalendrical(ChronoLocalDate<ThaiBuddhistChrono> jdate, LocalDate iso) {
+        assertEquals(ThaiBuddhistChrono.INSTANCE.date(iso), jdate);
+    }
+
+    @DataProvider(name="badDates")
+    Object[][] data_badDates() {
+        return new Object[][] {
+            {1728, 0, 0},
+
+            {1728, -1, 1},
+            {1728, 0, 1},
+            {1728, 14, 1},
+            {1728, 15, 1},
+
+            {1728, 1, -1},
+            {1728, 1, 0},
+            {1728, 1, 32},
+
+            {1728, 12, -1},
+            {1728, 12, 0},
+            {1728, 12, 32},
+        };
+    }
+
+    @Test(dataProvider="badDates", groups={"tck"}, expectedExceptions=DateTimeException.class)
+    public void test_badDates(int year, int month, int dom) {
+        ThaiBuddhistChrono.INSTANCE.date(year, month, dom);
+    }
+
+    //-----------------------------------------------------------------------
+    // with(WithAdjuster)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_adjust1() {
+        ChronoLocalDate<ThaiBuddhistChrono> base = ThaiBuddhistChrono.INSTANCE.date(1728, 10, 29);
+        ChronoLocalDate<ThaiBuddhistChrono> test = base.with(Adjusters.lastDayOfMonth());
+        assertEquals(test, ThaiBuddhistChrono.INSTANCE.date(1728, 10, 31));
+    }
+
+    @Test(groups={"tck"})
+    public void test_adjust2() {
+        ChronoLocalDate<ThaiBuddhistChrono> base = ThaiBuddhistChrono.INSTANCE.date(1728, 12, 2);
+        ChronoLocalDate<ThaiBuddhistChrono> test = base.with(Adjusters.lastDayOfMonth());
+        assertEquals(test, ThaiBuddhistChrono.INSTANCE.date(1728, 12, 31));
+    }
+
+    //-----------------------------------------------------------------------
+    // withYear()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withYear_BE() {
+        ChronoLocalDate<ThaiBuddhistChrono> base = ThaiBuddhistChrono.INSTANCE.date(2555, 8, 29);
+        ChronoLocalDate<ThaiBuddhistChrono> test = base.with(YEAR, 2554);
+        assertEquals(test, ThaiBuddhistChrono.INSTANCE.date(2554, 8, 29));
+    }
+
+    @Test(groups={"tck"})
+    public void test_withYear_BBE() {
+        ChronoLocalDate<ThaiBuddhistChrono> base = ThaiBuddhistChrono.INSTANCE.date(-2554, 8, 29);
+        ChronoLocalDate<ThaiBuddhistChrono> test = base.with(YEAR_OF_ERA, 2554);
+        assertEquals(test, ThaiBuddhistChrono.INSTANCE.date(-2553, 8, 29));
+    }
+
+    //-----------------------------------------------------------------------
+    // withEra()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withEra_BE() {
+        ChronoLocalDate<ThaiBuddhistChrono> base = ThaiBuddhistChrono.INSTANCE.date(2555, 8, 29);
+        ChronoLocalDate<ThaiBuddhistChrono> test = base.with(ChronoField.ERA, ThaiBuddhistChrono.ERA_BE.getValue());
+        assertEquals(test, ThaiBuddhistChrono.INSTANCE.date(2555, 8, 29));
+    }
+
+    @Test(groups={"tck"})
+    public void test_withEra_BBE() {
+        ChronoLocalDate<ThaiBuddhistChrono> base = ThaiBuddhistChrono.INSTANCE.date(-2554, 8, 29);
+        ChronoLocalDate<ThaiBuddhistChrono> test = base.with(ChronoField.ERA, ThaiBuddhistChrono.ERA_BEFORE_BE.getValue());
+        assertEquals(test, ThaiBuddhistChrono.INSTANCE.date(-2554, 8, 29));
+    }
+
+    @Test(groups={"tck"})
+    public void test_withEra_swap() {
+        ChronoLocalDate<ThaiBuddhistChrono> base = ThaiBuddhistChrono.INSTANCE.date(-2554, 8, 29);
+        ChronoLocalDate<ThaiBuddhistChrono> test = base.with(ChronoField.ERA, ThaiBuddhistChrono.ERA_BE.getValue());
+        assertEquals(test, ThaiBuddhistChrono.INSTANCE.date(2555, 8, 29));
+    }
+
+    //-----------------------------------------------------------------------
+    // BuddhistDate.with(Local*)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_adjust_toLocalDate() {
+        ChronoLocalDate<ThaiBuddhistChrono> jdate = ThaiBuddhistChrono.INSTANCE.date(1726, 1, 4);
+        ChronoLocalDate<ThaiBuddhistChrono> test = jdate.with(LocalDate.of(2012, 7, 6));
+        assertEquals(test, ThaiBuddhistChrono.INSTANCE.date(2555, 7, 6));
+    }
+
+    @Test(groups={"tck"}, expectedExceptions=DateTimeException.class)
+    public void test_adjust_toMonth() {
+        ChronoLocalDate<ThaiBuddhistChrono> jdate = ThaiBuddhistChrono.INSTANCE.date(1726, 1, 4);
+        jdate.with(Month.APRIL);
+    }
+
+    //-----------------------------------------------------------------------
+    // LocalDate.with(BuddhistDate)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_LocalDate_adjustToBuddhistDate() {
+        ChronoLocalDate<ThaiBuddhistChrono> jdate = ThaiBuddhistChrono.INSTANCE.date(2555, 10, 29);
+        LocalDate test = LocalDate.MIN.with(jdate);
+        assertEquals(test, LocalDate.of(2012, 10, 29));
+    }
+
+    @Test(groups={"tck"})
+    public void test_LocalDateTime_adjustToBuddhistDate() {
+        ChronoLocalDate<ThaiBuddhistChrono> jdate = ThaiBuddhistChrono.INSTANCE.date(2555, 10, 29);
+        LocalDateTime test = LocalDateTime.MIN.with(jdate);
+        assertEquals(test, LocalDateTime.of(2012, 10, 29, 0, 0));
+    }
+
+    //-----------------------------------------------------------------------
+    // toString()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="toString")
+    Object[][] data_toString() {
+        return new Object[][] {
+            {ThaiBuddhistChrono.INSTANCE.date(544, 1, 1), "ThaiBuddhist BE 544-01-01"},
+            {ThaiBuddhistChrono.INSTANCE.date(2271, 10, 28), "ThaiBuddhist BE 2271-10-28"},
+            {ThaiBuddhistChrono.INSTANCE.date(2271, 10, 29), "ThaiBuddhist BE 2271-10-29"},
+            {ThaiBuddhistChrono.INSTANCE.date(2270, 12, 5), "ThaiBuddhist BE 2270-12-05"},
+            {ThaiBuddhistChrono.INSTANCE.date(2270, 12, 6), "ThaiBuddhist BE 2270-12-06"},
+        };
+    }
+
+    @Test(dataProvider="toString", groups={"tck"})
+    public void test_toString(ChronoLocalDate<ThaiBuddhistChrono> jdate, String expected) {
+        assertEquals(jdate.toString(), expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // chronology range(ChronoField)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_Chrono_range() {
+        long minYear = LocalDate.MIN.getYear() + YDIFF;
+        long maxYear = LocalDate.MAX.getYear() + YDIFF;
+        assertEquals(ThaiBuddhistChrono.INSTANCE.range(YEAR), ValueRange.of(minYear, maxYear));
+        assertEquals(ThaiBuddhistChrono.INSTANCE.range(YEAR_OF_ERA), ValueRange.of(1, -minYear + 1, maxYear));
+
+        assertEquals(ThaiBuddhistChrono.INSTANCE.range(DAY_OF_MONTH), DAY_OF_MONTH.range());
+        assertEquals(ThaiBuddhistChrono.INSTANCE.range(DAY_OF_YEAR), DAY_OF_YEAR.range());
+        assertEquals(ThaiBuddhistChrono.INSTANCE.range(MONTH_OF_YEAR), MONTH_OF_YEAR.range());
+    }
+
+    //-----------------------------------------------------------------------
+    // equals()
+    //-----------------------------------------------------------------------
+    @Test(groups="tck")
+    public void test_equals_true() {
+        assertTrue(ThaiBuddhistChrono.INSTANCE.equals(ThaiBuddhistChrono.INSTANCE));
+    }
+
+    @Test(groups="tck")
+    public void test_equals_false() {
+        assertFalse(ThaiBuddhistChrono.INSTANCE.equals(ISOChrono.INSTANCE));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatSymbols.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.format;
+
+import java.time.format.*;
+import test.java.time.format.*;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.Locale;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test DateTimeFormatSymbols.
+ */
+@Test
+public class TCKDateTimeFormatSymbols {
+
+    @Test(groups={"tck"})
+    public void test_getAvailableLocales() {
+        Locale[] locales = DateTimeFormatSymbols.getAvailableLocales();
+        assertEquals(locales.length > 0, true);
+        assertEquals(Arrays.asList(locales).contains(Locale.US), true);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_of_Locale() {
+        DateTimeFormatSymbols loc1 = DateTimeFormatSymbols.of(Locale.CANADA);
+        assertEquals(loc1.getZeroDigit(), '0');
+        assertEquals(loc1.getPositiveSign(), '+');
+        assertEquals(loc1.getNegativeSign(), '-');
+        assertEquals(loc1.getDecimalSeparator(), '.');
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_STANDARD() {
+        DateTimeFormatSymbols loc1 = DateTimeFormatSymbols.STANDARD;
+        assertEquals(loc1.getZeroDigit(), '0');
+        assertEquals(loc1.getPositiveSign(), '+');
+        assertEquals(loc1.getNegativeSign(), '-');
+        assertEquals(loc1.getDecimalSeparator(), '.');
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_zeroDigit() {
+        DateTimeFormatSymbols base = DateTimeFormatSymbols.STANDARD;
+        assertEquals(base.withZeroDigit('A').getZeroDigit(), 'A');
+    }
+
+    @Test(groups={"tck"})
+    public void test_positiveSign() {
+        DateTimeFormatSymbols base = DateTimeFormatSymbols.STANDARD;
+        assertEquals(base.withPositiveSign('A').getPositiveSign(), 'A');
+    }
+
+    @Test(groups={"tck"})
+    public void test_negativeSign() {
+        DateTimeFormatSymbols base = DateTimeFormatSymbols.STANDARD;
+        assertEquals(base.withNegativeSign('A').getNegativeSign(), 'A');
+    }
+
+    @Test(groups={"tck"})
+    public void test_decimalSeparator() {
+        DateTimeFormatSymbols base = DateTimeFormatSymbols.STANDARD;
+        assertEquals(base.withDecimalSeparator('A').getDecimalSeparator(), 'A');
+    }
+
+    //-----------------------------------------------------------------------
+    /* TBD: convertToDigit and convertNumberToI18N are package-private methods
+    @Test(groups={"tck"})
+    public void test_convertToDigit_base() {
+        DateTimeFormatSymbols base = DateTimeFormatSymbols.STANDARD;
+        assertEquals(base.convertToDigit('0'), 0);
+        assertEquals(base.convertToDigit('1'), 1);
+        assertEquals(base.convertToDigit('9'), 9);
+        assertEquals(base.convertToDigit(' '), -1);
+        assertEquals(base.convertToDigit('A'), -1);
+    }
+
+    @Test(groups={"tck"})
+    public void test_convertToDigit_altered() {
+        DateTimeFormatSymbols base = DateTimeFormatSymbols.STANDARD.withZeroDigit('A');
+        assertEquals(base.convertToDigit('A'), 0);
+        assertEquals(base.convertToDigit('B'), 1);
+        assertEquals(base.convertToDigit('J'), 9);
+        assertEquals(base.convertToDigit(' '), -1);
+        assertEquals(base.convertToDigit('0'), -1);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_convertNumberToI18N_base() {
+        DateTimeFormatSymbols base = DateTimeFormatSymbols.STANDARD;
+        assertEquals(base.convertNumberToI18N("134"), "134");
+    }
+
+    @Test(groups={"tck"})
+    public void test_convertNumberToI18N_altered() {
+        DateTimeFormatSymbols base = DateTimeFormatSymbols.STANDARD.withZeroDigit('A');
+        assertEquals(base.convertNumberToI18N("134"), "BDE");
+    }
+    */
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_equalsHashCode1() {
+        DateTimeFormatSymbols a = DateTimeFormatSymbols.STANDARD;
+        DateTimeFormatSymbols b = DateTimeFormatSymbols.STANDARD;
+        assertEquals(a.equals(b), true);
+        assertEquals(b.equals(a), true);
+        assertEquals(a.hashCode(), b.hashCode());
+    }
+
+    @Test(groups={"tck"})
+    public void test_equalsHashCode2() {
+        DateTimeFormatSymbols a = DateTimeFormatSymbols.STANDARD.withZeroDigit('A');
+        DateTimeFormatSymbols b = DateTimeFormatSymbols.STANDARD.withZeroDigit('A');
+        assertEquals(a.equals(b), true);
+        assertEquals(b.equals(a), true);
+        assertEquals(a.hashCode(), b.hashCode());
+    }
+
+    @Test(groups={"tck"})
+    public void test_equalsHashCode3() {
+        DateTimeFormatSymbols a = DateTimeFormatSymbols.STANDARD.withZeroDigit('A');
+        DateTimeFormatSymbols b = DateTimeFormatSymbols.STANDARD.withDecimalSeparator('A');
+        assertEquals(a.equals(b), false);
+        assertEquals(b.equals(a), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equalsHashCode_bad() {
+        DateTimeFormatSymbols a = DateTimeFormatSymbols.STANDARD;
+        assertEquals(a.equals(""), false);
+        assertEquals(a.equals(null), false);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_toString_base() {
+        DateTimeFormatSymbols base = DateTimeFormatSymbols.STANDARD;
+        assertEquals(base.toString(), "Symbols[0+-.]");
+    }
+
+    @Test(groups={"tck"})
+    public void test_toString_altered() {
+        DateTimeFormatSymbols base = DateTimeFormatSymbols.of(Locale.US).withZeroDigit('A').withDecimalSeparator('@');
+        assertEquals(base.toString(), "Symbols[A+-@]");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatter.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,705 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.format;
+
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.HOUR_OF_DAY;
+import static java.time.temporal.ChronoField.YEAR;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.io.IOException;
+import java.text.Format;
+import java.text.ParseException;
+import java.text.ParsePosition;
+import java.util.Locale;
+
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.calendar.ThaiBuddhistChrono;
+import java.time.format.DateTimeFormatSymbols;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.DateTimeFormatters;
+import java.time.format.DateTimeParseException;
+import java.time.format.DateTimePrintException;
+import java.time.format.SignStyle;
+import java.time.format.DateTimeBuilder;
+import java.time.temporal.Chrono;
+import java.time.temporal.ISOChrono;
+import java.time.temporal.OffsetDate;
+import java.time.temporal.OffsetDateTime;
+import java.time.temporal.OffsetTime;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalQuery;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import test.java.time.format.MockIOExceptionAppendable;
+
+/**
+ * Test DateTimeFormatter.
+ */
+@Test(groups={"tck"})
+public class TCKDateTimeFormatter {
+
+    private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1);
+    private static final ZoneOffset OFFSET_PTHREE = ZoneOffset.ofHours(3);
+    private static final ZoneId ZONE_PARIS = ZoneId.of("Europe/Paris");
+
+    private static final DateTimeFormatter BASIC_FORMATTER = DateTimeFormatters.pattern("'ONE'd");
+    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatters.pattern("'ONE'yyyy MM dd");
+
+    private DateTimeFormatter fmt;
+
+    @BeforeMethod
+    public void setUp() {
+        fmt = new DateTimeFormatterBuilder().appendLiteral("ONE")
+                                            .appendValue(DAY_OF_MONTH, 1, 2, SignStyle.NOT_NEGATIVE)
+                                            .toFormatter();
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_withLocale() {
+        DateTimeFormatter base = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        DateTimeFormatter test = base.withLocale(Locale.GERMAN);
+        assertEquals(test.getLocale(), Locale.GERMAN);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_withLocale_null() {
+        DateTimeFormatter base = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        base.withLocale((Locale) null);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_withChrono() {
+        DateTimeFormatter test = fmt;
+        assertEquals(test.getChrono(), null);
+        test = test.withChrono(ISOChrono.INSTANCE);
+        assertEquals(test.getChrono(), ISOChrono.INSTANCE);
+        test = test.withChrono(null);
+        assertEquals(test.getChrono(), null);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_withZone() {
+        DateTimeFormatter test = fmt;
+        assertEquals(test.getZone(), null);
+        test = test.withZone(ZoneId.of("Europe/Paris"));
+        assertEquals(test.getZone(), ZoneId.of("Europe/Paris"));
+        test = test.withZone(ZoneOffset.UTC);
+        assertEquals(test.getZone(), ZoneOffset.UTC);
+        test = test.withZone(null);
+        assertEquals(test.getZone(), null);
+    }
+
+    //-----------------------------------------------------------------------
+    // print
+    //-----------------------------------------------------------------------
+    @DataProvider(name="print")
+    Object[][] data_print() {
+        LocalDate ld = LocalDate.of(2008, 6, 30);
+        LocalTime lt = LocalTime.of(11, 30);
+        LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 11, 30);
+        OffsetDate od = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE);
+        OffsetTime ot = OffsetTime.of(LocalTime.of(11, 30), OFFSET_PONE);
+        OffsetDateTime odt = OffsetDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 30), OFFSET_PONE);
+        ZonedDateTime zdt = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 30), ZONE_PARIS);
+        Instant instant = Instant.ofEpochSecond(3600);
+        return new Object[][] {
+                {null, null, ld, "2008::"},
+                {null, null, lt, ":11:"},
+                {null, null, ldt, "2008:11:"},
+                {null, null, od, "2008::+01:00"},
+                {null, null, ot, ":11:+01:00"},
+                {null, null, odt, "2008:11:+01:00"},
+                {null, null, zdt, "2008:11:+02:00Europe/Paris"},
+                {null, null, instant, "::"},
+
+                {null, ZONE_PARIS, ld, "2008::"},
+                {null, ZONE_PARIS, lt, ":11:"},
+                {null, ZONE_PARIS, ldt, "2008:11:"},
+                {null, ZONE_PARIS, od, "2008::+01:00"},
+                {null, ZONE_PARIS, ot, ":11:+01:00"},
+                {null, ZONE_PARIS, odt, "2008:12:+02:00Europe/Paris"},
+                {null, ZONE_PARIS, zdt, "2008:11:+02:00Europe/Paris"},
+                {null, ZONE_PARIS, instant, "1970:02:+01:00Europe/Paris"},
+
+                {null, OFFSET_PTHREE, ld, "2008::"},
+                {null, OFFSET_PTHREE, lt, ":11:"},
+                {null, OFFSET_PTHREE, ldt, "2008:11:"},
+                {null, OFFSET_PTHREE, od, "2008::+01:00"},
+                {null, OFFSET_PTHREE, ot, ":11:+01:00"},
+                {null, OFFSET_PTHREE, odt, "2008:13:+03:00"},
+                {null, OFFSET_PTHREE, zdt, "2008:12:+03:00"},
+                {null, OFFSET_PTHREE, instant, "1970:04:+03:00"},
+
+                {ThaiBuddhistChrono.INSTANCE, null, ld, "2551::"},
+                {ThaiBuddhistChrono.INSTANCE, null, lt, ":11:"},
+                {ThaiBuddhistChrono.INSTANCE, null, ldt, "2551:11:"},
+                {ThaiBuddhistChrono.INSTANCE, null, od, "2551::+01:00"},
+                {ThaiBuddhistChrono.INSTANCE, null, ot, ":11:+01:00"},
+                {ThaiBuddhistChrono.INSTANCE, null, odt, "2551:11:+01:00"},
+                {ThaiBuddhistChrono.INSTANCE, null, zdt, "2551:11:+02:00Europe/Paris"},
+                {ThaiBuddhistChrono.INSTANCE, null, instant, "::"},
+
+                {ThaiBuddhistChrono.INSTANCE, ZONE_PARIS, ld, "2551::"},
+                {ThaiBuddhistChrono.INSTANCE, ZONE_PARIS, lt, ":11:"},
+                {ThaiBuddhistChrono.INSTANCE, ZONE_PARIS, ldt, "2551:11:"},
+                {ThaiBuddhistChrono.INSTANCE, ZONE_PARIS, od, "2551::+01:00"},
+                {ThaiBuddhistChrono.INSTANCE, ZONE_PARIS, ot, ":11:+01:00"},
+                {ThaiBuddhistChrono.INSTANCE, ZONE_PARIS, odt, "2551:12:+02:00Europe/Paris"},
+                {ThaiBuddhistChrono.INSTANCE, ZONE_PARIS, zdt, "2551:11:+02:00Europe/Paris"},
+                {ThaiBuddhistChrono.INSTANCE, ZONE_PARIS, instant, "1970:02:+01:00Europe/Paris"},
+        };
+    }
+
+    @Test(dataProvider="print")
+    public void test_print_Temporal(Chrono<?> overrideChrono, ZoneId overrideZone, Temporal temporal, String expected) {
+        DateTimeFormatter test = new DateTimeFormatterBuilder()
+                .optionalStart().appendValue(YEAR, 4).optionalEnd()
+                .appendLiteral(':').optionalStart().appendValue(HOUR_OF_DAY, 2).optionalEnd()
+                .appendLiteral(':').optionalStart().appendOffsetId().optionalStart().appendZoneRegionId().optionalEnd().optionalEnd()
+                .toFormatter(Locale.ENGLISH)
+                .withChrono(overrideChrono).withZone(overrideZone);
+        String result = test.print(temporal);
+        assertEquals(result, expected);
+    }
+
+    @Test
+    public void test_print_Temporal_simple() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        String result = test.print(LocalDate.of(2008, 6, 30));
+        assertEquals(result, "ONE30");
+    }
+
+    @Test(expectedExceptions=DateTimeException.class)
+    public void test_print_Temporal_noSuchField() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        test.print(LocalTime.of(11, 30));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_print_Temporal_null() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        test.print((TemporalAccessor) null);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_print_TemporalAppendable() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        StringBuilder buf = new StringBuilder();
+        test.printTo(LocalDate.of(2008, 6, 30), buf);
+        assertEquals(buf.toString(), "ONE30");
+    }
+
+    @Test(expectedExceptions=DateTimeException.class)
+    public void test_print_TemporalAppendable_noSuchField() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        StringBuilder buf = new StringBuilder();
+        test.printTo(LocalTime.of(11, 30), buf);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_print_TemporalAppendable_nullTemporal() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        StringBuilder buf = new StringBuilder();
+        test.printTo((TemporalAccessor) null, buf);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_print_TemporalAppendable_nullAppendable() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        test.printTo(LocalDate.of(2008, 6, 30), (Appendable) null);
+    }
+
+    @Test(expectedExceptions=IOException.class)  // IOException
+    public void test_print_TemporalAppendable_ioError() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        try {
+            test.printTo(LocalDate.of(2008, 6, 30), new MockIOExceptionAppendable());
+        } catch (DateTimePrintException ex) {
+            assertEquals(ex.getCause() instanceof IOException, true);
+            ex.rethrowIOException();
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // parse(Query)
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_parse_Query_String() throws Exception {
+        LocalDate result = DATE_FORMATTER.parse("ONE2012 07 27", LocalDate::from);
+        assertEquals(result, LocalDate.of(2012, 7, 27));
+    }
+
+    @Test
+    public void test_parse_Query_CharSequence() throws Exception {
+        LocalDate result = DATE_FORMATTER.parse(new StringBuilder("ONE2012 07 27"), LocalDate::from);
+        assertEquals(result, LocalDate.of(2012, 7, 27));
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class)
+    public void test_parse_Query_String_parseError() throws Exception {
+        try {
+            DATE_FORMATTER.parse("ONE2012 07 XX", LocalDate::from);
+        } catch (DateTimeParseException ex) {
+            assertEquals(ex.getMessage().contains("could not be parsed"), true);
+            assertEquals(ex.getMessage().contains("ONE2012 07 XX"), true);
+            assertEquals(ex.getParsedString(), "ONE2012 07 XX");
+            assertEquals(ex.getErrorIndex(), 11);
+            throw ex;
+        }
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class)
+    public void test_parse_Query_String_parseErrorLongText() throws Exception {
+        try {
+            DATE_FORMATTER.parse("ONEXXX67890123456789012345678901234567890123456789012345678901234567890123456789", LocalDate::from);
+        } catch (DateTimeParseException ex) {
+            assertEquals(ex.getMessage().contains("could not be parsed"), true);
+            assertEquals(ex.getMessage().contains("ONEXXX6789012345678901234567890123456789012345678901234567890123..."), true);
+            assertEquals(ex.getParsedString(), "ONEXXX67890123456789012345678901234567890123456789012345678901234567890123456789");
+            assertEquals(ex.getErrorIndex(), 3);
+            throw ex;
+        }
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class)
+    public void test_parse_Query_String_parseIncomplete() throws Exception {
+        try {
+            DATE_FORMATTER.parse("ONE2012 07 27SomethingElse", LocalDate::from);
+        } catch (DateTimeParseException ex) {
+            assertEquals(ex.getMessage().contains("could not be parsed"), true);
+            assertEquals(ex.getMessage().contains("ONE2012 07 27SomethingElse"), true);
+            assertEquals(ex.getParsedString(), "ONE2012 07 27SomethingElse");
+            assertEquals(ex.getErrorIndex(), 13);
+            throw ex;
+        }
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_parse_Query_String_nullText() throws Exception {
+        DATE_FORMATTER.parse((String) null, LocalDate::from);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_parse_Query_String_nullRule() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        test.parse("30", (TemporalQuery<?>) null);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_parseBest_firstOption() throws Exception {
+        DateTimeFormatter test = DateTimeFormatters.pattern("yyyy-MM-dd[ZZZ]");
+        TemporalAccessor result = test.parseBest("2011-06-30+03:00", OffsetDate::from, LocalDate::from);
+        assertEquals(result, OffsetDate.of(LocalDate.of(2011, 6, 30), ZoneOffset.ofHours(3)));
+    }
+
+    @Test
+    public void test_parseBest_secondOption() throws Exception {
+        DateTimeFormatter test = DateTimeFormatters.pattern("yyyy-MM-dd[ZZZ]");
+        TemporalAccessor result = test.parseBest("2011-06-30", OffsetDate::from, LocalDate::from);
+        assertEquals(result, LocalDate.of(2011, 6, 30));
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class)
+    public void test_parseBest_String_parseError() throws Exception {
+        DateTimeFormatter test = DateTimeFormatters.pattern("yyyy-MM-dd[ZZZ]");
+        try {
+            test.parseBest("2011-06-XX", OffsetDate::from, LocalDate::from);
+        } catch (DateTimeParseException ex) {
+            assertEquals(ex.getMessage().contains("could not be parsed"), true);
+            assertEquals(ex.getMessage().contains("XX"), true);
+            assertEquals(ex.getParsedString(), "2011-06-XX");
+            assertEquals(ex.getErrorIndex(), 8);
+            throw ex;
+        }
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class)
+    public void test_parseBest_String_parseErrorLongText() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        try {
+            test.parseBest("ONEXXX67890123456789012345678901234567890123456789012345678901234567890123456789", LocalDate::from, OffsetDate::from);
+        } catch (DateTimeParseException ex) {
+            assertEquals(ex.getMessage().contains("could not be parsed"), true);
+            assertEquals(ex.getMessage().contains("ONEXXX6789012345678901234567890123456789012345678901234567890123..."), true);
+            assertEquals(ex.getParsedString(), "ONEXXX67890123456789012345678901234567890123456789012345678901234567890123456789");
+            assertEquals(ex.getErrorIndex(), 3);
+            throw ex;
+        }
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class)
+    public void test_parseBest_String_parseIncomplete() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        try {
+            test.parseBest("ONE30SomethingElse", LocalDate::from, OffsetDate::from);
+        } catch (DateTimeParseException ex) {
+            assertEquals(ex.getMessage().contains("could not be parsed"), true);
+            assertEquals(ex.getMessage().contains("ONE30SomethingElse"), true);
+            assertEquals(ex.getParsedString(), "ONE30SomethingElse");
+            assertEquals(ex.getErrorIndex(), 5);
+            throw ex;
+        }
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_parseBest_String_nullText() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        test.parseBest((String) null, LocalDate::from, OffsetDate::from);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_parseBest_String_nullRules() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        test.parseBest("30", (TemporalQuery<?>[]) null);
+    }
+
+    @Test(expectedExceptions=IllegalArgumentException.class)
+    public void test_parseBest_String_zeroRules() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        test.parseBest("30", new TemporalQuery<?>[0]);
+    }
+
+    @Test(expectedExceptions=IllegalArgumentException.class)
+    public void test_parseBest_String_oneRule() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        test.parseBest("30", LocalDate::from);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_parseToBuilder_String() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        DateTimeBuilder result = test.parseToBuilder("ONE30");
+        assertEquals(result.getFieldValueMap().size(), 1);
+        assertEquals(result.getFieldValue(DAY_OF_MONTH), 30L);
+        assertEquals(result.getCalendricalList().size(), 0);
+    }
+
+    @Test
+    public void test_parseToBuilder_CharSequence() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        DateTimeBuilder result = test.parseToBuilder(new StringBuilder("ONE30"));
+        assertEquals(result.getFieldValueMap().size(), 1);
+        assertEquals(result.getFieldValue(DAY_OF_MONTH), 30L);
+        assertEquals(result.getCalendricalList().size(), 0);
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class)
+    public void test_parseToBuilder_String_parseError() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        try {
+            test.parseToBuilder("ONEXXX");
+        } catch (DateTimeParseException ex) {
+            assertEquals(ex.getMessage().contains("ONEXXX"), true);
+            assertEquals(ex.getParsedString(), "ONEXXX");
+            assertEquals(ex.getErrorIndex(), 3);
+            throw ex;
+        }
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class)
+    public void test_parseToBuilder_String_parseErrorLongText() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        try {
+            test.parseToBuilder("ONEXXX67890123456789012345678901234567890123456789012345678901234567890123456789");
+        } catch (DateTimeParseException ex) {
+            assertEquals(ex.getMessage().contains("ONEXXX6789012345678901234567890123456789012345678901234567890123..."), true);
+            assertEquals(ex.getParsedString(), "ONEXXX67890123456789012345678901234567890123456789012345678901234567890123456789");
+            assertEquals(ex.getErrorIndex(), 3);
+            throw ex;
+        }
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class)
+    public void test_parseToBuilder_String_parseIncomplete() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        try {
+            test.parseToBuilder("ONE30SomethingElse");
+        } catch (DateTimeParseException ex) {
+            assertEquals(ex.getMessage().contains("ONE30SomethingElse"), true);
+            assertEquals(ex.getParsedString(), "ONE30SomethingElse");
+            assertEquals(ex.getErrorIndex(), 5);
+            throw ex;
+        }
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_parseToBuilder_String_null() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        test.parseToBuilder((String) null);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_parseToBuilder_StringParsePosition() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        ParsePosition pos = new ParsePosition(0);
+        DateTimeBuilder result = test.parseToBuilder("ONE30XXX", pos);
+        assertEquals(pos.getIndex(), 5);
+        assertEquals(pos.getErrorIndex(), -1);
+        assertEquals(result.getFieldValueMap().size(), 1);
+        assertEquals(result.getFieldValueMap().get(DAY_OF_MONTH), Long.valueOf(30));
+    }
+
+    @Test
+    public void test_parseToBuilder_StringParsePosition_parseError() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        ParsePosition pos = new ParsePosition(0);
+        DateTimeBuilder result = test.parseToBuilder("ONEXXX", pos);
+        assertEquals(pos.getIndex(), 0);  // TODO: is this right?
+        assertEquals(pos.getErrorIndex(), 3);
+        assertEquals(result, null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_parseToBuilder_StringParsePosition_nullString() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        ParsePosition pos = new ParsePosition(0);
+        test.parseToBuilder((String) null, pos);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_parseToBuilder_StringParsePosition_nullParsePosition() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        test.parseToBuilder("ONE30", (ParsePosition) null);
+    }
+
+    @Test(expectedExceptions=IndexOutOfBoundsException.class)
+    public void test_parseToBuilder_StringParsePosition_invalidPosition() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        ParsePosition pos = new ParsePosition(6);
+        test.parseToBuilder("ONE30", pos);
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_toFormat_format() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        Format format = test.toFormat();
+        String result = format.format(LocalDate.of(2008, 6, 30));
+        assertEquals(result, "ONE30");
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_toFormat_format_null() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        Format format = test.toFormat();
+        format.format(null);
+    }
+
+    @Test(expectedExceptions=IllegalArgumentException.class)
+    public void test_toFormat_format_notTemporal() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        Format format = test.toFormat();
+        format.format("Not a Temporal");
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_toFormat_parseObject_String() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        Format format = test.toFormat();
+        DateTimeBuilder result = (DateTimeBuilder) format.parseObject("ONE30");
+        assertEquals(result.getFieldValueMap().size(), 1);
+        assertEquals(result.getFieldValue(DAY_OF_MONTH), 30L);
+    }
+
+    @Test(expectedExceptions=ParseException.class)
+    public void test_toFormat_parseObject_String_parseError() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        Format format = test.toFormat();
+        try {
+            format.parseObject("ONEXXX");
+        } catch (ParseException ex) {
+            assertEquals(ex.getMessage().contains("ONEXXX"), true);
+            assertEquals(ex.getErrorOffset(), 3);
+            throw ex;
+        }
+    }
+
+    @Test(expectedExceptions=ParseException.class)
+    public void test_toFormat_parseObject_String_parseErrorLongText() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        Format format = test.toFormat();
+        try {
+            format.parseObject("ONEXXX67890123456789012345678901234567890123456789012345678901234567890123456789");
+        } catch (DateTimeParseException ex) {
+            assertEquals(ex.getMessage().contains("ONEXXX6789012345678901234567890123456789012345678901234567890123..."), true);
+            assertEquals(ex.getParsedString(), "ONEXXX67890123456789012345678901234567890123456789012345678901234567890123456789");
+            assertEquals(ex.getErrorIndex(), 3);
+            throw ex;
+        }
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_toFormat_parseObject_String_null() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        Format format = test.toFormat();
+        format.parseObject((String) null);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_toFormat_parseObject_StringParsePosition() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        Format format = test.toFormat();
+        ParsePosition pos = new ParsePosition(0);
+        DateTimeBuilder result = (DateTimeBuilder) format.parseObject("ONE30XXX", pos);
+        assertEquals(pos.getIndex(), 5);
+        assertEquals(pos.getErrorIndex(), -1);
+        assertEquals(result.getFieldValueMap().size(), 1);
+        assertEquals(result.getFieldValue(DAY_OF_MONTH), 30L);
+    }
+
+    @Test
+    public void test_toFormat_parseObject_StringParsePosition_parseError() throws Exception {
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        Format format = test.toFormat();
+        ParsePosition pos = new ParsePosition(0);
+        TemporalAccessor result = (TemporalAccessor) format.parseObject("ONEXXX", pos);
+        assertEquals(pos.getIndex(), 0);  // TODO: is this right?
+        assertEquals(pos.getErrorIndex(), 3);
+        assertEquals(result, null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_toFormat_parseObject_StringParsePosition_nullString() throws Exception {
+        // SimpleDateFormat has this behavior
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        Format format = test.toFormat();
+        ParsePosition pos = new ParsePosition(0);
+        format.parseObject((String) null, pos);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_toFormat_parseObject_StringParsePosition_nullParsePosition() throws Exception {
+        // SimpleDateFormat has this behavior
+        DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        Format format = test.toFormat();
+        format.parseObject("ONE30", (ParsePosition) null);
+    }
+
+    @Test
+    public void test_toFormat_parseObject_StringParsePosition_invalidPosition_tooBig() throws Exception {
+        // SimpleDateFormat has this behavior
+        DateTimeFormatter dtf = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        ParsePosition pos = new ParsePosition(6);
+        Format test = dtf.toFormat();
+        assertNull(test.parseObject("ONE30", pos));
+        assertTrue(pos.getErrorIndex() >= 0);
+    }
+
+    @Test
+    public void test_toFormat_parseObject_StringParsePosition_invalidPosition_tooSmall() throws Exception {
+        // SimpleDateFormat throws StringIndexOutOfBoundException
+        DateTimeFormatter dtf = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD);
+        ParsePosition pos = new ParsePosition(-1);
+        Format test = dtf.toFormat();
+        assertNull(test.parseObject("ONE30", pos));
+        assertTrue(pos.getErrorIndex() >= 0);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_toFormat_Query_format() throws Exception {
+        Format format = BASIC_FORMATTER.toFormat();
+        String result = format.format(LocalDate.of(2008, 6, 30));
+        assertEquals(result, "ONE30");
+    }
+
+    @Test
+    public void test_toFormat_Query_parseObject_String() throws Exception {
+        Format format = DATE_FORMATTER.toFormat(LocalDate::from);
+        LocalDate result = (LocalDate) format.parseObject("ONE2012 07 27");
+        assertEquals(result, LocalDate.of(2012, 7, 27));
+    }
+
+    @Test(expectedExceptions=ParseException.class)
+    public void test_toFormat_parseObject_StringParsePosition_dateTimeError() throws Exception {
+        Format format = DATE_FORMATTER.toFormat(LocalDate::from);
+        format.parseObject("ONE2012 07 32");
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_toFormat_Query() throws Exception {
+        BASIC_FORMATTER.toFormat(null);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,856 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.format;
+
+import java.time.LocalDate;
+import java.time.ZoneOffset;
+import java.time.format.*;
+
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.DAY_OF_WEEK;
+import static java.time.temporal.ChronoField.MINUTE_OF_HOUR;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.YEAR;
+import static org.testng.Assert.assertEquals;
+
+import java.text.ParsePosition;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import java.time.format.DateTimeBuilder;
+import java.time.temporal.Temporal;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test DateTimeFormatterBuilder.
+ */
+@Test
+public class TCKDateTimeFormatterBuilder {
+
+    private DateTimeFormatterBuilder builder;
+
+    @BeforeMethod(groups={"tck"})
+    public void setUp() {
+        builder = new DateTimeFormatterBuilder();
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_toFormatter_empty() throws Exception {
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "");
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_parseCaseSensitive() throws Exception {
+        builder.parseCaseSensitive();
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "ParseCaseSensitive(true)");
+    }
+
+    @Test(groups={"tck"})
+    public void test_parseCaseInsensitive() throws Exception {
+        builder.parseCaseInsensitive();
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "ParseCaseSensitive(false)");
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_parseStrict() throws Exception {
+        builder.parseStrict();
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "ParseStrict(true)");
+    }
+
+    @Test(groups={"tck"})
+    public void test_parseLenient() throws Exception {
+        builder.parseLenient();
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "ParseStrict(false)");
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_appendValue_1arg() throws Exception {
+        builder.appendValue(DAY_OF_MONTH);
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "Value(DayOfMonth)");
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_appendValue_1arg_null() throws Exception {
+        builder.appendValue(null);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_appendValue_2arg() throws Exception {
+        builder.appendValue(DAY_OF_MONTH, 3);
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "Value(DayOfMonth,3)");
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_appendValue_2arg_null() throws Exception {
+        builder.appendValue(null, 3);
+    }
+
+    @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"})
+    public void test_appendValue_2arg_widthTooSmall() throws Exception {
+        builder.appendValue(DAY_OF_MONTH, 0);
+    }
+
+    @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"})
+    public void test_appendValue_2arg_widthTooBig() throws Exception {
+        builder.appendValue(DAY_OF_MONTH, 20);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_appendValue_3arg() throws Exception {
+        builder.appendValue(DAY_OF_MONTH, 2, 3, SignStyle.NORMAL);
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "Value(DayOfMonth,2,3,NORMAL)");
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_appendValue_3arg_nullField() throws Exception {
+        builder.appendValue(null, 2, 3, SignStyle.NORMAL);
+    }
+
+    @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"})
+    public void test_appendValue_3arg_minWidthTooSmall() throws Exception {
+        builder.appendValue(DAY_OF_MONTH, 0, 2, SignStyle.NORMAL);
+    }
+
+    @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"})
+    public void test_appendValue_3arg_minWidthTooBig() throws Exception {
+        builder.appendValue(DAY_OF_MONTH, 20, 2, SignStyle.NORMAL);
+    }
+
+    @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"})
+    public void test_appendValue_3arg_maxWidthTooSmall() throws Exception {
+        builder.appendValue(DAY_OF_MONTH, 2, 0, SignStyle.NORMAL);
+    }
+
+    @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"})
+    public void test_appendValue_3arg_maxWidthTooBig() throws Exception {
+        builder.appendValue(DAY_OF_MONTH, 2, 20, SignStyle.NORMAL);
+    }
+
+    @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"})
+    public void test_appendValue_3arg_maxWidthMinWidth() throws Exception {
+        builder.appendValue(DAY_OF_MONTH, 4, 2, SignStyle.NORMAL);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_appendValue_3arg_nullSignStyle() throws Exception {
+        builder.appendValue(DAY_OF_MONTH, 2, 3, null);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_appendValue_subsequent2_parse3() throws Exception {
+        builder.appendValue(MONTH_OF_YEAR, 1, 2, SignStyle.NORMAL).appendValue(DAY_OF_MONTH, 2);
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "Value(MonthOfYear,1,2,NORMAL)Value(DayOfMonth,2)");
+        DateTimeBuilder cal = f.parseToBuilder("123", new ParsePosition(0));
+        assertEquals(cal.getFieldValueMap().get(MONTH_OF_YEAR), Long.valueOf(1));
+        assertEquals(cal.getFieldValueMap().get(DAY_OF_MONTH), Long.valueOf(23));
+    }
+
+    @Test(groups={"tck"})
+    public void test_appendValue_subsequent2_parse4() throws Exception {
+        builder.appendValue(MONTH_OF_YEAR, 1, 2, SignStyle.NORMAL).appendValue(DAY_OF_MONTH, 2);
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "Value(MonthOfYear,1,2,NORMAL)Value(DayOfMonth,2)");
+        DateTimeBuilder cal = f.parseToBuilder("0123", new ParsePosition(0));
+        assertEquals(cal.getFieldValueMap().get(MONTH_OF_YEAR), Long.valueOf(1));
+        assertEquals(cal.getFieldValueMap().get(DAY_OF_MONTH), Long.valueOf(23));
+    }
+
+    @Test(groups={"tck"})
+    public void test_appendValue_subsequent2_parse5() throws Exception {
+        builder.appendValue(MONTH_OF_YEAR, 1, 2, SignStyle.NORMAL).appendValue(DAY_OF_MONTH, 2).appendLiteral('4');
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "Value(MonthOfYear,1,2,NORMAL)Value(DayOfMonth,2)'4'");
+        DateTimeBuilder cal = f.parseToBuilder("01234", new ParsePosition(0));
+        assertEquals(cal.getFieldValueMap().get(MONTH_OF_YEAR), Long.valueOf(1));
+        assertEquals(cal.getFieldValueMap().get(DAY_OF_MONTH), Long.valueOf(23));
+    }
+
+    @Test(groups={"tck"})
+    public void test_appendValue_subsequent3_parse6() throws Exception {
+        builder
+            .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
+            .appendValue(MONTH_OF_YEAR, 2)
+            .appendValue(DAY_OF_MONTH, 2);
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "Value(Year,4,10,EXCEEDS_PAD)Value(MonthOfYear,2)Value(DayOfMonth,2)");
+        DateTimeBuilder cal = f.parseToBuilder("20090630", new ParsePosition(0));
+        assertEquals(cal.getFieldValueMap().get(YEAR), Long.valueOf(2009));
+        assertEquals(cal.getFieldValueMap().get(MONTH_OF_YEAR), Long.valueOf(6));
+        assertEquals(cal.getFieldValueMap().get(DAY_OF_MONTH), Long.valueOf(30));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_appendValueReduced_null() throws Exception {
+        builder.appendValueReduced(null, 2, 2000);
+    }
+
+    @Test(groups={"tck"})
+    public void test_appendValueReduced() throws Exception {
+        builder.appendValueReduced(YEAR, 2, 2000);
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "ReducedValue(Year,2,2000)");
+        DateTimeBuilder cal = f.parseToBuilder("12", new ParsePosition(0));
+        assertEquals(cal.getFieldValueMap().get(YEAR), Long.valueOf(2012));
+    }
+
+    @Test(groups={"tck"})
+    public void test_appendValueReduced_subsequent_parse() throws Exception {
+        builder.appendValue(MONTH_OF_YEAR, 1, 2, SignStyle.NORMAL).appendValueReduced(YEAR, 2, 2000);
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "Value(MonthOfYear,1,2,NORMAL)ReducedValue(Year,2,2000)");
+        DateTimeBuilder cal = f.parseToBuilder("123", new ParsePosition(0));
+        assertEquals(cal.getFieldValueMap().get(MONTH_OF_YEAR), Long.valueOf(1));
+        assertEquals(cal.getFieldValueMap().get(YEAR), Long.valueOf(2023));
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_appendFraction_4arg() throws Exception {
+        builder.appendFraction(MINUTE_OF_HOUR, 1, 9, false);
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "Fraction(MinuteOfHour,1,9)");
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_appendFraction_4arg_nullRule() throws Exception {
+        builder.appendFraction(null, 1, 9, false);
+    }
+
+    @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"})
+    public void test_appendFraction_4arg_invalidRuleNotFixedSet() throws Exception {
+        builder.appendFraction(DAY_OF_MONTH, 1, 9, false);
+    }
+
+    @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"})
+    public void test_appendFraction_4arg_minTooSmall() throws Exception {
+        builder.appendFraction(MINUTE_OF_HOUR, -1, 9, false);
+    }
+
+    @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"})
+    public void test_appendFraction_4arg_minTooBig() throws Exception {
+        builder.appendFraction(MINUTE_OF_HOUR, 10, 9, false);
+    }
+
+    @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"})
+    public void test_appendFraction_4arg_maxTooSmall() throws Exception {
+        builder.appendFraction(MINUTE_OF_HOUR, 0, -1, false);
+    }
+
+    @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"})
+    public void test_appendFraction_4arg_maxTooBig() throws Exception {
+        builder.appendFraction(MINUTE_OF_HOUR, 1, 10, false);
+    }
+
+    @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"})
+    public void test_appendFraction_4arg_maxWidthMinWidth() throws Exception {
+        builder.appendFraction(MINUTE_OF_HOUR, 9, 3, false);
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_appendText_1arg() throws Exception {
+        builder.appendText(MONTH_OF_YEAR);
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "Text(MonthOfYear)");
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_appendText_1arg_null() throws Exception {
+        builder.appendText(null);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_appendText_2arg() throws Exception {
+        builder.appendText(MONTH_OF_YEAR, TextStyle.SHORT);
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "Text(MonthOfYear,SHORT)");
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_appendText_2arg_nullRule() throws Exception {
+        builder.appendText(null, TextStyle.SHORT);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_appendText_2arg_nullStyle() throws Exception {
+        builder.appendText(MONTH_OF_YEAR, (TextStyle) null);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_appendTextMap() throws Exception {
+        Map<Long, String> map = new HashMap<Long, String>();
+        map.put(1L, "JNY");
+        map.put(2L, "FBY");
+        map.put(3L, "MCH");
+        map.put(4L, "APL");
+        map.put(5L, "MAY");
+        map.put(6L, "JUN");
+        map.put(7L, "JLY");
+        map.put(8L, "AGT");
+        map.put(9L, "SPT");
+        map.put(10L, "OBR");
+        map.put(11L, "NVR");
+        map.put(12L, "DBR");
+        builder.appendText(MONTH_OF_YEAR, map);
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "Text(MonthOfYear)");  // TODO: toString should be different?
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_appendTextMap_nullRule() throws Exception {
+        builder.appendText(null, new HashMap<Long, String>());
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_appendTextMap_nullStyle() throws Exception {
+        builder.appendText(MONTH_OF_YEAR, (Map<Long, String>) null);
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_appendOffsetId() throws Exception {
+        builder.appendOffsetId();
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "Offset('Z',+HH:MM:ss)");
+    }
+
+    @DataProvider(name="offsetPatterns")
+    Object[][] data_offsetPatterns() {
+        return new Object[][] {
+                {"+HH", 2, 0, 0, "+02"},
+                {"+HH", -2, 0, 0, "-02"},
+                {"+HH", 2, 30, 0, "+02"},
+                {"+HH", 2, 0, 45, "+02"},
+                {"+HH", 2, 30, 45, "+02"},
+
+                {"+HHMM", 2, 0, 0, "+0200"},
+                {"+HHMM", -2, 0, 0, "-0200"},
+                {"+HHMM", 2, 30, 0, "+0230"},
+                {"+HHMM", 2, 0, 45, "+0200"},
+                {"+HHMM", 2, 30, 45, "+0230"},
+
+                {"+HH:MM", 2, 0, 0, "+02:00"},
+                {"+HH:MM", -2, 0, 0, "-02:00"},
+                {"+HH:MM", 2, 30, 0, "+02:30"},
+                {"+HH:MM", 2, 0, 45, "+02:00"},
+                {"+HH:MM", 2, 30, 45, "+02:30"},
+
+                {"+HHMMss", 2, 0, 0, "+0200"},
+                {"+HHMMss", -2, 0, 0, "-0200"},
+                {"+HHMMss", 2, 30, 0, "+0230"},
+                {"+HHMMss", 2, 0, 45, "+020045"},
+                {"+HHMMss", 2, 30, 45, "+023045"},
+
+                {"+HH:MM:ss", 2, 0, 0, "+02:00"},
+                {"+HH:MM:ss", -2, 0, 0, "-02:00"},
+                {"+HH:MM:ss", 2, 30, 0, "+02:30"},
+                {"+HH:MM:ss", 2, 0, 45, "+02:00:45"},
+                {"+HH:MM:ss", 2, 30, 45, "+02:30:45"},
+
+                {"+HHMMSS", 2, 0, 0, "+020000"},
+                {"+HHMMSS", -2, 0, 0, "-020000"},
+                {"+HHMMSS", 2, 30, 0, "+023000"},
+                {"+HHMMSS", 2, 0, 45, "+020045"},
+                {"+HHMMSS", 2, 30, 45, "+023045"},
+
+                {"+HH:MM:SS", 2, 0, 0, "+02:00:00"},
+                {"+HH:MM:SS", -2, 0, 0, "-02:00:00"},
+                {"+HH:MM:SS", 2, 30, 0, "+02:30:00"},
+                {"+HH:MM:SS", 2, 0, 45, "+02:00:45"},
+                {"+HH:MM:SS", 2, 30, 45, "+02:30:45"},
+        };
+    }
+
+    @Test(dataProvider="offsetPatterns", groups={"tck"})
+    public void test_appendOffset_print(String pattern, int h, int m, int s, String expected) throws Exception {
+        builder.appendOffset(pattern, "Z");
+        DateTimeFormatter f = builder.toFormatter();
+        ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(h, m, s);
+        assertEquals(f.print(offset), expected);
+    }
+
+    @Test(dataProvider="offsetPatterns", groups={"tck"})
+    public void test_appendOffset_parse(String pattern, int h, int m, int s, String expected) throws Exception {
+        builder.appendOffset(pattern, "Z");
+        DateTimeFormatter f = builder.toFormatter();
+        ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(h, m, s);
+        ZoneOffset parsed = f.parse(expected, ZoneOffset::from);
+        assertEquals(f.print(parsed), expected);
+    }
+
+    @DataProvider(name="badOffsetPatterns")
+    Object[][] data_badOffsetPatterns() {
+        return new Object[][] {
+            {"HH"},
+            {"HHMM"},
+            {"HH:MM"},
+            {"HHMMss"},
+            {"HH:MM:ss"},
+            {"HHMMSS"},
+            {"HH:MM:SS"},
+            {"+H"},
+            {"+HMM"},
+            {"+HHM"},
+            {"+A"},
+        };
+    }
+
+    @Test(dataProvider="badOffsetPatterns", expectedExceptions=IllegalArgumentException.class, groups={"tck"})
+    public void test_appendOffset_badPattern(String pattern) throws Exception {
+        builder.appendOffset(pattern, "Z");
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_appendOffset_3arg_nullText() throws Exception {
+        builder.appendOffset("+HH:MM", null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_appendOffset_3arg_nullPattern() throws Exception {
+        builder.appendOffset(null, "Z");
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_appendZoneId() throws Exception {
+        builder.appendZoneId();
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "ZoneId()");
+    }
+
+    @Test(groups={"tck"})
+    public void test_appendZoneText_1arg() throws Exception {
+        builder.appendZoneText(TextStyle.FULL);
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "ZoneText(FULL)");
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_appendZoneText_1arg_nullText() throws Exception {
+        builder.appendZoneText(null);
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_padNext_1arg() throws Exception {
+        builder.appendValue(MONTH_OF_YEAR).padNext(2).appendValue(DAY_OF_MONTH).appendValue(DAY_OF_WEEK);
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "Value(MonthOfYear)Pad(Value(DayOfMonth),2)Value(DayOfWeek)");
+    }
+
+    @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"})
+    public void test_padNext_1arg_invalidWidth() throws Exception {
+        builder.padNext(0);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_padNext_2arg_dash() throws Exception {
+        builder.appendValue(MONTH_OF_YEAR).padNext(2, '-').appendValue(DAY_OF_MONTH).appendValue(DAY_OF_WEEK);
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "Value(MonthOfYear)Pad(Value(DayOfMonth),2,'-')Value(DayOfWeek)");
+    }
+
+    @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"})
+    public void test_padNext_2arg_invalidWidth() throws Exception {
+        builder.padNext(0, '-');
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_padOptional() throws Exception {
+        builder.appendValue(MONTH_OF_YEAR).padNext(5).optionalStart().appendValue(DAY_OF_MONTH).optionalEnd().appendValue(DAY_OF_WEEK);
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "Value(MonthOfYear)Pad([Value(DayOfMonth)],5)Value(DayOfWeek)");
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_optionalStart_noEnd() throws Exception {
+        builder.appendValue(MONTH_OF_YEAR).optionalStart().appendValue(DAY_OF_MONTH).appendValue(DAY_OF_WEEK);
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "Value(MonthOfYear)[Value(DayOfMonth)Value(DayOfWeek)]");
+    }
+
+    @Test(groups={"tck"})
+    public void test_optionalStart2_noEnd() throws Exception {
+        builder.appendValue(MONTH_OF_YEAR).optionalStart().appendValue(DAY_OF_MONTH).optionalStart().appendValue(DAY_OF_WEEK);
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "Value(MonthOfYear)[Value(DayOfMonth)[Value(DayOfWeek)]]");
+    }
+
+    @Test(groups={"tck"})
+    public void test_optionalStart_doubleStart() throws Exception {
+        builder.appendValue(MONTH_OF_YEAR).optionalStart().optionalStart().appendValue(DAY_OF_MONTH);
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "Value(MonthOfYear)[[Value(DayOfMonth)]]");
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_optionalEnd() throws Exception {
+        builder.appendValue(MONTH_OF_YEAR).optionalStart().appendValue(DAY_OF_MONTH).optionalEnd().appendValue(DAY_OF_WEEK);
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "Value(MonthOfYear)[Value(DayOfMonth)]Value(DayOfWeek)");
+    }
+
+    @Test(groups={"tck"})
+    public void test_optionalEnd2() throws Exception {
+        builder.appendValue(MONTH_OF_YEAR).optionalStart().appendValue(DAY_OF_MONTH)
+            .optionalStart().appendValue(DAY_OF_WEEK).optionalEnd().appendValue(DAY_OF_MONTH).optionalEnd();
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "Value(MonthOfYear)[Value(DayOfMonth)[Value(DayOfWeek)]Value(DayOfMonth)]");
+    }
+
+    @Test(groups={"tck"})
+    public void test_optionalEnd_doubleStartSingleEnd() throws Exception {
+        builder.appendValue(MONTH_OF_YEAR).optionalStart().optionalStart().appendValue(DAY_OF_MONTH).optionalEnd();
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "Value(MonthOfYear)[[Value(DayOfMonth)]]");
+    }
+
+    @Test(groups={"tck"})
+    public void test_optionalEnd_doubleStartDoubleEnd() throws Exception {
+        builder.appendValue(MONTH_OF_YEAR).optionalStart().optionalStart().appendValue(DAY_OF_MONTH).optionalEnd().optionalEnd();
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "Value(MonthOfYear)[[Value(DayOfMonth)]]");
+    }
+
+    @Test(groups={"tck"})
+    public void test_optionalStartEnd_immediateStartEnd() throws Exception {
+        builder.appendValue(MONTH_OF_YEAR).optionalStart().optionalEnd().appendValue(DAY_OF_MONTH);
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), "Value(MonthOfYear)Value(DayOfMonth)");
+    }
+
+    @Test(expectedExceptions=IllegalStateException.class, groups={"tck"})
+    public void test_optionalEnd_noStart() throws Exception {
+        builder.optionalEnd();
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    @DataProvider(name="validPatterns")
+    Object[][] dataValid() {
+        return new Object[][] {
+            {"'a'", "'a'"},
+            {"''", "''"},
+            {"'!'", "'!'"},
+            {"!", "'!'"},
+
+            {"'hello_people,][)('", "'hello_people,][)('"},
+            {"'hi'", "'hi'"},
+            {"'yyyy'", "'yyyy'"},
+            {"''''", "''"},
+            {"'o''clock'", "'o''clock'"},
+
+            {"G", "Value(Era)"},
+            {"GG", "Value(Era,2)"},
+            {"GGG", "Text(Era,SHORT)"},
+            {"GGGG", "Text(Era)"},
+            {"GGGGG", "Text(Era,NARROW)"},
+
+            {"y", "Value(Year)"},
+            {"yy", "ReducedValue(Year,2,2000)"},
+            {"yyy", "Value(Year,3,19,NORMAL)"},
+            {"yyyy", "Value(Year,4,19,EXCEEDS_PAD)"},
+            {"yyyyy", "Value(Year,5,19,EXCEEDS_PAD)"},
+
+//            {"Y", "Value(WeekBasedYear)"},
+//            {"YY", "ReducedValue(WeekBasedYear,2,2000)"},
+//            {"YYY", "Value(WeekBasedYear,3,19,NORMAL)"},
+//            {"YYYY", "Value(WeekBasedYear,4,19,EXCEEDS_PAD)"},
+//            {"YYYYY", "Value(WeekBasedYear,5,19,EXCEEDS_PAD)"},
+
+            {"M", "Value(MonthOfYear)"},
+            {"MM", "Value(MonthOfYear,2)"},
+            {"MMM", "Text(MonthOfYear,SHORT)"},
+            {"MMMM", "Text(MonthOfYear)"},
+            {"MMMMM", "Text(MonthOfYear,NARROW)"},
+
+            {"D", "Value(DayOfYear)"},
+            {"DD", "Value(DayOfYear,2)"},
+            {"DDD", "Value(DayOfYear,3)"},
+
+            {"d", "Value(DayOfMonth)"},
+            {"dd", "Value(DayOfMonth,2)"},
+            {"ddd", "Value(DayOfMonth,3)"},
+
+            {"F", "Value(AlignedWeekOfMonth)"},
+            {"FF", "Value(AlignedWeekOfMonth,2)"},
+            {"FFF", "Value(AlignedWeekOfMonth,3)"},
+
+            {"Q", "Value(QuarterOfYear)"},
+            {"QQ", "Value(QuarterOfYear,2)"},
+            {"QQQ", "Text(QuarterOfYear,SHORT)"},
+            {"QQQQ", "Text(QuarterOfYear)"},
+            {"QQQQQ", "Text(QuarterOfYear,NARROW)"},
+
+            {"E", "Value(DayOfWeek)"},
+            {"EE", "Value(DayOfWeek,2)"},
+            {"EEE", "Text(DayOfWeek,SHORT)"},
+            {"EEEE", "Text(DayOfWeek)"},
+            {"EEEEE", "Text(DayOfWeek,NARROW)"},
+
+            {"a", "Text(AmPmOfDay,SHORT)"},
+            {"aa", "Text(AmPmOfDay,SHORT)"},
+            {"aaa", "Text(AmPmOfDay,SHORT)"},
+            {"aaaa", "Text(AmPmOfDay)"},
+            {"aaaaa", "Text(AmPmOfDay,NARROW)"},
+
+            {"H", "Value(HourOfDay)"},
+            {"HH", "Value(HourOfDay,2)"},
+            {"HHH", "Value(HourOfDay,3)"},
+
+            {"K", "Value(HourOfAmPm)"},
+            {"KK", "Value(HourOfAmPm,2)"},
+            {"KKK", "Value(HourOfAmPm,3)"},
+
+            {"k", "Value(ClockHourOfDay)"},
+            {"kk", "Value(ClockHourOfDay,2)"},
+            {"kkk", "Value(ClockHourOfDay,3)"},
+
+            {"h", "Value(ClockHourOfAmPm)"},
+            {"hh", "Value(ClockHourOfAmPm,2)"},
+            {"hhh", "Value(ClockHourOfAmPm,3)"},
+
+            {"m", "Value(MinuteOfHour)"},
+            {"mm", "Value(MinuteOfHour,2)"},
+            {"mmm", "Value(MinuteOfHour,3)"},
+
+            {"s", "Value(SecondOfMinute)"},
+            {"ss", "Value(SecondOfMinute,2)"},
+            {"sss", "Value(SecondOfMinute,3)"},
+
+            {"S", "Fraction(NanoOfSecond,1,1)"},
+            {"SS", "Fraction(NanoOfSecond,2,2)"},
+            {"SSS", "Fraction(NanoOfSecond,3,3)"},
+            {"SSSSSSSSS", "Fraction(NanoOfSecond,9,9)"},
+
+            {"A", "Value(MilliOfDay)"},
+            {"AA", "Value(MilliOfDay,2)"},
+            {"AAA", "Value(MilliOfDay,3)"},
+
+            {"n", "Value(NanoOfSecond)"},
+            {"nn", "Value(NanoOfSecond,2)"},
+            {"nnn", "Value(NanoOfSecond,3)"},
+
+            {"N", "Value(NanoOfDay)"},
+            {"NN", "Value(NanoOfDay,2)"},
+            {"NNN", "Value(NanoOfDay,3)"},
+
+            {"z", "ZoneText(SHORT)"},
+            {"zz", "ZoneText(SHORT)"},
+            {"zzz", "ZoneText(SHORT)"},
+            {"zzzz", "ZoneText(FULL)"},
+            {"zzzzz", "ZoneText(FULL)"},
+
+            {"I", "ZoneId()"},
+            {"II", "ZoneId()"},
+            {"III", "ZoneId()"},
+            {"IIII", "ZoneId()"},
+            {"IIIII", "ZoneId()"},
+
+            {"Z", "Offset('+0000',+HHMM)"},  // SimpleDateFormat compatible
+            {"ZZ", "Offset('+0000',+HHMM)"},
+            {"ZZZ", "Offset('+00:00',+HH:MM)"},
+
+            {"X", "Offset('Z',+HH)"},
+            {"XX", "Offset('Z',+HHMM)"},
+            {"XXX", "Offset('Z',+HH:MM)"},
+            {"XXXX", "Offset('Z',+HHMMss)"},
+            {"XXXXX", "Offset('Z',+HH:MM:ss)"},
+
+            {"ppH", "Pad(Value(HourOfDay),2)"},
+            {"pppDD", "Pad(Value(DayOfYear,2),3)"},
+
+            {"yyyy[-MM[-dd", "Value(Year,4,19,EXCEEDS_PAD)['-'Value(MonthOfYear,2)['-'Value(DayOfMonth,2)]]"},
+            {"yyyy[-MM[-dd]]", "Value(Year,4,19,EXCEEDS_PAD)['-'Value(MonthOfYear,2)['-'Value(DayOfMonth,2)]]"},
+            {"yyyy[-MM[]-dd]", "Value(Year,4,19,EXCEEDS_PAD)['-'Value(MonthOfYear,2)'-'Value(DayOfMonth,2)]"},
+
+            {"yyyy-MM-dd'T'HH:mm:ss.SSS", "Value(Year,4,19,EXCEEDS_PAD)'-'Value(MonthOfYear,2)'-'Value(DayOfMonth,2)" +
+                "'T'Value(HourOfDay,2)':'Value(MinuteOfHour,2)':'Value(SecondOfMinute,2)'.'Fraction(NanoOfSecond,3,3)"},
+
+            {"e", "WeekBased(e1)"},
+            {"w", "WeekBased(w1)"},
+            {"W", "WeekBased(W1)"},
+            {"WW", "WeekBased(W2)"},
+
+        };
+    }
+
+    @Test(dataProvider="validPatterns", groups={"implementation"})
+    public void test_appendPattern_valid(String input, String expected) throws Exception {
+        builder.appendPattern(input);
+        DateTimeFormatter f = builder.toFormatter();
+        assertEquals(f.toString(), expected);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="invalidPatterns")
+    Object[][] dataInvalid() {
+        return new Object[][] {
+            {"'"},
+            {"'hello"},
+            {"'hel''lo"},
+            {"'hello''"},
+            {"{"},
+            {"}"},
+            {"{}"},
+            {"]"},
+            {"yyyy]"},
+            {"yyyy]MM"},
+            {"yyyy[MM]]"},
+
+            {"MMMMMM"},
+            {"QQQQQQ"},
+            {"EEEEEE"},
+            {"aaaaaa"},
+            {"ZZZZ"},
+            {"XXXXXX"},
+
+            {"RO"},
+
+            {"p"},
+            {"pp"},
+            {"p:"},
+
+            {"f"},
+            {"ff"},
+            {"f:"},
+            {"fy"},
+            {"fa"},
+            {"fM"},
+
+            {"ww"},
+            {"ee"},
+            {"WWW"},
+        };
+    }
+
+    @Test(dataProvider="invalidPatterns", expectedExceptions=IllegalArgumentException.class, groups={"tck"})
+    public void test_appendPattern_invalid(String input) throws Exception {
+        try {
+            builder.appendPattern(input);
+        } catch (IllegalArgumentException ex) {
+            throw ex;
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="patternPrint")
+    Object[][] data_patternPrint() {
+        return new Object[][] {
+            {"Q", date(2012, 2, 10), "1"},
+            {"QQ", date(2012, 2, 10), "01"},
+//            {"QQQ", date(2012, 2, 10), "Q1"},  // TODO: data for quarters?
+//            {"QQQQ", date(2012, 2, 10), "Q1"},
+//            {"QQQQQ", date(2012, 2, 10), "Q1"},
+        };
+    }
+
+    @Test(dataProvider="patternPrint", groups={"tck"})
+    public void test_appendPattern_patternPrint(String input, Temporal temporal, String expected) throws Exception {
+        DateTimeFormatter f = builder.appendPattern(input).toFormatter(Locale.UK);
+        String test = f.print(temporal);
+        assertEquals(test, expected);
+    }
+
+    private static Temporal date(int y, int m, int d) {
+        return LocalDate.of(y, m, d);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatters.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,1276 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.format;
+
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.DAY_OF_WEEK;
+import static java.time.temporal.ChronoField.DAY_OF_YEAR;
+import static java.time.temporal.ChronoField.HOUR_OF_DAY;
+import static java.time.temporal.ChronoField.MINUTE_OF_HOUR;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.NANO_OF_SECOND;
+import static java.time.temporal.ChronoField.OFFSET_SECONDS;
+import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
+import static java.time.temporal.ChronoField.YEAR;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.text.ParsePosition;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeBuilder;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatters;
+import java.time.format.DateTimeParseException;
+import java.time.format.DateTimePrintException;
+import java.time.temporal.ISOFields;
+import java.time.temporal.Queries;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.Year;
+import java.time.temporal.YearMonth;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test DateTimeFormatters.
+ */
+@Test
+public class TCKDateTimeFormatters {
+
+    @BeforeMethod
+    public void setUp() {
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_print_nullCalendrical() {
+        DateTimeFormatters.isoDate().print((TemporalAccessor) null);
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_pattern_String() {
+        DateTimeFormatter test = DateTimeFormatters.pattern("d MMM yyyy");
+        assertEquals(test.toString(), "Value(DayOfMonth)' 'Text(MonthOfYear,SHORT)' 'Value(Year,4,19,EXCEEDS_PAD)");
+        assertEquals(test.getLocale(), Locale.getDefault());
+    }
+
+    @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"})
+    public void test_pattern_String_invalid() {
+        DateTimeFormatters.pattern("p");
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_pattern_String_null() {
+        DateTimeFormatters.pattern(null);
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_pattern_StringLocale() {
+        DateTimeFormatter test = DateTimeFormatters.pattern("d MMM yyyy", Locale.UK);
+        assertEquals(test.toString(), "Value(DayOfMonth)' 'Text(MonthOfYear,SHORT)' 'Value(Year,4,19,EXCEEDS_PAD)");
+        assertEquals(test.getLocale(), Locale.UK);
+    }
+
+    @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"})
+    public void test_pattern_StringLocale_invalid() {
+        DateTimeFormatters.pattern("p", Locale.UK);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_pattern_StringLocale_nullPattern() {
+        DateTimeFormatters.pattern(null, Locale.UK);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_pattern_StringLocale_nullLocale() {
+        DateTimeFormatters.pattern("yyyy", null);
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sample_isoLocalDate")
+    Object[][] provider_sample_isoLocalDate() {
+        return new Object[][]{
+                {2008, null, null, null, null, null, DateTimeException.class},
+                {null, 6, null, null, null, null, DateTimeException.class},
+                {null, null, 30, null, null, null, DateTimeException.class},
+                {null, null, null, "+01:00", null, null, DateTimeException.class},
+                {null, null, null, null, "Europe/Paris", null, DateTimeException.class},
+                {2008, 6, null, null, null, null, DateTimeException.class},
+                {null, 6, 30, null, null, null, DateTimeException.class},
+
+                {2008, 6, 30, null, null,                   "2008-06-30", null},
+                {2008, 6, 30, "+01:00", null,               "2008-06-30", null},
+                {2008, 6, 30, "+01:00", "Europe/Paris",     "2008-06-30", null},
+                {2008, 6, 30, null, "Europe/Paris",         "2008-06-30", null},
+
+                {123456, 6, 30, null, null,                 "+123456-06-30", null},
+        };
+    }
+
+    @Test(dataProvider="sample_isoLocalDate", groups={"tck"})
+    public void test_print_isoLocalDate(
+            Integer year, Integer month, Integer day, String offsetId, String zoneId,
+            String expected, Class<?> expectedEx) {
+        TemporalAccessor test = buildAccessor(year, month, day, null, null, null, null, offsetId, zoneId);
+        if (expectedEx == null) {
+            assertEquals(DateTimeFormatters.isoLocalDate().print(test), expected);
+        } else {
+            try {
+                DateTimeFormatters.isoLocalDate().print(test);
+                fail();
+            } catch (Exception ex) {
+                assertTrue(expectedEx.isInstance(ex));
+            }
+        }
+    }
+
+    @Test(dataProvider="sample_isoLocalDate", groups={"tck"})
+    public void test_parse_isoLocalDate(
+            Integer year, Integer month, Integer day, String offsetId, String zoneId,
+            String input, Class<?> invalid) {
+        if (input != null) {
+            DateTimeBuilder expected = createDate(year, month, day);
+            // offset/zone not expected to be parsed
+            assertParseMatch(DateTimeFormatters.isoLocalDate().parseToBuilder(input, new ParsePosition(0)), expected);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_parse_isoLocalDate_999999999() {
+        DateTimeBuilder expected = createDate(999999999, 8, 6);
+        assertParseMatch(DateTimeFormatters.isoLocalDate().parseToBuilder("+999999999-08-06", new ParsePosition(0)), expected);
+        assertEquals(LocalDate.parse("+999999999-08-06"), LocalDate.of(999999999, 8, 6));
+    }
+
+    @Test(groups={"tck"})
+    public void test_parse_isoLocalDate_1000000000() {
+        DateTimeBuilder expected = createDate(1000000000, 8, 6);
+        assertParseMatch(DateTimeFormatters.isoLocalDate().parseToBuilder("+1000000000-08-06", new ParsePosition(0)), expected);
+    }
+
+    @Test(expectedExceptions = DateTimeException.class, groups={"tck"})
+    public void test_parse_isoLocalDate_1000000000_failedCreate() {
+        LocalDate.parse("+1000000000-08-06");
+    }
+
+    @Test(groups={"tck"})
+    public void test_parse_isoLocalDate_M999999999() {
+        DateTimeBuilder expected = createDate(-999999999, 8, 6);
+        assertParseMatch(DateTimeFormatters.isoLocalDate().parseToBuilder("-999999999-08-06", new ParsePosition(0)), expected);
+        assertEquals(LocalDate.parse("-999999999-08-06"), LocalDate.of(-999999999, 8, 6));
+    }
+
+    @Test(groups={"tck"})
+    public void test_parse_isoLocalDate_M1000000000() {
+        DateTimeBuilder expected = createDate(-1000000000, 8, 6);
+        assertParseMatch(DateTimeFormatters.isoLocalDate().parseToBuilder("-1000000000-08-06", new ParsePosition(0)), expected);
+    }
+
+    @Test(expectedExceptions = DateTimeException.class, groups={"tck"})
+    public void test_parse_isoLocalDate_M1000000000_failedCreate() {
+        LocalDate.parse("-1000000000-08-06");
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sample_isoOffsetDate")
+    Object[][] provider_sample_isoOffsetDate() {
+        return new Object[][]{
+                {2008, null, null, null, null, null, DateTimeException.class},
+                {null, 6, null, null, null, null, DateTimeException.class},
+                {null, null, 30, null, null, null, DateTimeException.class},
+                {null, null, null, "+01:00", null, null, DateTimeException.class},
+                {null, null, null, null, "Europe/Paris", null, DateTimeException.class},
+                {2008, 6, null, null, null, null, DateTimeException.class},
+                {null, 6, 30, null, null, null, DateTimeException.class},
+
+                {2008, 6, 30, null, null,                   null, DateTimeException.class},
+                {2008, 6, 30, "+01:00", null,               "2008-06-30+01:00", null},
+                {2008, 6, 30, "+01:00", "Europe/Paris",     "2008-06-30+01:00", null},
+                {2008, 6, 30, null, "Europe/Paris",         null, DateTimeException.class},
+
+                {123456, 6, 30, "+01:00", null,             "+123456-06-30+01:00", null},
+        };
+    }
+
+    @Test(dataProvider="sample_isoOffsetDate", groups={"tck"})
+    public void test_print_isoOffsetDate(
+            Integer year, Integer month, Integer day, String offsetId, String zoneId,
+            String expected, Class<?> expectedEx) {
+        TemporalAccessor test = buildAccessor(year, month, day, null, null, null, null, offsetId, zoneId);
+        if (expectedEx == null) {
+            assertEquals(DateTimeFormatters.isoOffsetDate().print(test), expected);
+        } else {
+            try {
+                DateTimeFormatters.isoOffsetDate().print(test);
+                fail();
+            } catch (Exception ex) {
+                assertTrue(expectedEx.isInstance(ex));
+            }
+        }
+    }
+
+    @Test(dataProvider="sample_isoOffsetDate", groups={"tck"})
+    public void test_parse_isoOffsetDate(
+            Integer year, Integer month, Integer day, String offsetId, String zoneId,
+            String input, Class<?> invalid) {
+        if (input != null) {
+            DateTimeBuilder expected = createDate(year, month, day);
+            buildCalendrical(expected, offsetId, null);  // zone not expected to be parsed
+            assertParseMatch(DateTimeFormatters.isoOffsetDate().parseToBuilder(input, new ParsePosition(0)), expected);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sample_isoDate")
+    Object[][] provider_sample_isoDate() {
+        return new Object[][]{
+                {2008, null, null, null, null, null, DateTimeException.class},
+                {null, 6, null, null, null, null, DateTimeException.class},
+                {null, null, 30, null, null, null, DateTimeException.class},
+                {null, null, null, "+01:00", null, null, DateTimeException.class},
+                {null, null, null, null, "Europe/Paris", null, DateTimeException.class},
+                {2008, 6, null, null, null, null, DateTimeException.class},
+                {null, 6, 30, null, null, null, DateTimeException.class},
+
+                {2008, 6, 30, null, null,                   "2008-06-30", null},
+                {2008, 6, 30, "+01:00", null,               "2008-06-30+01:00", null},
+                {2008, 6, 30, "+01:00", "Europe/Paris",     "2008-06-30+01:00", null},
+                {2008, 6, 30, null, "Europe/Paris",         "2008-06-30", null},
+
+                {123456, 6, 30, "+01:00", "Europe/Paris",   "+123456-06-30+01:00", null},
+        };
+    }
+
+    @Test(dataProvider="sample_isoDate", groups={"tck"})
+    public void test_print_isoDate(
+            Integer year, Integer month, Integer day, String offsetId, String zoneId,
+            String expected, Class<?> expectedEx) {
+        TemporalAccessor test = buildAccessor(year, month, day, null, null, null, null, offsetId, zoneId);
+        if (expectedEx == null) {
+            assertEquals(DateTimeFormatters.isoDate().print(test), expected);
+        } else {
+            try {
+                DateTimeFormatters.isoDate().print(test);
+                fail();
+            } catch (Exception ex) {
+                assertTrue(expectedEx.isInstance(ex));
+            }
+        }
+    }
+
+    @Test(dataProvider="sample_isoDate", groups={"tck"})
+    public void test_parse_isoDate(
+            Integer year, Integer month, Integer day, String offsetId, String zoneId,
+            String input, Class<?> invalid) {
+        if (input != null) {
+            DateTimeBuilder expected = createDate(year, month, day);
+            if (offsetId != null) {
+                expected.addFieldValue(OFFSET_SECONDS, ZoneOffset.of(offsetId).getTotalSeconds());
+            }
+            assertParseMatch(DateTimeFormatters.isoDate().parseToBuilder(input, new ParsePosition(0)), expected);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sample_isoLocalTime")
+    Object[][] provider_sample_isoLocalTime() {
+        return new Object[][]{
+                {11, null, null, null, null, null, null, DateTimeException.class},
+                {null, 5, null, null, null, null, null, DateTimeException.class},
+                {null, null, 30, null, null, null, null, DateTimeException.class},
+                {null, null, null, 1, null, null, null, DateTimeException.class},
+                {null, null, null, null, "+01:00", null, null, DateTimeException.class},
+                {null, null, null, null, null, "Europe/Paris", null, DateTimeException.class},
+
+                {11, 5, null, null, null, null,     "11:05", null},
+                {11, 5, 30, null, null, null,       "11:05:30", null},
+                {11, 5, 30, 500000000, null, null,  "11:05:30.5", null},
+                {11, 5, 30, 1, null, null,          "11:05:30.000000001", null},
+
+                {11, 5, null, null, "+01:00", null,     "11:05", null},
+                {11, 5, 30, null, "+01:00", null,       "11:05:30", null},
+                {11, 5, 30, 500000000, "+01:00", null,  "11:05:30.5", null},
+                {11, 5, 30, 1, "+01:00", null,          "11:05:30.000000001", null},
+
+                {11, 5, null, null, "+01:00", "Europe/Paris",       "11:05", null},
+                {11, 5, 30, null, "+01:00", "Europe/Paris",         "11:05:30", null},
+                {11, 5, 30, 500000000, "+01:00", "Europe/Paris",    "11:05:30.5", null},
+                {11, 5, 30, 1, "+01:00", "Europe/Paris",            "11:05:30.000000001", null},
+
+                {11, 5, null, null, null, "Europe/Paris",       "11:05", null},
+                {11, 5, 30, null, null, "Europe/Paris",         "11:05:30", null},
+                {11, 5, 30, 500000000, null, "Europe/Paris",    "11:05:30.5", null},
+                {11, 5, 30, 1, null, "Europe/Paris",            "11:05:30.000000001", null},
+        };
+    }
+
+    @Test(dataProvider="sample_isoLocalTime", groups={"tck"})
+    public void test_print_isoLocalTime(
+            Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId,
+            String expected, Class<?> expectedEx) {
+        TemporalAccessor test = buildAccessor(null, null, null, hour, min, sec, nano, offsetId, zoneId);
+        if (expectedEx == null) {
+            assertEquals(DateTimeFormatters.isoLocalTime().print(test), expected);
+        } else {
+            try {
+                DateTimeFormatters.isoLocalTime().print(test);
+                fail();
+            } catch (Exception ex) {
+                assertTrue(expectedEx.isInstance(ex));
+            }
+        }
+    }
+
+    @Test(dataProvider="sample_isoLocalTime", groups={"tck"})
+    public void test_parse_isoLocalTime(
+            Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId,
+            String input, Class<?> invalid) {
+        if (input != null) {
+            DateTimeBuilder expected = createTime(hour, min, sec, nano);
+            // offset/zone not expected to be parsed
+            assertParseMatch(DateTimeFormatters.isoLocalTime().parseToBuilder(input, new ParsePosition(0)), expected);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sample_isoOffsetTime")
+    Object[][] provider_sample_isoOffsetTime() {
+        return new Object[][]{
+                {11, null, null, null, null, null, null, DateTimeException.class},
+                {null, 5, null, null, null, null, null, DateTimeException.class},
+                {null, null, 30, null, null, null, null, DateTimeException.class},
+                {null, null, null, 1, null, null, null, DateTimeException.class},
+                {null, null, null, null, "+01:00", null, null, DateTimeException.class},
+                {null, null, null, null, null, "Europe/Paris", null, DateTimeException.class},
+
+                {11, 5, null, null, null, null,     null, DateTimeException.class},
+                {11, 5, 30, null, null, null,       null, DateTimeException.class},
+                {11, 5, 30, 500000000, null, null,  null, DateTimeException.class},
+                {11, 5, 30, 1, null, null,          null, DateTimeException.class},
+
+                {11, 5, null, null, "+01:00", null,     "11:05+01:00", null},
+                {11, 5, 30, null, "+01:00", null,       "11:05:30+01:00", null},
+                {11, 5, 30, 500000000, "+01:00", null,  "11:05:30.5+01:00", null},
+                {11, 5, 30, 1, "+01:00", null,          "11:05:30.000000001+01:00", null},
+
+                {11, 5, null, null, "+01:00", "Europe/Paris",       "11:05+01:00", null},
+                {11, 5, 30, null, "+01:00", "Europe/Paris",         "11:05:30+01:00", null},
+                {11, 5, 30, 500000000, "+01:00", "Europe/Paris",    "11:05:30.5+01:00", null},
+                {11, 5, 30, 1, "+01:00", "Europe/Paris",            "11:05:30.000000001+01:00", null},
+
+                {11, 5, null, null, null, "Europe/Paris",       null, DateTimeException.class},
+                {11, 5, 30, null, null, "Europe/Paris",         null, DateTimeException.class},
+                {11, 5, 30, 500000000, null, "Europe/Paris",    null, DateTimeException.class},
+                {11, 5, 30, 1, null, "Europe/Paris",            null, DateTimeException.class},
+        };
+    }
+
+    @Test(dataProvider="sample_isoOffsetTime", groups={"tck"})
+    public void test_print_isoOffsetTime(
+            Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId,
+            String expected, Class<?> expectedEx) {
+        TemporalAccessor test = buildAccessor(null, null, null, hour, min, sec, nano, offsetId, zoneId);
+        if (expectedEx == null) {
+            assertEquals(DateTimeFormatters.isoOffsetTime().print(test), expected);
+        } else {
+            try {
+                DateTimeFormatters.isoOffsetTime().print(test);
+                fail();
+            } catch (Exception ex) {
+                assertTrue(expectedEx.isInstance(ex));
+            }
+        }
+    }
+
+    @Test(dataProvider="sample_isoOffsetTime", groups={"tck"})
+    public void test_parse_isoOffsetTime(
+            Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId,
+            String input, Class<?> invalid) {
+        if (input != null) {
+            DateTimeBuilder expected = createTime(hour, min, sec, nano);
+            buildCalendrical(expected, offsetId, null);  // zoneId is not expected from parse
+            assertParseMatch(DateTimeFormatters.isoOffsetTime().parseToBuilder(input, new ParsePosition(0)), expected);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sample_isoTime")
+    Object[][] provider_sample_isoTime() {
+        return new Object[][]{
+                {11, null, null, null, null, null, null, DateTimeException.class},
+                {null, 5, null, null, null, null, null, DateTimeException.class},
+                {null, null, 30, null, null, null, null, DateTimeException.class},
+                {null, null, null, 1, null, null, null, DateTimeException.class},
+                {null, null, null, null, "+01:00", null, null, DateTimeException.class},
+                {null, null, null, null, null, "Europe/Paris", null, DateTimeException.class},
+
+                {11, 5, null, null, null, null,     "11:05", null},
+                {11, 5, 30, null, null, null,       "11:05:30", null},
+                {11, 5, 30, 500000000, null, null,  "11:05:30.5", null},
+                {11, 5, 30, 1, null, null,          "11:05:30.000000001", null},
+
+                {11, 5, null, null, "+01:00", null,     "11:05+01:00", null},
+                {11, 5, 30, null, "+01:00", null,       "11:05:30+01:00", null},
+                {11, 5, 30, 500000000, "+01:00", null,  "11:05:30.5+01:00", null},
+                {11, 5, 30, 1, "+01:00", null,          "11:05:30.000000001+01:00", null},
+
+                {11, 5, null, null, "+01:00", "Europe/Paris",       "11:05+01:00", null},
+                {11, 5, 30, null, "+01:00", "Europe/Paris",         "11:05:30+01:00", null},
+                {11, 5, 30, 500000000, "+01:00", "Europe/Paris",    "11:05:30.5+01:00", null},
+                {11, 5, 30, 1, "+01:00", "Europe/Paris",            "11:05:30.000000001+01:00", null},
+
+                {11, 5, null, null, null, "Europe/Paris",       "11:05", null},
+                {11, 5, 30, null, null, "Europe/Paris",         "11:05:30", null},
+                {11, 5, 30, 500000000, null, "Europe/Paris",    "11:05:30.5", null},
+                {11, 5, 30, 1, null, "Europe/Paris",            "11:05:30.000000001", null},
+        };
+    }
+
+    @Test(dataProvider="sample_isoTime", groups={"tck"})
+    public void test_print_isoTime(
+            Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId,
+            String expected, Class<?> expectedEx) {
+        TemporalAccessor test = buildAccessor(null, null, null, hour, min, sec, nano, offsetId, zoneId);
+        if (expectedEx == null) {
+            assertEquals(DateTimeFormatters.isoTime().print(test), expected);
+        } else {
+            try {
+                DateTimeFormatters.isoTime().print(test);
+                fail();
+            } catch (Exception ex) {
+                assertTrue(expectedEx.isInstance(ex));
+            }
+        }
+    }
+
+    @Test(dataProvider="sample_isoTime", groups={"tck"})
+    public void test_parse_isoTime(
+            Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId,
+            String input, Class<?> invalid) {
+        if (input != null) {
+            DateTimeBuilder expected = createTime(hour, min, sec, nano);
+            if (offsetId != null) {
+                expected.addFieldValue(OFFSET_SECONDS, ZoneOffset.of(offsetId).getTotalSeconds());
+            }
+            assertParseMatch(DateTimeFormatters.isoTime().parseToBuilder(input, new ParsePosition(0)), expected);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sample_isoLocalDateTime")
+    Object[][] provider_sample_isoLocalDateTime() {
+        return new Object[][]{
+                {2008, null, null, null, null, null, null, null, null, null, DateTimeException.class},
+                {null, 6, null, null, null, null, null, null, null, null, DateTimeException.class},
+                {null, null, 30, null, null, null, null, null, null, null, DateTimeException.class},
+                {null, null, null, 11, null, null, null, null, null, null, DateTimeException.class},
+                {null, null, null, null, 5, null, null, null, null, null, DateTimeException.class},
+                {null, null, null, null, null, null, null, "+01:00", null, null, DateTimeException.class},
+                {null, null, null, null, null, null, null, null, "Europe/Paris", null, DateTimeException.class},
+                {2008, 6, 30, 11, null, null, null, null, null, null, DateTimeException.class},
+                {2008, 6, 30, null, 5, null, null, null, null, null, DateTimeException.class},
+                {2008, 6, null, 11, 5, null, null, null, null, null, DateTimeException.class},
+                {2008, null, 30, 11, 5, null, null, null, null, null, DateTimeException.class},
+                {null, 6, 30, 11, 5, null, null, null, null, null, DateTimeException.class},
+
+                {2008, 6, 30, 11, 5, null, null, null, null,                    "2008-06-30T11:05", null},
+                {2008, 6, 30, 11, 5, 30, null, null, null,                      "2008-06-30T11:05:30", null},
+                {2008, 6, 30, 11, 5, 30, 500000000, null, null,                 "2008-06-30T11:05:30.5", null},
+                {2008, 6, 30, 11, 5, 30, 1, null, null,                         "2008-06-30T11:05:30.000000001", null},
+
+                {2008, 6, 30, 11, 5, null, null, "+01:00", null,                "2008-06-30T11:05", null},
+                {2008, 6, 30, 11, 5, 30, null, "+01:00", null,                  "2008-06-30T11:05:30", null},
+                {2008, 6, 30, 11, 5, 30, 500000000, "+01:00", null,             "2008-06-30T11:05:30.5", null},
+                {2008, 6, 30, 11, 5, 30, 1, "+01:00", null,                     "2008-06-30T11:05:30.000000001", null},
+
+                {2008, 6, 30, 11, 5, null, null, "+01:00", "Europe/Paris",      "2008-06-30T11:05", null},
+                {2008, 6, 30, 11, 5, 30, null, "+01:00", "Europe/Paris",        "2008-06-30T11:05:30", null},
+                {2008, 6, 30, 11, 5, 30, 500000000, "+01:00", "Europe/Paris",   "2008-06-30T11:05:30.5", null},
+                {2008, 6, 30, 11, 5, 30, 1, "+01:00", "Europe/Paris",           "2008-06-30T11:05:30.000000001", null},
+
+                {2008, 6, 30, 11, 5, null, null, null, "Europe/Paris",          "2008-06-30T11:05", null},
+                {2008, 6, 30, 11, 5, 30, null, null, "Europe/Paris",            "2008-06-30T11:05:30", null},
+                {2008, 6, 30, 11, 5, 30, 500000000, null, "Europe/Paris",       "2008-06-30T11:05:30.5", null},
+                {2008, 6, 30, 11, 5, 30, 1, null, "Europe/Paris",               "2008-06-30T11:05:30.000000001", null},
+
+                {123456, 6, 30, 11, 5, null, null, null, null,                  "+123456-06-30T11:05", null},
+        };
+    }
+
+    @Test(dataProvider="sample_isoLocalDateTime", groups={"tck"})
+    public void test_print_isoLocalDateTime(
+            Integer year, Integer month, Integer day,
+            Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId,
+            String expected, Class<?> expectedEx) {
+        TemporalAccessor test = buildAccessor(year, month, day, hour, min, sec, nano, offsetId, zoneId);
+        if (expectedEx == null) {
+            assertEquals(DateTimeFormatters.isoLocalDateTime().print(test), expected);
+        } else {
+            try {
+                DateTimeFormatters.isoLocalDateTime().print(test);
+                fail();
+            } catch (Exception ex) {
+                assertTrue(expectedEx.isInstance(ex));
+            }
+        }
+    }
+
+    @Test(dataProvider="sample_isoLocalDateTime", groups={"tck"})
+    public void test_parse_isoLocalDateTime(
+            Integer year, Integer month, Integer day,
+            Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId,
+            String input, Class<?> invalid) {
+        if (input != null) {
+            DateTimeBuilder expected = createDateTime(year, month, day, hour, min, sec, nano);
+            assertParseMatch(DateTimeFormatters.isoLocalDateTime().parseToBuilder(input, new ParsePosition(0)), expected);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sample_isoOffsetDateTime")
+    Object[][] provider_sample_isoOffsetDateTime() {
+        return new Object[][]{
+                {2008, null, null, null, null, null, null, null, null, null, DateTimeException.class},
+                {null, 6, null, null, null, null, null, null, null, null, DateTimeException.class},
+                {null, null, 30, null, null, null, null, null, null, null, DateTimeException.class},
+                {null, null, null, 11, null, null, null, null, null, null, DateTimeException.class},
+                {null, null, null, null, 5, null, null, null, null, null, DateTimeException.class},
+                {null, null, null, null, null, null, null, "+01:00", null, null, DateTimeException.class},
+                {null, null, null, null, null, null, null, null, "Europe/Paris", null, DateTimeException.class},
+                {2008, 6, 30, 11, null, null, null, null, null, null, DateTimeException.class},
+                {2008, 6, 30, null, 5, null, null, null, null, null, DateTimeException.class},
+                {2008, 6, null, 11, 5, null, null, null, null, null, DateTimeException.class},
+                {2008, null, 30, 11, 5, null, null, null, null, null, DateTimeException.class},
+                {null, 6, 30, 11, 5, null, null, null, null, null, DateTimeException.class},
+
+                {2008, 6, 30, 11, 5, null, null, null, null,                    null, DateTimeException.class},
+                {2008, 6, 30, 11, 5, 30, null, null, null,                      null, DateTimeException.class},
+                {2008, 6, 30, 11, 5, 30, 500000000, null, null,                 null, DateTimeException.class},
+                {2008, 6, 30, 11, 5, 30, 1, null, null,                         null, DateTimeException.class},
+
+                {2008, 6, 30, 11, 5, null, null, "+01:00", null,                "2008-06-30T11:05+01:00", null},
+                {2008, 6, 30, 11, 5, 30, null, "+01:00", null,                  "2008-06-30T11:05:30+01:00", null},
+                {2008, 6, 30, 11, 5, 30, 500000000, "+01:00", null,             "2008-06-30T11:05:30.5+01:00", null},
+                {2008, 6, 30, 11, 5, 30, 1, "+01:00", null,                     "2008-06-30T11:05:30.000000001+01:00", null},
+
+                {2008, 6, 30, 11, 5, null, null, "+01:00", "Europe/Paris",      "2008-06-30T11:05+01:00", null},
+                {2008, 6, 30, 11, 5, 30, null, "+01:00", "Europe/Paris",        "2008-06-30T11:05:30+01:00", null},
+                {2008, 6, 30, 11, 5, 30, 500000000, "+01:00", "Europe/Paris",   "2008-06-30T11:05:30.5+01:00", null},
+                {2008, 6, 30, 11, 5, 30, 1, "+01:00", "Europe/Paris",           "2008-06-30T11:05:30.000000001+01:00", null},
+
+                {2008, 6, 30, 11, 5, null, null, null, "Europe/Paris",          null, DateTimeException.class},
+                {2008, 6, 30, 11, 5, 30, null, null, "Europe/Paris",            null, DateTimeException.class},
+                {2008, 6, 30, 11, 5, 30, 500000000, null, "Europe/Paris",       null, DateTimeException.class},
+                {2008, 6, 30, 11, 5, 30, 1, null, "Europe/Paris",               null, DateTimeException.class},
+
+                {123456, 6, 30, 11, 5, null, null, "+01:00", null,              "+123456-06-30T11:05+01:00", null},
+        };
+    }
+
+    @Test(dataProvider="sample_isoOffsetDateTime", groups={"tck"})
+    public void test_print_isoOffsetDateTime(
+            Integer year, Integer month, Integer day,
+            Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId,
+            String expected, Class<?> expectedEx) {
+        TemporalAccessor test = buildAccessor(year, month, day, hour, min, sec, nano, offsetId, zoneId);
+        if (expectedEx == null) {
+            assertEquals(DateTimeFormatters.isoOffsetDateTime().print(test), expected);
+        } else {
+            try {
+                DateTimeFormatters.isoOffsetDateTime().print(test);
+                fail();
+            } catch (Exception ex) {
+                assertTrue(expectedEx.isInstance(ex));
+            }
+        }
+    }
+
+    @Test(dataProvider="sample_isoOffsetDateTime", groups={"tck"})
+    public void test_parse_isoOffsetDateTime(
+            Integer year, Integer month, Integer day,
+            Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId,
+            String input, Class<?> invalid) {
+        if (input != null) {
+            DateTimeBuilder expected = createDateTime(year, month, day, hour, min, sec, nano);
+            buildCalendrical(expected, offsetId, null);  // zone not expected to be parsed
+            assertParseMatch(DateTimeFormatters.isoOffsetDateTime().parseToBuilder(input, new ParsePosition(0)), expected);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sample_isoZonedDateTime")
+    Object[][] provider_sample_isoZonedDateTime() {
+        return new Object[][]{
+                {2008, null, null, null, null, null, null, null, null, null, DateTimeException.class},
+                {null, 6, null, null, null, null, null, null, null, null, DateTimeException.class},
+                {null, null, 30, null, null, null, null, null, null, null, DateTimeException.class},
+                {null, null, null, 11, null, null, null, null, null, null, DateTimeException.class},
+                {null, null, null, null, 5, null, null, null, null, null, DateTimeException.class},
+                {null, null, null, null, null, null, null, "+01:00", null, null, DateTimeException.class},
+                {null, null, null, null, null, null, null, null, "Europe/Paris", null, DateTimeException.class},
+                {2008, 6, 30, 11, null, null, null, null, null, null, DateTimeException.class},
+                {2008, 6, 30, null, 5, null, null, null, null, null, DateTimeException.class},
+                {2008, 6, null, 11, 5, null, null, null, null, null, DateTimeException.class},
+                {2008, null, 30, 11, 5, null, null, null, null, null, DateTimeException.class},
+                {null, 6, 30, 11, 5, null, null, null, null, null, DateTimeException.class},
+
+                {2008, 6, 30, 11, 5, null, null, null, null,                    null, DateTimeException.class},
+                {2008, 6, 30, 11, 5, 30, null, null, null,                      null, DateTimeException.class},
+                {2008, 6, 30, 11, 5, 30, 500000000, null, null,                 null, DateTimeException.class},
+                {2008, 6, 30, 11, 5, 30, 1, null, null,                         null, DateTimeException.class},
+
+                // allow OffsetDateTime (no harm comes of this AFAICT)
+                {2008, 6, 30, 11, 5, null, null, "+01:00", null,                "2008-06-30T11:05+01:00", null},
+                {2008, 6, 30, 11, 5, 30, null, "+01:00", null,                  "2008-06-30T11:05:30+01:00", null},
+                {2008, 6, 30, 11, 5, 30, 500000000, "+01:00", null,             "2008-06-30T11:05:30.5+01:00", null},
+                {2008, 6, 30, 11, 5, 30, 1, "+01:00", null,                     "2008-06-30T11:05:30.000000001+01:00", null},
+
+                // ZonedDateTime with ZoneId of ZoneOffset
+                {2008, 6, 30, 11, 5, null, null, "+01:00", "+01:00",            "2008-06-30T11:05+01:00", null},
+                {2008, 6, 30, 11, 5, 30, null, "+01:00", "+01:00",              "2008-06-30T11:05:30+01:00", null},
+                {2008, 6, 30, 11, 5, 30, 500000000, "+01:00", "+01:00",         "2008-06-30T11:05:30.5+01:00", null},
+                {2008, 6, 30, 11, 5, 30, 1, "+01:00", "+01:00",                 "2008-06-30T11:05:30.000000001+01:00", null},
+
+                // ZonedDateTime with ZoneId of ZoneRegion
+                {2008, 6, 30, 11, 5, null, null, "+01:00", "Europe/Paris",      "2008-06-30T11:05+01:00[Europe/Paris]", null},
+                {2008, 6, 30, 11, 5, 30, null, "+01:00", "Europe/Paris",        "2008-06-30T11:05:30+01:00[Europe/Paris]", null},
+                {2008, 6, 30, 11, 5, 30, 500000000, "+01:00", "Europe/Paris",   "2008-06-30T11:05:30.5+01:00[Europe/Paris]", null},
+                {2008, 6, 30, 11, 5, 30, 1, "+01:00", "Europe/Paris",           "2008-06-30T11:05:30.000000001+01:00[Europe/Paris]", null},
+
+                // offset required
+                {2008, 6, 30, 11, 5, null, null, null, "Europe/Paris",          null, DateTimeException.class},
+                {2008, 6, 30, 11, 5, 30, null, null, "Europe/Paris",            null, DateTimeException.class},
+                {2008, 6, 30, 11, 5, 30, 500000000, null, "Europe/Paris",       null, DateTimeException.class},
+                {2008, 6, 30, 11, 5, 30, 1, null, "Europe/Paris",               null, DateTimeException.class},
+
+                {123456, 6, 30, 11, 5, null, null, "+01:00", "Europe/Paris",    "+123456-06-30T11:05+01:00[Europe/Paris]", null},
+        };
+    }
+
+    @Test(dataProvider="sample_isoZonedDateTime", groups={"tck"})
+    public void test_print_isoZonedDateTime(
+            Integer year, Integer month, Integer day,
+            Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId,
+            String expected, Class<?> expectedEx) {
+        TemporalAccessor test = buildAccessor(year, month, day, hour, min, sec, nano, offsetId, zoneId);
+        if (expectedEx == null) {
+            assertEquals(DateTimeFormatters.isoZonedDateTime().print(test), expected);
+        } else {
+            try {
+                DateTimeFormatters.isoZonedDateTime().print(test);
+                fail(test.toString());
+            } catch (Exception ex) {
+                assertTrue(expectedEx.isInstance(ex));
+            }
+        }
+    }
+
+    @Test(dataProvider="sample_isoZonedDateTime", groups={"tck"})
+    public void test_parse_isoZonedDateTime(
+            Integer year, Integer month, Integer day,
+            Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId,
+            String input, Class<?> invalid) {
+        if (input != null) {
+            DateTimeBuilder expected = createDateTime(year, month, day, hour, min, sec, nano);
+            if (offsetId.equals(zoneId)) {
+                buildCalendrical(expected, offsetId, null);
+            } else {
+                buildCalendrical(expected, offsetId, zoneId);
+            }
+            assertParseMatch(DateTimeFormatters.isoZonedDateTime().parseToBuilder(input, new ParsePosition(0)), expected);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sample_isoDateTime")
+    Object[][] provider_sample_isoDateTime() {
+        return new Object[][]{
+                {2008, null, null, null, null, null, null, null, null, null, DateTimeException.class},
+                {null, 6, null, null, null, null, null, null, null, null, DateTimeException.class},
+                {null, null, 30, null, null, null, null, null, null, null, DateTimeException.class},
+                {null, null, null, 11, null, null, null, null, null, null, DateTimeException.class},
+                {null, null, null, null, 5, null, null, null, null, null, DateTimeException.class},
+                {null, null, null, null, null, null, null, "+01:00", null, null, DateTimeException.class},
+                {null, null, null, null, null, null, null, null, "Europe/Paris", null, DateTimeException.class},
+                {2008, 6, 30, 11, null, null, null, null, null, null, DateTimeException.class},
+                {2008, 6, 30, null, 5, null, null, null, null, null, DateTimeException.class},
+                {2008, 6, null, 11, 5, null, null, null, null, null, DateTimeException.class},
+                {2008, null, 30, 11, 5, null, null, null, null, null, DateTimeException.class},
+                {null, 6, 30, 11, 5, null, null, null, null, null, DateTimeException.class},
+
+                {2008, 6, 30, 11, 5, null, null, null, null,                    "2008-06-30T11:05", null},
+                {2008, 6, 30, 11, 5, 30, null, null, null,                      "2008-06-30T11:05:30", null},
+                {2008, 6, 30, 11, 5, 30, 500000000, null, null,                 "2008-06-30T11:05:30.5", null},
+                {2008, 6, 30, 11, 5, 30, 1, null, null,                         "2008-06-30T11:05:30.000000001", null},
+
+                {2008, 6, 30, 11, 5, null, null, "+01:00", null,                "2008-06-30T11:05+01:00", null},
+                {2008, 6, 30, 11, 5, 30, null, "+01:00", null,                  "2008-06-30T11:05:30+01:00", null},
+                {2008, 6, 30, 11, 5, 30, 500000000, "+01:00", null,             "2008-06-30T11:05:30.5+01:00", null},
+                {2008, 6, 30, 11, 5, 30, 1, "+01:00", null,                     "2008-06-30T11:05:30.000000001+01:00", null},
+
+                {2008, 6, 30, 11, 5, null, null, "+01:00", "Europe/Paris",      "2008-06-30T11:05+01:00[Europe/Paris]", null},
+                {2008, 6, 30, 11, 5, 30, null, "+01:00", "Europe/Paris",        "2008-06-30T11:05:30+01:00[Europe/Paris]", null},
+                {2008, 6, 30, 11, 5, 30, 500000000, "+01:00", "Europe/Paris",   "2008-06-30T11:05:30.5+01:00[Europe/Paris]", null},
+                {2008, 6, 30, 11, 5, 30, 1, "+01:00", "Europe/Paris",           "2008-06-30T11:05:30.000000001+01:00[Europe/Paris]", null},
+
+                {2008, 6, 30, 11, 5, null, null, null, "Europe/Paris",          "2008-06-30T11:05", null},
+                {2008, 6, 30, 11, 5, 30, null, null, "Europe/Paris",            "2008-06-30T11:05:30", null},
+                {2008, 6, 30, 11, 5, 30, 500000000, null, "Europe/Paris",       "2008-06-30T11:05:30.5", null},
+                {2008, 6, 30, 11, 5, 30, 1, null, "Europe/Paris",               "2008-06-30T11:05:30.000000001", null},
+
+                {123456, 6, 30, 11, 5, null, null, null, null,                  "+123456-06-30T11:05", null},
+        };
+    }
+
+    @Test(dataProvider="sample_isoDateTime", groups={"tck"})
+    public void test_print_isoDateTime(
+            Integer year, Integer month, Integer day,
+            Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId,
+            String expected, Class<?> expectedEx) {
+        TemporalAccessor test = buildAccessor(year, month, day, hour, min, sec, nano, offsetId, zoneId);
+        if (expectedEx == null) {
+            assertEquals(DateTimeFormatters.isoDateTime().print(test), expected);
+        } else {
+            try {
+                DateTimeFormatters.isoDateTime().print(test);
+                fail();
+            } catch (Exception ex) {
+                assertTrue(expectedEx.isInstance(ex));
+            }
+        }
+    }
+
+    @Test(dataProvider="sample_isoDateTime", groups={"tck"})
+    public void test_parse_isoDateTime(
+            Integer year, Integer month, Integer day,
+            Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId,
+            String input, Class<?> invalid) {
+        if (input != null) {
+            DateTimeBuilder expected = createDateTime(year, month, day, hour, min, sec, nano);
+            if (offsetId != null) {
+                expected.addFieldValue(OFFSET_SECONDS, ZoneOffset.of(offsetId).getTotalSeconds());
+                if (zoneId != null) {
+                    expected.addCalendrical(ZoneId.of(zoneId));
+                }
+            }
+            assertParseMatch(DateTimeFormatters.isoDateTime().parseToBuilder(input, new ParsePosition(0)), expected);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_print_isoOrdinalDate() {
+        TemporalAccessor test = buildAccessor(LocalDateTime.of(2008, 6, 3, 11, 5, 30), null, null);
+        assertEquals(DateTimeFormatters.isoOrdinalDate().print(test), "2008-155");
+    }
+
+    @Test(groups={"tck"})
+    public void test_print_isoOrdinalDate_offset() {
+        TemporalAccessor test = buildAccessor(LocalDateTime.of(2008, 6, 3, 11, 5, 30), "Z", null);
+        assertEquals(DateTimeFormatters.isoOrdinalDate().print(test), "2008-155Z");
+    }
+
+    @Test(groups={"tck"})
+    public void test_print_isoOrdinalDate_zoned() {
+        TemporalAccessor test = buildAccessor(LocalDateTime.of(2008, 6, 3, 11, 5, 30), "+02:00", "Europe/Paris");
+        assertEquals(DateTimeFormatters.isoOrdinalDate().print(test), "2008-155+02:00");
+    }
+
+    @Test(groups={"tck"})
+    public void test_print_isoOrdinalDate_zoned_largeYear() {
+        TemporalAccessor test = buildAccessor(LocalDateTime.of(123456, 6, 3, 11, 5, 30), "Z", null);
+        assertEquals(DateTimeFormatters.isoOrdinalDate().print(test), "+123456-155Z");
+    }
+
+    @Test(groups={"tck"})
+    public void test_print_isoOrdinalDate_fields() {
+        TemporalAccessor test = new DateTimeBuilder(YEAR, 2008).addFieldValue(DAY_OF_YEAR, 231);
+        assertEquals(DateTimeFormatters.isoOrdinalDate().print(test), "2008-231");
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_print_isoOrdinalDate_missingField() {
+        TemporalAccessor test = Year.of(2008);
+        DateTimeFormatters.isoOrdinalDate().print(test);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_parse_isoOrdinalDate() {
+        DateTimeBuilder expected = new DateTimeBuilder(YEAR, 2008).addFieldValue(DAY_OF_YEAR, 123);
+        assertParseMatch(DateTimeFormatters.isoOrdinalDate().parseToBuilder("2008-123", new ParsePosition(0)), expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_parse_isoOrdinalDate_largeYear() {
+        DateTimeBuilder expected = new DateTimeBuilder(YEAR, 123456).addFieldValue(DAY_OF_YEAR, 123);
+        assertParseMatch(DateTimeFormatters.isoOrdinalDate().parseToBuilder("+123456-123", new ParsePosition(0)), expected);
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_print_basicIsoDate() {
+        TemporalAccessor test = buildAccessor(LocalDateTime.of(2008, 6, 3, 11, 5, 30), null, null);
+        assertEquals(DateTimeFormatters.basicIsoDate().print(test), "20080603");
+    }
+
+    @Test(groups={"tck"})
+    public void test_print_basicIsoDate_offset() {
+        TemporalAccessor test = buildAccessor(LocalDateTime.of(2008, 6, 3, 11, 5, 30), "Z", null);
+        assertEquals(DateTimeFormatters.basicIsoDate().print(test), "20080603Z");
+    }
+
+    @Test(groups={"tck"})
+    public void test_print_basicIsoDate_zoned() {
+        TemporalAccessor test = buildAccessor(LocalDateTime.of(2008, 6, 3, 11, 5, 30), "+02:00", "Europe/Paris");
+        assertEquals(DateTimeFormatters.basicIsoDate().print(test), "20080603+0200");
+    }
+
+    @Test(expectedExceptions=DateTimePrintException.class, groups={"tck"})
+    public void test_print_basicIsoDate_largeYear() {
+        TemporalAccessor test = buildAccessor(LocalDateTime.of(123456, 6, 3, 11, 5, 30), "Z", null);
+        DateTimeFormatters.basicIsoDate().print(test);
+    }
+
+    @Test(groups={"tck"})
+    public void test_print_basicIsoDate_fields() {
+        TemporalAccessor test = buildAccessor(LocalDate.of(2008, 6, 3), null, null);
+        assertEquals(DateTimeFormatters.basicIsoDate().print(test), "20080603");
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_print_basicIsoDate_missingField() {
+        TemporalAccessor test = YearMonth.of(2008, 6);
+        DateTimeFormatters.basicIsoDate().print(test);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_parse_basicIsoDate() {
+        LocalDate expected = LocalDate.of(2008, 6, 3);
+        assertEquals(DateTimeFormatters.basicIsoDate().parse("20080603", LocalDate::from), expected);
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"})
+    public void test_parse_basicIsoDate_largeYear() {
+        try {
+            LocalDate expected = LocalDate.of(123456, 6, 3);
+            assertEquals(DateTimeFormatters.basicIsoDate().parse("+1234560603", LocalDate::from), expected);
+        } catch (DateTimeParseException ex) {
+            assertEquals(ex.getErrorIndex(), 0);
+            assertEquals(ex.getParsedString(), "+1234560603");
+            throw ex;
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    @DataProvider(name="weekDate")
+    Iterator<Object[]> weekDate() {
+        return new Iterator<Object[]>() {
+            private ZonedDateTime date = ZonedDateTime.of(LocalDateTime.of(2003, 12, 29, 11, 5, 30), ZoneId.of("Europe/Paris"));
+            private ZonedDateTime endDate = date.withYear(2005).withMonth(1).withDayOfMonth(2);
+            private int week = 1;
+            private int day = 1;
+
+            public boolean hasNext() {
+                return !date.isAfter(endDate);
+            }
+            public Object[] next() {
+                StringBuilder sb = new StringBuilder("2004-W");
+                if (week < 10) {
+                    sb.append('0');
+                }
+                sb.append(week).append('-').append(day).append(date.getOffset());
+                Object[] ret = new Object[] {date, sb.toString()};
+                date = date.plusDays(1);
+                day += 1;
+                if (day == 8) {
+                    day = 1;
+                    week++;
+                }
+                return ret;
+            }
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    @Test(dataProvider="weekDate", groups={"tck"})
+    public void test_print_isoWeekDate(TemporalAccessor test, String expected) {
+        assertEquals(DateTimeFormatters.isoWeekDate().print(test), expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_print_isoWeekDate_zoned_largeYear() {
+        TemporalAccessor test = buildAccessor(LocalDateTime.of(123456, 6, 3, 11, 5, 30), "Z", null);
+        assertEquals(DateTimeFormatters.isoWeekDate().print(test), "+123456-W23-2Z");
+    }
+
+    @Test(groups={"tck"})
+    public void test_print_isoWeekDate_fields() {
+        TemporalAccessor test = buildAccessor(LocalDate.of(2004, 1, 27), null, null);
+        assertEquals(DateTimeFormatters.isoWeekDate().print(test), "2004-W05-2");
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_print_isoWeekDate_missingField() {
+        TemporalAccessor test = YearMonth.of(2008, 6);
+        DateTimeFormatters.isoWeekDate().print(test);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_parse_weekDate() {
+        LocalDate expected = LocalDate.of(2004, 1, 28);
+        assertEquals(DateTimeFormatters.isoWeekDate().parse("2004-W05-3", LocalDate::from), expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_parse_weekDate_largeYear() {
+        DateTimeBuilder builder = DateTimeFormatters.isoWeekDate().parseToBuilder("+123456-W04-5", new ParsePosition(0));
+        assertEquals(builder.getFieldValue(ISOFields.WEEK_BASED_YEAR), 123456);
+        assertEquals(builder.getFieldValue(ISOFields.WEEK_OF_WEEK_BASED_YEAR), 4);
+        assertEquals(builder.getFieldValue(DAY_OF_WEEK), 5);
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    @DataProvider(name="rfc")
+    Object[][] data_rfc() {
+        return new Object[][] {
+            {LocalDateTime.of(2008, 6, 3, 11, 5, 30), "Z", "Tue, 3 Jun 2008 11:05:30 GMT"},
+            {LocalDateTime.of(2008, 6, 30, 11, 5, 30), "Z", "Mon, 30 Jun 2008 11:05:30 GMT"},
+            {LocalDateTime.of(2008, 6, 3, 11, 5, 30), "+02:00", "Tue, 3 Jun 2008 11:05:30 +0200"},
+            {LocalDateTime.of(2008, 6, 30, 11, 5, 30), "-03:00", "Mon, 30 Jun 2008 11:05:30 -0300"},
+        };
+    }
+
+    @Test(groups={"tck"}, dataProvider="rfc")
+    public void test_print_rfc1123(LocalDateTime base, String offsetId, String expected) {
+        TemporalAccessor test = buildAccessor(base, offsetId, null);
+        assertEquals(DateTimeFormatters.rfc1123().print(test), expected);
+    }
+
+    @Test(groups={"tck"}, dataProvider="rfc")
+    public void test_print_rfc1123_french(LocalDateTime base, String offsetId, String expected) {
+        TemporalAccessor test = buildAccessor(base, offsetId, null);
+        assertEquals(DateTimeFormatters.rfc1123().withLocale(Locale.FRENCH).print(test), expected);
+    }
+
+    @Test(groups={"tck"}, expectedExceptions=DateTimeException.class)
+    public void test_print_rfc1123_missingField() {
+        TemporalAccessor test = YearMonth.of(2008, 6);
+        DateTimeFormatters.rfc1123().print(test);
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    private DateTimeBuilder createDate(Integer year, Integer month, Integer day) {
+        DateTimeBuilder test = new DateTimeBuilder();
+        if (year != null) {
+            test.addFieldValue(YEAR, year);
+        }
+        if (month != null) {
+            test.addFieldValue(MONTH_OF_YEAR, month);
+        }
+        if (day != null) {
+            test.addFieldValue(DAY_OF_MONTH, day);
+        }
+        return test;
+    }
+
+    private DateTimeBuilder createTime(Integer hour, Integer min, Integer sec, Integer nano) {
+        DateTimeBuilder test = new DateTimeBuilder();
+        if (hour != null) {
+            test.addFieldValue(HOUR_OF_DAY, hour);
+        }
+        if (min != null) {
+            test.addFieldValue(MINUTE_OF_HOUR, min);
+        }
+        if (sec != null) {
+            test.addFieldValue(SECOND_OF_MINUTE, sec);
+        }
+        if (nano != null) {
+            test.addFieldValue(NANO_OF_SECOND, nano);
+        }
+        return test;
+    }
+
+    private DateTimeBuilder createDateTime(
+            Integer year, Integer month, Integer day,
+            Integer hour, Integer min, Integer sec, Integer nano) {
+        DateTimeBuilder test = new DateTimeBuilder();
+        if (year != null) {
+            test.addFieldValue(YEAR, year);
+        }
+        if (month != null) {
+            test.addFieldValue(MONTH_OF_YEAR, month);
+        }
+        if (day != null) {
+            test.addFieldValue(DAY_OF_MONTH, day);
+        }
+        if (hour != null) {
+            test.addFieldValue(HOUR_OF_DAY, hour);
+        }
+        if (min != null) {
+            test.addFieldValue(MINUTE_OF_HOUR, min);
+        }
+        if (sec != null) {
+            test.addFieldValue(SECOND_OF_MINUTE, sec);
+        }
+        if (nano != null) {
+            test.addFieldValue(NANO_OF_SECOND, nano);
+        }
+        return test;
+    }
+
+    private TemporalAccessor buildAccessor(
+                    Integer year, Integer month, Integer day,
+                    Integer hour, Integer min, Integer sec, Integer nano,
+                    String offsetId, String zoneId) {
+        MockAccessor mock = new MockAccessor();
+        if (year != null) {
+            mock.fields.put(YEAR, (long) year);
+        }
+        if (month != null) {
+            mock.fields.put(MONTH_OF_YEAR, (long) month);
+        }
+        if (day != null) {
+            mock.fields.put(DAY_OF_MONTH, (long) day);
+        }
+        if (hour != null) {
+            mock.fields.put(HOUR_OF_DAY, (long) hour);
+        }
+        if (min != null) {
+            mock.fields.put(MINUTE_OF_HOUR, (long) min);
+        }
+        if (sec != null) {
+            mock.fields.put(SECOND_OF_MINUTE, (long) sec);
+        }
+        if (nano != null) {
+            mock.fields.put(NANO_OF_SECOND, (long) nano);
+        }
+        mock.setOffset(offsetId);
+        mock.setZone(zoneId);
+        return mock;
+    }
+
+    private TemporalAccessor buildAccessor(LocalDateTime base, String offsetId, String zoneId) {
+        MockAccessor mock = new MockAccessor();
+        mock.setFields(base);
+        mock.setOffset(offsetId);
+        mock.setZone(zoneId);
+        return mock;
+    }
+
+    private TemporalAccessor buildAccessor(LocalDate base, String offsetId, String zoneId) {
+        MockAccessor mock = new MockAccessor();
+        mock.setFields(base);
+        mock.setOffset(offsetId);
+        mock.setZone(zoneId);
+        return mock;
+    }
+
+    private void buildCalendrical(DateTimeBuilder cal, String offsetId, String zoneId) {
+        if (offsetId != null) {
+            cal.addFieldValue(OFFSET_SECONDS, ZoneOffset.of(offsetId).getTotalSeconds());
+        }
+        if (zoneId != null) {
+            cal.addCalendrical(ZoneId.of(zoneId));
+        }
+    }
+
+    private void assertParseMatch(DateTimeBuilder parsed, DateTimeBuilder expected) {
+        Map<TemporalField, Long> parsedFVMap = parsed.getFieldValueMap();
+        Map<TemporalField, Long> expectedFVMap = expected.getFieldValueMap();
+        assertEquals(parsedFVMap, expectedFVMap);
+
+        List<Object> parsedCMap = parsed.getCalendricalList();
+        List<Object> expectedCMap = expected.getCalendricalList();
+        assertEquals(parsedCMap, expectedCMap);
+    }
+
+    //-------------------------------------------------------------------------
+        Map<TemporalField, Long> fields = new HashMap<>();
+        ZoneId zoneId;
+    static class MockAccessor implements TemporalAccessor {
+        Map<TemporalField, Long> fields = new HashMap<>();
+        ZoneId zoneId;
+
+        void setFields(LocalDate dt) {
+            if (dt != null) {
+                fields.put(YEAR, (long) dt.getYear());
+                fields.put(MONTH_OF_YEAR, (long) dt.getMonthValue());
+                fields.put(DAY_OF_MONTH, (long) dt.getDayOfMonth());
+                fields.put(DAY_OF_YEAR, (long) dt.getDayOfYear());
+                fields.put(DAY_OF_WEEK, (long) dt.getDayOfWeek().getValue());
+                fields.put(ISOFields.WEEK_BASED_YEAR, dt.getLong(ISOFields.WEEK_BASED_YEAR));
+                fields.put(ISOFields.WEEK_OF_WEEK_BASED_YEAR, dt.getLong(ISOFields.WEEK_OF_WEEK_BASED_YEAR));
+            }
+        }
+
+        void setFields(LocalDateTime dt) {
+            if (dt != null) {
+                fields.put(YEAR, (long) dt.getYear());
+                fields.put(MONTH_OF_YEAR, (long) dt.getMonthValue());
+                fields.put(DAY_OF_MONTH, (long) dt.getDayOfMonth());
+                fields.put(DAY_OF_YEAR, (long) dt.getDayOfYear());
+                fields.put(DAY_OF_WEEK, (long) dt.getDayOfWeek().getValue());
+                fields.put(ISOFields.WEEK_BASED_YEAR, dt.getLong(ISOFields.WEEK_BASED_YEAR));
+                fields.put(ISOFields.WEEK_OF_WEEK_BASED_YEAR, dt.getLong(ISOFields.WEEK_OF_WEEK_BASED_YEAR));
+                fields.put(HOUR_OF_DAY, (long) dt.getHour());
+                fields.put(MINUTE_OF_HOUR, (long) dt.getMinute());
+                fields.put(SECOND_OF_MINUTE, (long) dt.getSecond());
+                fields.put(NANO_OF_SECOND, (long) dt.getNano());
+            }
+        }
+
+        void setOffset(String offsetId) {
+            if (offsetId != null) {
+                this.fields.put(OFFSET_SECONDS, (long) ZoneOffset.of(offsetId).getTotalSeconds());
+            }
+        }
+
+        void setZone(String zoneId) {
+            if (zoneId != null) {
+                this.zoneId = ZoneId.of(zoneId);
+            }
+        }
+
+        @Override
+        public boolean isSupported(TemporalField field) {
+            return fields.containsKey(field);
+        }
+
+        @Override
+        public long getLong(TemporalField field) {
+            try {
+                return fields.get(field);
+            } catch (NullPointerException ex) {
+                throw new DateTimeException("Field missing: " + field);
+            }
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public <R> R query(TemporalQuery<R> query) {
+            if (query == Queries.zoneId()) {
+                return (R) zoneId;
+            }
+            return TemporalAccessor.super.query(query);
+        }
+
+        @Override
+        public String toString() {
+            return fields + (zoneId != null ? " " + zoneId : "");
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/format/TCKDateTimePrintException.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.format;
+
+import java.time.format.*;
+import test.java.time.format.*;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.IOException;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test DateTimePrintException.
+ */
+@Test
+public class TCKDateTimePrintException {
+
+    @Test(groups={"tck"})
+    public void test_constructor_String() throws Exception {
+        DateTimePrintException ex = new DateTimePrintException("TEST");
+        assertEquals(ex.getMessage(), "TEST");
+    }
+
+    @Test(groups={"tck"})
+    public void test_constructor_StringThrowable_notIOException_equal() throws Exception {
+        IllegalArgumentException iaex = new IllegalArgumentException("INNER");
+        DateTimePrintException ex = new DateTimePrintException("TEST", iaex);
+        assertEquals(ex.getMessage(), "TEST");
+        assertEquals(ex.getCause(), iaex);
+        ex.rethrowIOException();  // no effect
+    }
+
+    @Test(expectedExceptions=IOException.class, groups={"tck"})
+    public void test_constructor_StringThrowable_IOException() throws Exception {
+        IOException ioex = new IOException("INNER");
+        DateTimePrintException ex = new DateTimePrintException("TEST", ioex);
+        assertEquals(ex.getMessage(), "TEST");
+        assertEquals(ex.getCause(), ioex);
+        ex.rethrowIOException();  // rethrows
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/format/TCKDateTimeTextPrinting.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.format;
+
+import java.time.format.*;
+
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.DAY_OF_WEEK;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static org.testng.Assert.assertEquals;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import java.time.LocalDateTime;
+import java.time.Month;
+import java.time.temporal.TemporalField;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test text printing.
+ */
+@Test
+public class TCKDateTimeTextPrinting {
+
+    private DateTimeFormatterBuilder builder;
+
+    @BeforeMethod(groups={"tck"})
+    public void setUp() {
+        builder = new DateTimeFormatterBuilder();
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="printText")
+    Object[][] data_text() {
+        return new Object[][] {
+            {DAY_OF_WEEK, TextStyle.FULL, 1, "Monday"},
+            {DAY_OF_WEEK, TextStyle.FULL, 2, "Tuesday"},
+            {DAY_OF_WEEK, TextStyle.FULL, 3, "Wednesday"},
+            {DAY_OF_WEEK, TextStyle.FULL, 4, "Thursday"},
+            {DAY_OF_WEEK, TextStyle.FULL, 5, "Friday"},
+            {DAY_OF_WEEK, TextStyle.FULL, 6, "Saturday"},
+            {DAY_OF_WEEK, TextStyle.FULL, 7, "Sunday"},
+
+            {DAY_OF_WEEK, TextStyle.SHORT, 1, "Mon"},
+            {DAY_OF_WEEK, TextStyle.SHORT, 2, "Tue"},
+            {DAY_OF_WEEK, TextStyle.SHORT, 3, "Wed"},
+            {DAY_OF_WEEK, TextStyle.SHORT, 4, "Thu"},
+            {DAY_OF_WEEK, TextStyle.SHORT, 5, "Fri"},
+            {DAY_OF_WEEK, TextStyle.SHORT, 6, "Sat"},
+            {DAY_OF_WEEK, TextStyle.SHORT, 7, "Sun"},
+
+            {DAY_OF_MONTH, TextStyle.FULL, 1, "1"},
+            {DAY_OF_MONTH, TextStyle.FULL, 2, "2"},
+            {DAY_OF_MONTH, TextStyle.FULL, 3, "3"},
+            {DAY_OF_MONTH, TextStyle.FULL, 28, "28"},
+            {DAY_OF_MONTH, TextStyle.FULL, 29, "29"},
+            {DAY_OF_MONTH, TextStyle.FULL, 30, "30"},
+            {DAY_OF_MONTH, TextStyle.FULL, 31, "31"},
+
+            {DAY_OF_MONTH, TextStyle.SHORT, 1, "1"},
+            {DAY_OF_MONTH, TextStyle.SHORT, 2, "2"},
+            {DAY_OF_MONTH, TextStyle.SHORT, 3, "3"},
+            {DAY_OF_MONTH, TextStyle.SHORT, 28, "28"},
+            {DAY_OF_MONTH, TextStyle.SHORT, 29, "29"},
+            {DAY_OF_MONTH, TextStyle.SHORT, 30, "30"},
+            {DAY_OF_MONTH, TextStyle.SHORT, 31, "31"},
+
+            {MONTH_OF_YEAR, TextStyle.FULL, 1, "January"},
+            {MONTH_OF_YEAR, TextStyle.FULL, 12, "December"},
+
+            {MONTH_OF_YEAR, TextStyle.SHORT, 1, "Jan"},
+            {MONTH_OF_YEAR, TextStyle.SHORT, 12, "Dec"},
+       };
+    }
+
+    @Test(dataProvider="printText", groups={"tck"})
+    public void test_appendText2arg_print(TemporalField field, TextStyle style, int value, String expected) throws Exception {
+        DateTimeFormatter f = builder.appendText(field, style).toFormatter(Locale.ENGLISH);
+        LocalDateTime dt = LocalDateTime.of(2010, 1, 1, 0, 0);
+        dt = dt.with(field, value);
+        String text = f.print(dt);
+        assertEquals(text, expected);
+    }
+
+    @Test(dataProvider="printText", groups={"tck"})
+    public void test_appendText1arg_print(TemporalField field, TextStyle style, int value, String expected) throws Exception {
+        if (style == TextStyle.FULL) {
+            DateTimeFormatter f = builder.appendText(field).toFormatter(Locale.ENGLISH);
+            LocalDateTime dt = LocalDateTime.of(2010, 1, 1, 0, 0);
+            dt = dt.with(field, value);
+            String text = f.print(dt);
+            assertEquals(text, expected);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_print_appendText2arg_french_long() throws Exception {
+        DateTimeFormatter f = builder.appendText(MONTH_OF_YEAR, TextStyle.FULL).toFormatter(Locale.FRENCH);
+        LocalDateTime dt = LocalDateTime.of(2010, 1, 1, 0, 0);
+        String text = f.print(dt);
+        assertEquals(text, "janvier");
+    }
+
+    @Test(groups={"tck"})
+    public void test_print_appendText2arg_french_short() throws Exception {
+        DateTimeFormatter f = builder.appendText(MONTH_OF_YEAR, TextStyle.SHORT).toFormatter(Locale.FRENCH);
+        LocalDateTime dt = LocalDateTime.of(2010, 1, 1, 0, 0);
+        String text = f.print(dt);
+        assertEquals(text, "janv.");
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_appendTextMap() throws Exception {
+        Map<Long, String> map = new HashMap<Long, String>();
+        map.put(1L, "JNY");
+        map.put(2L, "FBY");
+        map.put(3L, "MCH");
+        map.put(4L, "APL");
+        map.put(5L, "MAY");
+        map.put(6L, "JUN");
+        map.put(7L, "JLY");
+        map.put(8L, "AGT");
+        map.put(9L, "SPT");
+        map.put(10L, "OBR");
+        map.put(11L, "NVR");
+        map.put(12L, "DBR");
+        builder.appendText(MONTH_OF_YEAR, map);
+        DateTimeFormatter f = builder.toFormatter();
+        LocalDateTime dt = LocalDateTime.of(2010, 1, 1, 0, 0);
+        for (Month month : Month.values()) {
+            assertEquals(f.print(dt.with(month)), map.get((long) month.getValue()));
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_appendTextMap_DOM() throws Exception {
+        Map<Long, String> map = new HashMap<Long, String>();
+        map.put(1L, "1st");
+        map.put(2L, "2nd");
+        map.put(3L, "3rd");
+        builder.appendText(DAY_OF_MONTH, map);
+        DateTimeFormatter f = builder.toFormatter();
+        LocalDateTime dt = LocalDateTime.of(2010, 1, 1, 0, 0);
+        assertEquals(f.print(dt.withDayOfMonth(1)), "1st");
+        assertEquals(f.print(dt.withDayOfMonth(2)), "2nd");
+        assertEquals(f.print(dt.withDayOfMonth(3)), "3rd");
+    }
+
+    @Test(groups={"tck"})
+    public void test_appendTextMapIncomplete() throws Exception {
+        Map<Long, String> map = new HashMap<Long, String>();
+        map.put(1L, "JNY");
+        builder.appendText(MONTH_OF_YEAR, map);
+        DateTimeFormatter f = builder.toFormatter();
+        LocalDateTime dt = LocalDateTime.of(2010, 2, 1, 0, 0);
+        assertEquals(f.print(dt), "2");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/format/TCKLocalizedFieldParser.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2010-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.format;
+
+import java.time.format.*;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+
+import java.text.ParsePosition;
+import java.time.format.DateTimeBuilder;
+
+import java.time.LocalDate;
+import java.time.temporal.TemporalField;
+import java.time.temporal.WeekFields;
+
+import test.java.time.format.AbstractTestPrinterParser;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test TCKLocalizedFieldParser.
+ */
+@Test(groups={"tck"})
+public class TCKLocalizedFieldParser extends AbstractTestPrinterParser {
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="FieldPatterns")
+    Object[][] provider_fieldPatterns() {
+        return new Object[][] {
+            {"e",  "6", 0, 1, 6},
+            {"w",  "3", 0, 1, 3},
+            {"W",  "29", 0, 2, 29},
+            {"WW", "29", 0, 2, 29},
+        };
+    }
+
+    @Test(dataProvider="FieldPatterns",groups={"tck"})
+    public void test_parse_textField(String pattern, String text, int pos, int expectedPos, long expectedValue) {
+        WeekFields weekDef = WeekFields.of(locale);
+        TemporalField field = null;
+        switch(pattern.charAt(0)) {
+            case 'e' :
+                field = weekDef.dayOfWeek();
+                break;
+            case 'w':
+                field = weekDef.weekOfMonth();
+                break;
+            case 'W':
+                field = weekDef.weekOfYear();
+                break;
+            default:
+                throw new IllegalStateException("bad format letter from pattern");
+        }
+        ParsePosition ppos = new ParsePosition(pos);
+        DateTimeFormatterBuilder b
+                = new DateTimeFormatterBuilder().appendPattern(pattern);
+        DateTimeFormatter dtf = b.toFormatter(locale);
+        DateTimeBuilder dtb = dtf.parseToBuilder(text, ppos);
+        if (ppos.getErrorIndex() != -1) {
+            assertEquals(ppos.getErrorIndex(), expectedPos);
+        } else {
+            assertEquals(ppos.getIndex(), expectedPos, "Incorrect ending parse position");
+            long value = dtb.getLong(field);
+            assertEquals(value, expectedValue, "Value incorrect for " + field);
+        }
+    }
+
+   //-----------------------------------------------------------------------
+    @DataProvider(name="LocalDatePatterns")
+    Object[][] provider_patternLocalDate() {
+        return new Object[][] {
+            {"e w M y",  "1 1 1 2012", 0, 10, LocalDate.of(2012, 1, 1)},
+            {"e w M y",  "1 2 1 2012", 0, 10, LocalDate.of(2012, 1, 8)},
+            {"e w M y",  "2 2 1 2012", 0, 10, LocalDate.of(2012, 1, 9)},
+            {"e w M y",  "3 2 1 2012", 0, 10, LocalDate.of(2012, 1, 10)},
+            {"e w M y",  "1 3 1 2012", 0, 10, LocalDate.of(2012, 1, 15)},
+            {"e w M y",  "2 3 1 2012", 0, 10, LocalDate.of(2012, 1, 16)},
+            {"e w M y",  "6 2 1 2012", 0, 10, LocalDate.of(2012, 1, 13)},
+            {"e w M y",  "6 2 7 2012", 0, 10, LocalDate.of(2012, 7, 13)},
+            {"e W y",  "6 29 2012", 0, 9, LocalDate.of(2012, 7, 20)},
+            {"'Date: 'y-MM', day-of-week: 'e', week-of-month: 'w",
+                "Date: 2012-07, day-of-week: 6, week-of-month: 3", 0, 47, LocalDate.of(2012, 7, 20)},
+            {"'Date: 'y', day-of-week: 'e', week-of-year: 'W",
+                "Date: 2012, day-of-week: 6, week-of-year: 29", 0, 44, LocalDate.of(2012, 7, 20)},
+        };
+    }
+   @Test(dataProvider="LocalDatePatterns",groups={"tck"})
+    public void test_parse_textLocalDate(String pattern, String text, int pos, int expectedPos, LocalDate expectedValue) {
+        WeekFields weekDef = WeekFields.of(locale);
+        ParsePosition ppos = new ParsePosition(pos);
+        DateTimeFormatterBuilder b
+                = new DateTimeFormatterBuilder().appendPattern(pattern);
+        DateTimeFormatter dtf = b.toFormatter(locale);
+        DateTimeBuilder dtb = dtf.parseToBuilder(text, ppos);
+        if (ppos.getErrorIndex() != -1) {
+            assertEquals(ppos.getErrorIndex(), expectedPos);
+        } else {
+            assertEquals(ppos.getIndex(), expectedPos, "Incorrect ending parse position");
+            dtb.resolve();
+            LocalDate result = dtb.query(LocalDate::from);
+            assertEquals(result, expectedValue, "LocalDate incorrect for " + pattern);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/format/TCKLocalizedFieldPrinter.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2010-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.format;
+
+import java.time.format.*;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+
+import java.time.LocalDate;
+
+import test.java.time.format.AbstractTestPrinterParser;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test LocalizedFieldPrinterParser.
+ */
+@Test(groups={"tck"})
+public class TCKLocalizedFieldPrinter extends AbstractTestPrinterParser {
+
+        //-----------------------------------------------------------------------
+    @DataProvider(name="Patterns")
+    Object[][] provider_pad() {
+        return new Object[][] {
+            {"e",  "6"},
+            {"w",  "3"},
+            {"W",  "29"},
+            {"WW", "29"},
+            {"'Date: 'y-MM-d', week-of-month: 'w', week-of-year: 'W",
+                "Date: 2012-07-20, week-of-month: 3, week-of-year: 29"},
+
+        };
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="Patterns",groups={"tck"})
+    public void test_localizedDayOfWeek(String pattern, String expected) {
+        DateTimeFormatterBuilder b
+                = new DateTimeFormatterBuilder().appendPattern(pattern);
+        LocalDate date = LocalDate.of(2012, 7, 20);
+
+        String result = b.toFormatter(locale).print(date);
+        assertEquals(result, expected, "Wrong output for pattern '" + pattern + "'.");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/temporal/TCKDateTimeAdjusters.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,601 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.temporal;
+
+import java.time.temporal.*;
+
+import static java.time.DayOfWeek.MONDAY;
+import static java.time.DayOfWeek.TUESDAY;
+import static java.time.Month.DECEMBER;
+import static java.time.Month.JANUARY;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
+
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+import java.time.Month;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test Adjusters.
+ */
+@Test
+public class TCKDateTimeAdjusters {
+
+    //-----------------------------------------------------------------------
+    // firstDayOfMonth()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_firstDayOfMonth() {
+        assertNotNull(Adjusters.firstDayOfMonth());
+    }
+
+    @Test(groups={"tck"})
+    public void test_firstDayOfMonth_nonLeap() {
+        for (Month month : Month.values()) {
+            for (int i = 1; i <= month.length(false); i++) {
+                LocalDate date = date(2007, month, i);
+                LocalDate test = (LocalDate) Adjusters.firstDayOfMonth().adjustInto(date);
+                assertEquals(test.getYear(), 2007);
+                assertEquals(test.getMonth(), month);
+                assertEquals(test.getDayOfMonth(), 1);
+            }
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_firstDayOfMonth_leap() {
+        for (Month month : Month.values()) {
+            for (int i = 1; i <= month.length(true); i++) {
+                LocalDate date = date(2008, month, i);
+                LocalDate test = (LocalDate) Adjusters.firstDayOfMonth().adjustInto(date);
+                assertEquals(test.getYear(), 2008);
+                assertEquals(test.getMonth(), month);
+                assertEquals(test.getDayOfMonth(), 1);
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // lastDayOfMonth()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_lastDayOfMonth() {
+        assertNotNull(Adjusters.lastDayOfMonth());
+    }
+
+    @Test(groups={"tck"})
+    public void test_lastDayOfMonth_nonLeap() {
+        for (Month month : Month.values()) {
+            for (int i = 1; i <= month.length(false); i++) {
+                LocalDate date = date(2007, month, i);
+                LocalDate test = (LocalDate) Adjusters.lastDayOfMonth().adjustInto(date);
+                assertEquals(test.getYear(), 2007);
+                assertEquals(test.getMonth(), month);
+                assertEquals(test.getDayOfMonth(), month.length(false));
+            }
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_lastDayOfMonth_leap() {
+        for (Month month : Month.values()) {
+            for (int i = 1; i <= month.length(true); i++) {
+                LocalDate date = date(2008, month, i);
+                LocalDate test = (LocalDate) Adjusters.lastDayOfMonth().adjustInto(date);
+                assertEquals(test.getYear(), 2008);
+                assertEquals(test.getMonth(), month);
+                assertEquals(test.getDayOfMonth(), month.length(true));
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // firstDayOfNextMonth()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_firstDayOfNextMonth() {
+        assertNotNull(Adjusters.firstDayOfNextMonth());
+    }
+
+    @Test(groups={"tck"})
+    public void test_firstDayOfNextMonth_nonLeap() {
+        for (Month month : Month.values()) {
+            for (int i = 1; i <= month.length(false); i++) {
+                LocalDate date = date(2007, month, i);
+                LocalDate test = (LocalDate) Adjusters.firstDayOfNextMonth().adjustInto(date);
+                assertEquals(test.getYear(), month == DECEMBER ? 2008 : 2007);
+                assertEquals(test.getMonth(), month.plus(1));
+                assertEquals(test.getDayOfMonth(), 1);
+            }
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_firstDayOfNextMonth_leap() {
+        for (Month month : Month.values()) {
+            for (int i = 1; i <= month.length(true); i++) {
+                LocalDate date = date(2008, month, i);
+                LocalDate test = (LocalDate) Adjusters.firstDayOfNextMonth().adjustInto(date);
+                assertEquals(test.getYear(), month == DECEMBER ? 2009 : 2008);
+                assertEquals(test.getMonth(), month.plus(1));
+                assertEquals(test.getDayOfMonth(), 1);
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // firstDayOfYear()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_firstDayOfYear() {
+        assertNotNull(Adjusters.firstDayOfYear());
+    }
+
+    @Test(groups={"tck"})
+    public void test_firstDayOfYear_nonLeap() {
+        for (Month month : Month.values()) {
+            for (int i = 1; i <= month.length(false); i++) {
+                LocalDate date = date(2007, month, i);
+                LocalDate test = (LocalDate) Adjusters.firstDayOfYear().adjustInto(date);
+                assertEquals(test.getYear(), 2007);
+                assertEquals(test.getMonth(), Month.JANUARY);
+                assertEquals(test.getDayOfMonth(), 1);
+            }
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_firstDayOfYear_leap() {
+        for (Month month : Month.values()) {
+            for (int i = 1; i <= month.length(true); i++) {
+                LocalDate date = date(2008, month, i);
+                LocalDate test = (LocalDate) Adjusters.firstDayOfYear().adjustInto(date);
+                assertEquals(test.getYear(), 2008);
+                assertEquals(test.getMonth(), Month.JANUARY);
+                assertEquals(test.getDayOfMonth(), 1);
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // lastDayOfYear()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_lastDayOfYear() {
+        assertNotNull(Adjusters.lastDayOfYear());
+    }
+
+    @Test(groups={"tck"})
+    public void test_lastDayOfYear_nonLeap() {
+        for (Month month : Month.values()) {
+            for (int i = 1; i <= month.length(false); i++) {
+                LocalDate date = date(2007, month, i);
+                LocalDate test = (LocalDate) Adjusters.lastDayOfYear().adjustInto(date);
+                assertEquals(test.getYear(), 2007);
+                assertEquals(test.getMonth(), Month.DECEMBER);
+                assertEquals(test.getDayOfMonth(), 31);
+            }
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_lastDayOfYear_leap() {
+        for (Month month : Month.values()) {
+            for (int i = 1; i <= month.length(true); i++) {
+                LocalDate date = date(2008, month, i);
+                LocalDate test = (LocalDate) Adjusters.lastDayOfYear().adjustInto(date);
+                assertEquals(test.getYear(), 2008);
+                assertEquals(test.getMonth(), Month.DECEMBER);
+                assertEquals(test.getDayOfMonth(), 31);
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // firstDayOfNextYear()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_firstDayOfNextYear() {
+        assertNotNull(Adjusters.firstDayOfNextYear());
+    }
+
+    @Test(groups={"tck"})
+    public void test_firstDayOfNextYear_nonLeap() {
+        for (Month month : Month.values()) {
+            for (int i = 1; i <= month.length(false); i++) {
+                LocalDate date = date(2007, month, i);
+                LocalDate test = (LocalDate) Adjusters.firstDayOfNextYear().adjustInto(date);
+                assertEquals(test.getYear(), 2008);
+                assertEquals(test.getMonth(), JANUARY);
+                assertEquals(test.getDayOfMonth(), 1);
+            }
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_firstDayOfNextYear_leap() {
+        for (Month month : Month.values()) {
+            for (int i = 1; i <= month.length(true); i++) {
+                LocalDate date = date(2008, month, i);
+                LocalDate test = (LocalDate) Adjusters.firstDayOfNextYear().adjustInto(date);
+                assertEquals(test.getYear(), 2009);
+                assertEquals(test.getMonth(), JANUARY);
+                assertEquals(test.getDayOfMonth(), 1);
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // dayOfWeekInMonth()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_dayOfWeekInMonth() {
+        assertNotNull(Adjusters.dayOfWeekInMonth(1, MONDAY));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_dayOfWeekInMonth_nullDayOfWeek() {
+        Adjusters.dayOfWeekInMonth(1, null);
+    }
+
+    @DataProvider(name = "dayOfWeekInMonth_positive")
+    Object[][] data_dayOfWeekInMonth_positive() {
+        return new Object[][] {
+            {2011, 1, TUESDAY, date(2011, 1, 4)},
+            {2011, 2, TUESDAY, date(2011, 2, 1)},
+            {2011, 3, TUESDAY, date(2011, 3, 1)},
+            {2011, 4, TUESDAY, date(2011, 4, 5)},
+            {2011, 5, TUESDAY, date(2011, 5, 3)},
+            {2011, 6, TUESDAY, date(2011, 6, 7)},
+            {2011, 7, TUESDAY, date(2011, 7, 5)},
+            {2011, 8, TUESDAY, date(2011, 8, 2)},
+            {2011, 9, TUESDAY, date(2011, 9, 6)},
+            {2011, 10, TUESDAY, date(2011, 10, 4)},
+            {2011, 11, TUESDAY, date(2011, 11, 1)},
+            {2011, 12, TUESDAY, date(2011, 12, 6)},
+        };
+    }
+
+    @Test(groups={"tck"}, dataProvider = "dayOfWeekInMonth_positive")
+    public void test_dayOfWeekInMonth_positive(int year, int month, DayOfWeek dow, LocalDate expected) {
+        for (int ordinal = 1; ordinal <= 5; ordinal++) {
+            for (int day = 1; day <= Month.of(month).length(false); day++) {
+                LocalDate date = date(year, month, day);
+                LocalDate test = (LocalDate) Adjusters.dayOfWeekInMonth(ordinal, dow).adjustInto(date);
+                assertEquals(test, expected.plusWeeks(ordinal - 1));
+            }
+        }
+    }
+
+    @DataProvider(name = "dayOfWeekInMonth_zero")
+    Object[][] data_dayOfWeekInMonth_zero() {
+        return new Object[][] {
+            {2011, 1, TUESDAY, date(2010, 12, 28)},
+            {2011, 2, TUESDAY, date(2011, 1, 25)},
+            {2011, 3, TUESDAY, date(2011, 2, 22)},
+            {2011, 4, TUESDAY, date(2011, 3, 29)},
+            {2011, 5, TUESDAY, date(2011, 4, 26)},
+            {2011, 6, TUESDAY, date(2011, 5, 31)},
+            {2011, 7, TUESDAY, date(2011, 6, 28)},
+            {2011, 8, TUESDAY, date(2011, 7, 26)},
+            {2011, 9, TUESDAY, date(2011, 8, 30)},
+            {2011, 10, TUESDAY, date(2011, 9, 27)},
+            {2011, 11, TUESDAY, date(2011, 10, 25)},
+            {2011, 12, TUESDAY, date(2011, 11, 29)},
+        };
+    }
+
+    @Test(groups={"tck"}, dataProvider = "dayOfWeekInMonth_zero")
+    public void test_dayOfWeekInMonth_zero(int year, int month, DayOfWeek dow, LocalDate expected) {
+        for (int day = 1; day <= Month.of(month).length(false); day++) {
+            LocalDate date = date(year, month, day);
+            LocalDate test = (LocalDate) Adjusters.dayOfWeekInMonth(0, dow).adjustInto(date);
+            assertEquals(test, expected);
+        }
+    }
+
+    @DataProvider(name = "dayOfWeekInMonth_negative")
+    Object[][] data_dayOfWeekInMonth_negative() {
+        return new Object[][] {
+            {2011, 1, TUESDAY, date(2011, 1, 25)},
+            {2011, 2, TUESDAY, date(2011, 2, 22)},
+            {2011, 3, TUESDAY, date(2011, 3, 29)},
+            {2011, 4, TUESDAY, date(2011, 4, 26)},
+            {2011, 5, TUESDAY, date(2011, 5, 31)},
+            {2011, 6, TUESDAY, date(2011, 6, 28)},
+            {2011, 7, TUESDAY, date(2011, 7, 26)},
+            {2011, 8, TUESDAY, date(2011, 8, 30)},
+            {2011, 9, TUESDAY, date(2011, 9, 27)},
+            {2011, 10, TUESDAY, date(2011, 10, 25)},
+            {2011, 11, TUESDAY, date(2011, 11, 29)},
+            {2011, 12, TUESDAY, date(2011, 12, 27)},
+        };
+    }
+
+    @Test(groups={"tck"}, dataProvider = "dayOfWeekInMonth_negative")
+    public void test_dayOfWeekInMonth_negative(int year, int month, DayOfWeek dow, LocalDate expected) {
+        for (int ordinal = 0; ordinal < 5; ordinal++) {
+            for (int day = 1; day <= Month.of(month).length(false); day++) {
+                LocalDate date = date(year, month, day);
+                LocalDate test = (LocalDate) Adjusters.dayOfWeekInMonth(-1 - ordinal, dow).adjustInto(date);
+                assertEquals(test, expected.minusWeeks(ordinal));
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // firstInMonth()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_firstInMonth() {
+        assertNotNull(Adjusters.firstInMonth(MONDAY));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_firstInMonth_nullDayOfWeek() {
+        Adjusters.firstInMonth(null);
+    }
+
+    @Test(groups={"tck"}, dataProvider = "dayOfWeekInMonth_positive")
+    public void test_firstInMonth(int year, int month, DayOfWeek dow, LocalDate expected) {
+        for (int day = 1; day <= Month.of(month).length(false); day++) {
+            LocalDate date = date(year, month, day);
+            LocalDate test = (LocalDate) Adjusters.firstInMonth(dow).adjustInto(date);
+            assertEquals(test, expected, "day-of-month=" + day);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // lastInMonth()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_lastInMonth() {
+        assertNotNull(Adjusters.lastInMonth(MONDAY));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_lastInMonth_nullDayOfWeek() {
+        Adjusters.lastInMonth(null);
+    }
+
+    @Test(groups={"tck"}, dataProvider = "dayOfWeekInMonth_negative")
+    public void test_lastInMonth(int year, int month, DayOfWeek dow, LocalDate expected) {
+        for (int day = 1; day <= Month.of(month).length(false); day++) {
+            LocalDate date = date(year, month, day);
+            LocalDate test = (LocalDate) Adjusters.lastInMonth(dow).adjustInto(date);
+            assertEquals(test, expected, "day-of-month=" + day);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // next()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_next() {
+        assertNotNull(Adjusters.next(MONDAY));
+    }
+
+    @Test(expectedExceptions = NullPointerException.class, groups={"tck"})
+    public void factory_next_nullDayOfWeek() {
+        Adjusters.next(null);
+    }
+
+    @Test(groups={"tck"})
+    public void test_next() {
+        for (Month month : Month.values()) {
+            for (int i = 1; i <= month.length(false); i++) {
+                LocalDate date = date(2007, month, i);
+
+                for (DayOfWeek dow : DayOfWeek.values()) {
+                    LocalDate test = (LocalDate) Adjusters.next(dow).adjustInto(date);
+
+                    assertSame(test.getDayOfWeek(), dow, date + " " + test);
+
+                    if (test.getYear() == 2007) {
+                        int dayDiff = test.getDayOfYear() - date.getDayOfYear();
+                        assertTrue(dayDiff > 0 && dayDiff < 8);
+                    } else {
+                        assertSame(month, Month.DECEMBER);
+                        assertTrue(date.getDayOfMonth() > 24);
+                        assertEquals(test.getYear(), 2008);
+                        assertSame(test.getMonth(), Month.JANUARY);
+                        assertTrue(test.getDayOfMonth() < 8);
+                    }
+                }
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // nextOrSame()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_nextOrCurrent() {
+        assertNotNull(Adjusters.nextOrSame(MONDAY));
+    }
+
+    @Test(expectedExceptions = NullPointerException.class, groups={"tck"})
+    public void factory_nextOrCurrent_nullDayOfWeek() {
+        Adjusters.nextOrSame(null);
+    }
+
+    @Test(groups={"tck"})
+    public void test_nextOrCurrent() {
+        for (Month month : Month.values()) {
+            for (int i = 1; i <= month.length(false); i++) {
+                LocalDate date = date(2007, month, i);
+
+                for (DayOfWeek dow : DayOfWeek.values()) {
+                    LocalDate test = (LocalDate) Adjusters.nextOrSame(dow).adjustInto(date);
+
+                    assertSame(test.getDayOfWeek(), dow);
+
+                    if (test.getYear() == 2007) {
+                        int dayDiff = test.getDayOfYear() - date.getDayOfYear();
+                        assertTrue(dayDiff < 8);
+                        assertEquals(date.equals(test), date.getDayOfWeek() == dow);
+                    } else {
+                        assertFalse(date.getDayOfWeek() == dow);
+                        assertSame(month, Month.DECEMBER);
+                        assertTrue(date.getDayOfMonth() > 24);
+                        assertEquals(test.getYear(), 2008);
+                        assertSame(test.getMonth(), Month.JANUARY);
+                        assertTrue(test.getDayOfMonth() < 8);
+                    }
+                }
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // previous()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_previous() {
+        assertNotNull(Adjusters.previous(MONDAY));
+    }
+
+    @Test(expectedExceptions = NullPointerException.class, groups={"tck"})
+    public void factory_previous_nullDayOfWeek() {
+        Adjusters.previous(null);
+    }
+
+    @Test(groups={"tck"})
+    public void test_previous() {
+        for (Month month : Month.values()) {
+            for (int i = 1; i <= month.length(false); i++) {
+                LocalDate date = date(2007, month, i);
+
+                for (DayOfWeek dow : DayOfWeek.values()) {
+                    LocalDate test = (LocalDate) Adjusters.previous(dow).adjustInto(date);
+
+                    assertSame(test.getDayOfWeek(), dow, date + " " + test);
+
+                    if (test.getYear() == 2007) {
+                        int dayDiff = test.getDayOfYear() - date.getDayOfYear();
+                        assertTrue(dayDiff < 0 && dayDiff > -8, dayDiff + " " + test);
+                    } else {
+                        assertSame(month, Month.JANUARY);
+                        assertTrue(date.getDayOfMonth() < 8);
+                        assertEquals(test.getYear(), 2006);
+                        assertSame(test.getMonth(), Month.DECEMBER);
+                        assertTrue(test.getDayOfMonth() > 24);
+                    }
+                }
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // previousOrSame()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_previousOrCurrent() {
+        assertNotNull(Adjusters.previousOrSame(MONDAY));
+    }
+
+    @Test(expectedExceptions = NullPointerException.class, groups={"tck"})
+    public void factory_previousOrCurrent_nullDayOfWeek() {
+        Adjusters.previousOrSame(null);
+    }
+
+    @Test(groups={"tck"})
+    public void test_previousOrCurrent() {
+        for (Month month : Month.values()) {
+            for (int i = 1; i <= month.length(false); i++) {
+                LocalDate date = date(2007, month, i);
+
+                for (DayOfWeek dow : DayOfWeek.values()) {
+                    LocalDate test = (LocalDate) Adjusters.previousOrSame(dow).adjustInto(date);
+
+                    assertSame(test.getDayOfWeek(), dow);
+
+                    if (test.getYear() == 2007) {
+                        int dayDiff = test.getDayOfYear() - date.getDayOfYear();
+                        assertTrue(dayDiff <= 0 && dayDiff > -7);
+                        assertEquals(date.equals(test), date.getDayOfWeek() == dow);
+                    } else {
+                        assertFalse(date.getDayOfWeek() == dow);
+                        assertSame(month, Month.JANUARY);
+                        assertTrue(date.getDayOfMonth() < 7);
+                        assertEquals(test.getYear(), 2006);
+                        assertSame(test.getMonth(), Month.DECEMBER);
+                        assertTrue(test.getDayOfMonth() > 25);
+                    }
+                }
+            }
+        }
+    }
+
+    private LocalDate date(int year, Month month, int day) {
+        return LocalDate.of(year, month, day);
+    }
+
+    private LocalDate date(int year, int month, int day) {
+        return LocalDate.of(year, month, day);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/temporal/TCKISOFields.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.temporal;
+
+import java.time.format.DateTimeBuilder;
+import java.time.temporal.*;
+
+import static java.time.DayOfWeek.FRIDAY;
+import static java.time.DayOfWeek.MONDAY;
+import static java.time.DayOfWeek.SATURDAY;
+import static java.time.DayOfWeek.SUNDAY;
+import static java.time.DayOfWeek.THURSDAY;
+import static java.time.DayOfWeek.TUESDAY;
+import static java.time.DayOfWeek.WEDNESDAY;
+import static java.time.temporal.ChronoField.DAY_OF_WEEK;
+import static java.time.temporal.ChronoField.YEAR;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test.
+ */
+@Test(groups={"tck"})
+public class TCKISOFields {
+
+    @DataProvider(name="quarter")
+    Object[][] data_quarter() {
+        return new Object[][] {
+                {LocalDate.of(1969, 12, 29), 90, 4},
+                {LocalDate.of(1969, 12, 30), 91, 4},
+                {LocalDate.of(1969, 12, 31), 92, 4},
+
+                {LocalDate.of(1970, 1, 1), 1, 1},
+                {LocalDate.of(1970, 1, 2), 2, 1},
+                {LocalDate.of(1970, 2, 28), 59, 1},
+                {LocalDate.of(1970, 3, 1), 60, 1},
+                {LocalDate.of(1970, 3, 31), 90, 1},
+
+                {LocalDate.of(1970, 4, 1), 1, 2},
+                {LocalDate.of(1970, 6, 30), 91, 2},
+
+                {LocalDate.of(1970, 7, 1), 1, 3},
+                {LocalDate.of(1970, 9, 30), 92, 3},
+
+                {LocalDate.of(1970, 10, 1), 1, 4},
+                {LocalDate.of(1970, 12, 31), 92, 4},
+
+                {LocalDate.of(1972, 2, 28), 59, 1},
+                {LocalDate.of(1972, 2, 29), 60, 1},
+                {LocalDate.of(1972, 3, 1), 61, 1},
+                {LocalDate.of(1972, 3, 31), 91, 1},
+        };
+    }
+
+    //-----------------------------------------------------------------------
+    // DAY_OF_QUARTER
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="quarter")
+    public void test_DOQ(LocalDate date, int doq, int qoy) {
+        assertEquals(ISOFields.DAY_OF_QUARTER.doGet(date), doq);
+        assertEquals(date.get(ISOFields.DAY_OF_QUARTER), doq);
+    }
+
+    //-----------------------------------------------------------------------
+    // QUARTER_OF_YEAR
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="quarter")
+    public void test_QOY(LocalDate date, int doq, int qoy) {
+        assertEquals(ISOFields.QUARTER_OF_YEAR.doGet(date), qoy);
+        assertEquals(date.get(ISOFields.QUARTER_OF_YEAR), qoy);
+    }
+
+    //-----------------------------------------------------------------------
+    // builder
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="quarter")
+    public void test_builder_quarters(LocalDate date, int doq, int qoy) {
+        DateTimeBuilder builder = new DateTimeBuilder();
+        builder.addFieldValue(ISOFields.DAY_OF_QUARTER, doq);
+        builder.addFieldValue(ISOFields.QUARTER_OF_YEAR, qoy);
+        builder.addFieldValue(YEAR, date.getYear());
+        builder.resolve();
+        assertEquals(builder.query(LocalDate::from), date);
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    @DataProvider(name="week")
+    Object[][] data_week() {
+        return new Object[][] {
+                {LocalDate.of(1969, 12, 29), MONDAY, 1, 1970},
+                {LocalDate.of(2012, 12, 23), SUNDAY, 51, 2012},
+                {LocalDate.of(2012, 12, 24), MONDAY, 52, 2012},
+                {LocalDate.of(2012, 12, 27), THURSDAY, 52, 2012},
+                {LocalDate.of(2012, 12, 28), FRIDAY, 52, 2012},
+                {LocalDate.of(2012, 12, 29), SATURDAY, 52, 2012},
+                {LocalDate.of(2012, 12, 30), SUNDAY, 52, 2012},
+                {LocalDate.of(2012, 12, 31), MONDAY, 1, 2013},
+                {LocalDate.of(2013, 1, 1), TUESDAY, 1, 2013},
+                {LocalDate.of(2013, 1, 2), WEDNESDAY, 1, 2013},
+                {LocalDate.of(2013, 1, 6), SUNDAY, 1, 2013},
+                {LocalDate.of(2013, 1, 7), MONDAY, 2, 2013},
+        };
+    }
+
+    //-----------------------------------------------------------------------
+    // WEEK_OF_WEEK_BASED_YEAR
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="week")
+    public void test_WOWBY(LocalDate date, DayOfWeek dow, int week, int wby) {
+        assertEquals(date.getDayOfWeek(), dow);
+        assertEquals(ISOFields.WEEK_OF_WEEK_BASED_YEAR.doGet(date), week);
+        assertEquals(date.get(ISOFields.WEEK_OF_WEEK_BASED_YEAR), week);
+    }
+
+    //-----------------------------------------------------------------------
+    // WEEK_BASED_YEAR
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="week")
+    public void test_WBY(LocalDate date, DayOfWeek dow, int week, int wby) {
+        assertEquals(date.getDayOfWeek(), dow);
+        assertEquals(ISOFields.WEEK_BASED_YEAR.doGet(date), wby);
+        assertEquals(date.get(ISOFields.WEEK_BASED_YEAR), wby);
+    }
+
+    //-----------------------------------------------------------------------
+    // builder
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="week")
+    public void test_builder_weeks(LocalDate date, DayOfWeek dow, int week, int wby) {
+        DateTimeBuilder builder = new DateTimeBuilder();
+        builder.addFieldValue(ISOFields.WEEK_BASED_YEAR, wby);
+        builder.addFieldValue(ISOFields.WEEK_OF_WEEK_BASED_YEAR, week);
+        builder.addFieldValue(DAY_OF_WEEK, dow.getValue());
+        builder.resolve();
+        assertEquals(builder.query(LocalDate::from), date);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_loop() {
+        // loop round at least one 400 year cycle, including before 1970
+        LocalDate date = LocalDate.of(1960, 1, 5);  // Tuseday of week 1 1960
+        int year = 1960;
+        int wby = 1960;
+        int weekLen = 52;
+        int week = 1;
+        while (date.getYear() < 2400) {
+            DayOfWeek loopDow = date.getDayOfWeek();
+            if (date.getYear() != year) {
+                year = date.getYear();
+            }
+            if (loopDow == MONDAY) {
+                week++;
+                if ((week == 53 && weekLen == 52) || week == 54) {
+                    week = 1;
+                    LocalDate firstDayOfWeekBasedYear = date.plusDays(14).withDayOfYear(1);
+                    DayOfWeek firstDay = firstDayOfWeekBasedYear.getDayOfWeek();
+                    weekLen = (firstDay == THURSDAY || (firstDay == WEDNESDAY && firstDayOfWeekBasedYear.isLeapYear()) ? 53 : 52);
+                    wby++;
+                }
+            }
+            assertEquals(ISOFields.WEEK_OF_WEEK_BASED_YEAR.doRange(date), ValueRange.of(1, weekLen), "Failed on " + date + " " + date.getDayOfWeek());
+            assertEquals(ISOFields.WEEK_OF_WEEK_BASED_YEAR.doGet(date), week, "Failed on " + date + " " + date.getDayOfWeek());
+            assertEquals(date.get(ISOFields.WEEK_OF_WEEK_BASED_YEAR), week, "Failed on " + date + " " + date.getDayOfWeek());
+            assertEquals(ISOFields.WEEK_BASED_YEAR.doGet(date), wby, "Failed on " + date + " " + date.getDayOfWeek());
+            assertEquals(date.get(ISOFields.WEEK_BASED_YEAR), wby, "Failed on " + date + " " + date.getDayOfWeek());
+            date = date.plusDays(1);
+        }
+    }
+
+    // TODO: more tests
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/temporal/TCKJulianFields.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.temporal;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertSame;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import java.time.LocalDate;
+
+import java.time.temporal.*;
+
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test.
+ */
+@Test
+public class TCKJulianFields {
+
+    private static final LocalDate JAN01_1970 = LocalDate.of(1970, 1, 1);
+    private static final LocalDate DEC31_1969 = LocalDate.of(1969, 12, 31);
+    private static final LocalDate NOV12_1945 = LocalDate.of(1945, 11, 12);
+    private static final LocalDate JAN01_0001 = LocalDate.of(1, 1, 1);
+
+    @BeforeMethod
+    public void setUp() {
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="julian_fields")
+    Object[][] julian_samples() {
+        return new Object[][] {
+            {JulianFields.JULIAN_DAY},
+            {JulianFields.MODIFIED_JULIAN_DAY},
+            {JulianFields.RATA_DIE},
+        };
+    }
+
+    @DataProvider(name="samples")
+    Object[][] data_samples() {
+        return new Object[][] {
+            {ChronoField.EPOCH_DAY, JAN01_1970, 0L},
+            {JulianFields.JULIAN_DAY, JAN01_1970, 2400001L + 40587L},
+            {JulianFields.MODIFIED_JULIAN_DAY, JAN01_1970, 40587L},
+            {JulianFields.RATA_DIE, JAN01_1970, 710347L + (40587L - 31771L)},
+
+            {ChronoField.EPOCH_DAY, DEC31_1969, -1L},
+            {JulianFields.JULIAN_DAY, DEC31_1969, 2400001L + 40586L},
+            {JulianFields.MODIFIED_JULIAN_DAY, DEC31_1969, 40586L},
+            {JulianFields.RATA_DIE, DEC31_1969, 710347L + (40586L - 31771L)},
+
+            {ChronoField.EPOCH_DAY, NOV12_1945, (-24 * 365 - 6) - 31 - 30 + 11},
+            {JulianFields.JULIAN_DAY, NOV12_1945, 2431772L},
+            {JulianFields.MODIFIED_JULIAN_DAY, NOV12_1945, 31771L},
+            {JulianFields.RATA_DIE, NOV12_1945, 710347L},
+
+            {ChronoField.EPOCH_DAY, JAN01_0001, (-24 * 365 - 6) - 31 - 30 + 11 - 710346L},
+            {JulianFields.JULIAN_DAY, JAN01_0001, 2431772L - 710346L},
+            {JulianFields.MODIFIED_JULIAN_DAY, JAN01_0001, 31771L - 710346L},
+            {JulianFields.RATA_DIE, JAN01_0001, 1},
+        };
+    }
+
+    @Test(dataProvider="samples", groups={"tck"})
+    public void test_samples_get(TemporalField field, LocalDate date, long expected) {
+        assertEquals(date.getLong(field), expected);
+    }
+
+    @Test(dataProvider="samples", groups={"tck"})
+    public void test_samples_set(TemporalField field, LocalDate date, long value) {
+        assertEquals(field.doWith(LocalDate.MAX, value), date);
+        assertEquals(field.doWith(LocalDate.MIN, value), date);
+        assertEquals(field.doWith(JAN01_1970, value), date);
+        assertEquals(field.doWith(DEC31_1969, value), date);
+        assertEquals(field.doWith(NOV12_1945, value), date);
+    }
+
+    //-----------------------------------------------------------------------
+    // toString()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_toString() {
+        assertEquals(JulianFields.JULIAN_DAY.toString(), "JulianDay");
+        assertEquals(JulianFields.MODIFIED_JULIAN_DAY.toString(), "ModifiedJulianDay");
+        assertEquals(JulianFields.RATA_DIE.toString(), "RataDie");
+    }
+
+    @Test(groups = {"tck"},dataProvider="julian_fields")
+    public void test_JulianFieldsSingleton(TemporalField field) throws IOException, ClassNotFoundException {
+        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                ObjectOutputStream oos = new ObjectOutputStream(baos)) {
+            oos.writeObject(field);
+
+            ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(
+                    baos.toByteArray()));
+            TemporalField result = (TemporalField)ois.readObject();
+            assertSame(result, field, "Deserialized object same as serialized.");
+        }
+        // Exceptions will be handled as failures by TestNG
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/temporal/TCKMonthDay.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,756 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.temporal;
+
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.Month;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatters;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.JulianFields;
+import java.time.temporal.MonthDay;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalField;
+import java.time.temporal.YearMonth;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import tck.java.time.AbstractDateTimeTest;
+
+/**
+ * Test MonthDay.
+ */
+@Test
+public class TCKMonthDay extends AbstractDateTimeTest {
+
+    private MonthDay TEST_07_15;
+
+    @BeforeMethod(groups={"tck","implementation"})
+    public void setUp() {
+        TEST_07_15 = MonthDay.of(7, 15);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    protected List<TemporalAccessor> samples() {
+        TemporalAccessor[] array = {TEST_07_15, };
+        return Arrays.asList(array);
+    }
+
+    @Override
+    protected List<TemporalField> validFields() {
+        TemporalField[] array = {
+            DAY_OF_MONTH,
+            MONTH_OF_YEAR,
+        };
+        return Arrays.asList(array);
+    }
+
+    @Override
+    protected List<TemporalField> invalidFields() {
+        List<TemporalField> list = new ArrayList<>(Arrays.<TemporalField>asList(ChronoField.values()));
+        list.removeAll(validFields());
+        list.add(JulianFields.JULIAN_DAY);
+        list.add(JulianFields.MODIFIED_JULIAN_DAY);
+        list.add(JulianFields.RATA_DIE);
+        return list;
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_serialization() throws ClassNotFoundException, IOException {
+        assertSerializable(TEST_07_15);
+    }
+
+    @Test
+    public void test_serialization_format() throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try (DataOutputStream dos = new DataOutputStream(baos) ) {
+            dos.writeByte(6);
+            dos.writeByte(9);
+            dos.writeByte(16);
+        }
+        byte[] bytes = baos.toByteArray();
+        assertSerializedBySer(MonthDay.of(9, 16), bytes);
+    }
+
+    //-----------------------------------------------------------------------
+    void check(MonthDay test, int m, int d) {
+        assertEquals(test.getMonth().getValue(), m);
+        assertEquals(test.getDayOfMonth(), d);
+    }
+
+    //-----------------------------------------------------------------------
+    // now()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void now() {
+        MonthDay expected = MonthDay.now(Clock.systemDefaultZone());
+        MonthDay test = MonthDay.now();
+        for (int i = 0; i < 100; i++) {
+            if (expected.equals(test)) {
+                return;
+            }
+            expected = MonthDay.now(Clock.systemDefaultZone());
+            test = MonthDay.now();
+        }
+        assertEquals(test, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // now(ZoneId)
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void now_ZoneId_nullZoneId() {
+        MonthDay.now((ZoneId) null);
+    }
+
+    @Test(groups={"tck"})
+    public void now_ZoneId() {
+        ZoneId zone = ZoneId.of("UTC+01:02:03");
+        MonthDay expected = MonthDay.now(Clock.system(zone));
+        MonthDay test = MonthDay.now(zone);
+        for (int i = 0; i < 100; i++) {
+            if (expected.equals(test)) {
+                return;
+            }
+            expected = MonthDay.now(Clock.system(zone));
+            test = MonthDay.now(zone);
+        }
+        assertEquals(test, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // now(Clock)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void now_Clock() {
+        Instant instant = LocalDateTime.of(2010, 12, 31, 0, 0).toInstant(ZoneOffset.UTC);
+        Clock clock = Clock.fixed(instant, ZoneOffset.UTC);
+        MonthDay test = MonthDay.now(clock);
+        assertEquals(test.getMonth(), Month.DECEMBER);
+        assertEquals(test.getDayOfMonth(), 31);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void now_Clock_nullClock() {
+        MonthDay.now((Clock) null);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_intMonth() {
+        assertEquals(TEST_07_15, MonthDay.of(Month.JULY, 15));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_intMonth_dayTooLow() {
+        MonthDay.of(Month.JANUARY, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_intMonth_dayTooHigh() {
+        MonthDay.of(Month.JANUARY, 32);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_intMonth_nullMonth() {
+        MonthDay.of(null, 15);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_ints() {
+        check(TEST_07_15, 7, 15);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_ints_dayTooLow() {
+        MonthDay.of(1, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_ints_dayTooHigh() {
+        MonthDay.of(1, 32);
+    }
+
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_ints_monthTooLow() {
+        MonthDay.of(0, 1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_ints_monthTooHigh() {
+        MonthDay.of(13, 1);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_factory_CalendricalObject() {
+        assertEquals(MonthDay.from(LocalDate.of(2007, 7, 15)), TEST_07_15);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_CalendricalObject_invalid_noDerive() {
+        MonthDay.from(LocalTime.of(12, 30));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_factory_CalendricalObject_null() {
+        MonthDay.from((TemporalAccessor) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // parse()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="goodParseData")
+    Object[][] provider_goodParseData() {
+        return new Object[][] {
+                {"--01-01", MonthDay.of(1, 1)},
+                {"--01-31", MonthDay.of(1, 31)},
+                {"--02-01", MonthDay.of(2, 1)},
+                {"--02-29", MonthDay.of(2, 29)},
+                {"--03-01", MonthDay.of(3, 1)},
+                {"--03-31", MonthDay.of(3, 31)},
+                {"--04-01", MonthDay.of(4, 1)},
+                {"--04-30", MonthDay.of(4, 30)},
+                {"--05-01", MonthDay.of(5, 1)},
+                {"--05-31", MonthDay.of(5, 31)},
+                {"--06-01", MonthDay.of(6, 1)},
+                {"--06-30", MonthDay.of(6, 30)},
+                {"--07-01", MonthDay.of(7, 1)},
+                {"--07-31", MonthDay.of(7, 31)},
+                {"--08-01", MonthDay.of(8, 1)},
+                {"--08-31", MonthDay.of(8, 31)},
+                {"--09-01", MonthDay.of(9, 1)},
+                {"--09-30", MonthDay.of(9, 30)},
+                {"--10-01", MonthDay.of(10, 1)},
+                {"--10-31", MonthDay.of(10, 31)},
+                {"--11-01", MonthDay.of(11, 1)},
+                {"--11-30", MonthDay.of(11, 30)},
+                {"--12-01", MonthDay.of(12, 1)},
+                {"--12-31", MonthDay.of(12, 31)},
+        };
+    }
+
+    @Test(dataProvider="goodParseData", groups={"tck"})
+    public void factory_parse_success(String text, MonthDay expected) {
+        MonthDay monthDay = MonthDay.parse(text);
+        assertEquals(monthDay, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="badParseData")
+    Object[][] provider_badParseData() {
+        return new Object[][] {
+                {"", 0},
+                {"-00", 0},
+                {"--FEB-23", 2},
+                {"--01-0", 5},
+                {"--01-3A", 5},
+        };
+    }
+
+    @Test(dataProvider="badParseData", expectedExceptions=DateTimeParseException.class, groups={"tck"})
+    public void factory_parse_fail(String text, int pos) {
+        try {
+            MonthDay.parse(text);
+            fail(String.format("Parse should have failed for %s at position %d", text, pos));
+        }
+        catch (DateTimeParseException ex) {
+            assertEquals(ex.getParsedString(), text);
+            assertEquals(ex.getErrorIndex(), pos);
+            throw ex;
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"})
+    public void factory_parse_illegalValue_Day() {
+        MonthDay.parse("--06-32");
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"})
+    public void factory_parse_invalidValue_Day() {
+        MonthDay.parse("--06-31");
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"})
+    public void factory_parse_illegalValue_Month() {
+        MonthDay.parse("--13-25");
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_parse_nullText() {
+        MonthDay.parse(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // parse(DateTimeFormatter)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_parse_formatter() {
+        DateTimeFormatter f = DateTimeFormatters.pattern("M d");
+        MonthDay test = MonthDay.parse("12 3", f);
+        assertEquals(test, MonthDay.of(12, 3));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_parse_formatter_nullText() {
+        DateTimeFormatter f = DateTimeFormatters.pattern("M d");
+        MonthDay.parse((String) null, f);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_parse_formatter_nullFormatter() {
+        MonthDay.parse("ANY", null);
+    }
+
+    //-----------------------------------------------------------------------
+    // get(TemporalField)
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_get_TemporalField() {
+        assertEquals(TEST_07_15.get(ChronoField.DAY_OF_MONTH), 15);
+        assertEquals(TEST_07_15.get(ChronoField.MONTH_OF_YEAR), 7);
+    }
+
+    @Test
+    public void test_getLong_TemporalField() {
+        assertEquals(TEST_07_15.getLong(ChronoField.DAY_OF_MONTH), 15);
+        assertEquals(TEST_07_15.getLong(ChronoField.MONTH_OF_YEAR), 7);
+    }
+
+    //-----------------------------------------------------------------------
+    // get*()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sampleDates")
+    Object[][] provider_sampleDates() {
+        return new Object[][] {
+            {1, 1},
+            {1, 31},
+            {2, 1},
+            {2, 28},
+            {2, 29},
+            {7, 4},
+            {7, 5},
+        };
+    }
+
+    @Test(dataProvider="sampleDates", groups={"tck"})
+    public void test_get(int m, int d) {
+        MonthDay a = MonthDay.of(m, d);
+        assertEquals(a.getMonth(), Month.of(m));
+        assertEquals(a.getDayOfMonth(), d);
+    }
+
+    //-----------------------------------------------------------------------
+    // with(Month)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_with_Month() {
+        assertEquals(MonthDay.of(6, 30).with(Month.JANUARY), MonthDay.of(1, 30));
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_Month_adjustToValid() {
+        assertEquals(MonthDay.of(7, 31).with(Month.JUNE), MonthDay.of(6, 30));
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_Month_adjustToValidFeb() {
+        assertEquals(MonthDay.of(7, 31).with(Month.FEBRUARY), MonthDay.of(2, 29));
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_Month_noChangeEqual() {
+        MonthDay test = MonthDay.of(6, 30);
+        assertEquals(test.with(Month.JUNE), test);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_with_Month_null() {
+        MonthDay.of(6, 30).with((Month) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // withMonth()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withMonth() {
+        assertEquals(MonthDay.of(6, 30).withMonth(1), MonthDay.of(1, 30));
+    }
+
+    @Test(groups={"tck"})
+    public void test_withMonth_adjustToValid() {
+        assertEquals(MonthDay.of(7, 31).withMonth(6), MonthDay.of(6, 30));
+    }
+
+    @Test(groups={"tck"})
+    public void test_withMonth_adjustToValidFeb() {
+        assertEquals(MonthDay.of(7, 31).withMonth(2), MonthDay.of(2, 29));
+    }
+
+    @Test(groups={"tck"})
+    public void test_withMonth_int_noChangeEqual() {
+        MonthDay test = MonthDay.of(6, 30);
+        assertEquals(test.withMonth(6), test);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withMonth_tooLow() {
+        MonthDay.of(6, 30).withMonth(0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withMonth_tooHigh() {
+        MonthDay.of(6, 30).withMonth(13);
+    }
+
+    //-----------------------------------------------------------------------
+    // withDayOfMonth()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withDayOfMonth() {
+        assertEquals(MonthDay.of(6, 30).withDayOfMonth(1), MonthDay.of(6, 1));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withDayOfMonth_invalid() {
+        MonthDay.of(6, 30).withDayOfMonth(31);
+    }
+
+    @Test(groups={"tck"})
+    public void test_withDayOfMonth_adjustToValidFeb() {
+        assertEquals(MonthDay.of(2, 1).withDayOfMonth(29), MonthDay.of(2, 29));
+    }
+
+    @Test(groups={"tck"})
+    public void test_withDayOfMonth_noChangeEqual() {
+        MonthDay test = MonthDay.of(6, 30);
+        assertEquals(test.withDayOfMonth(30), test);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withDayOfMonth_tooLow() {
+        MonthDay.of(6, 30).withDayOfMonth(0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withDayOfMonth_tooHigh() {
+        MonthDay.of(6, 30).withDayOfMonth(32);
+    }
+
+    //-----------------------------------------------------------------------
+    // adjustInto()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_adjustDate() {
+        MonthDay test = MonthDay.of(6, 30);
+        LocalDate date = LocalDate.of(2007, 1, 1);
+        assertEquals(test.adjustInto(date), LocalDate.of(2007, 6, 30));
+    }
+
+    @Test(groups={"tck"})
+    public void test_adjustDate_resolve() {
+        MonthDay test = MonthDay.of(2, 29);
+        LocalDate date = LocalDate.of(2007, 6, 30);
+        assertEquals(test.adjustInto(date), LocalDate.of(2007, 2, 28));
+    }
+
+    @Test(groups={"tck"})
+    public void test_adjustDate_equal() {
+        MonthDay test = MonthDay.of(6, 30);
+        LocalDate date = LocalDate.of(2007, 6, 30);
+        assertEquals(test.adjustInto(date), date);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_adjustDate_null() {
+        TEST_07_15.adjustInto((LocalDate) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // isValidYear(int)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_isValidYear_june() {
+        MonthDay test = MonthDay.of(6, 30);
+        assertEquals(test.isValidYear(2007), true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_isValidYear_febNonLeap() {
+        MonthDay test = MonthDay.of(2, 29);
+        assertEquals(test.isValidYear(2007), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_isValidYear_febLeap() {
+        MonthDay test = MonthDay.of(2, 29);
+        assertEquals(test.isValidYear(2008), true);
+    }
+
+    //-----------------------------------------------------------------------
+    // atYear(int)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_atYear_int() {
+        MonthDay test = MonthDay.of(6, 30);
+        assertEquals(test.atYear(2008), LocalDate.of(2008, 6, 30));
+    }
+
+    @Test(groups={"tck"})
+    public void test_atYear_int_leapYearAdjust() {
+        MonthDay test = MonthDay.of(2, 29);
+        assertEquals(test.atYear(2005), LocalDate.of(2005, 2, 28));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_atYear_int_invalidYear() {
+        MonthDay test = MonthDay.of(6, 30);
+        test.atYear(Integer.MIN_VALUE);
+    }
+
+    //-----------------------------------------------------------------------
+    // compareTo()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_comparisons() {
+        doTest_comparisons_MonthDay(
+            MonthDay.of(1, 1),
+            MonthDay.of(1, 31),
+            MonthDay.of(2, 1),
+            MonthDay.of(2, 29),
+            MonthDay.of(3, 1),
+            MonthDay.of(12, 31)
+        );
+    }
+
+    void doTest_comparisons_MonthDay(MonthDay... localDates) {
+        for (int i = 0; i < localDates.length; i++) {
+            MonthDay a = localDates[i];
+            for (int j = 0; j < localDates.length; j++) {
+                MonthDay b = localDates[j];
+                if (i < j) {
+                    assertTrue(a.compareTo(b) < 0, a + " <=> " + b);
+                    assertEquals(a.isBefore(b), true, a + " <=> " + b);
+                    assertEquals(a.isAfter(b), false, a + " <=> " + b);
+                    assertEquals(a.equals(b), false, a + " <=> " + b);
+                } else if (i > j) {
+                    assertTrue(a.compareTo(b) > 0, a + " <=> " + b);
+                    assertEquals(a.isBefore(b), false, a + " <=> " + b);
+                    assertEquals(a.isAfter(b), true, a + " <=> " + b);
+                    assertEquals(a.equals(b), false, a + " <=> " + b);
+                } else {
+                    assertEquals(a.compareTo(b), 0, a + " <=> " + b);
+                    assertEquals(a.isBefore(b), false, a + " <=> " + b);
+                    assertEquals(a.isAfter(b), false, a + " <=> " + b);
+                    assertEquals(a.equals(b), true, a + " <=> " + b);
+                }
+            }
+        }
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_compareTo_ObjectNull() {
+        TEST_07_15.compareTo(null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_isBefore_ObjectNull() {
+        TEST_07_15.isBefore(null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_isAfter_ObjectNull() {
+        TEST_07_15.isAfter(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // equals()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_equals() {
+        MonthDay a = MonthDay.of(1, 1);
+        MonthDay b = MonthDay.of(1, 1);
+        MonthDay c = MonthDay.of(2, 1);
+        MonthDay d = MonthDay.of(1, 2);
+
+        assertEquals(a.equals(a), true);
+        assertEquals(a.equals(b), true);
+        assertEquals(a.equals(c), false);
+        assertEquals(a.equals(d), false);
+
+        assertEquals(b.equals(a), true);
+        assertEquals(b.equals(b), true);
+        assertEquals(b.equals(c), false);
+        assertEquals(b.equals(d), false);
+
+        assertEquals(c.equals(a), false);
+        assertEquals(c.equals(b), false);
+        assertEquals(c.equals(c), true);
+        assertEquals(c.equals(d), false);
+
+        assertEquals(d.equals(a), false);
+        assertEquals(d.equals(b), false);
+        assertEquals(d.equals(c), false);
+        assertEquals(d.equals(d), true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_itself_true() {
+        assertEquals(TEST_07_15.equals(TEST_07_15), true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_string_false() {
+        assertEquals(TEST_07_15.equals("2007-07-15"), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_null_false() {
+        assertEquals(TEST_07_15.equals(null), false);
+    }
+
+    //-----------------------------------------------------------------------
+    // hashCode()
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="sampleDates", groups={"tck"})
+    public void test_hashCode(int m, int d) {
+        MonthDay a = MonthDay.of(m, d);
+        assertEquals(a.hashCode(), a.hashCode());
+        MonthDay b = MonthDay.of(m, d);
+        assertEquals(a.hashCode(), b.hashCode());
+    }
+
+    @Test(groups={"tck"})
+    public void test_hashCode_unique() {
+        int leapYear = 2008;
+        Set<Integer> uniques = new HashSet<Integer>(366);
+        for (int i = 1; i <= 12; i++) {
+            for (int j = 1; j <= 31; j++) {
+                if (YearMonth.of(leapYear, i).isValidDay(j)) {
+                    assertTrue(uniques.add(MonthDay.of(i, j).hashCode()));
+                }
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // toString()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sampleToString")
+    Object[][] provider_sampleToString() {
+        return new Object[][] {
+            {7, 5, "--07-05"},
+            {12, 31, "--12-31"},
+            {1, 2, "--01-02"},
+        };
+    }
+
+    @Test(dataProvider="sampleToString", groups={"tck"})
+    public void test_toString(int m, int d, String expected) {
+        MonthDay test = MonthDay.of(m, d);
+        String str = test.toString();
+        assertEquals(str, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // toString(DateTimeFormatter)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_toString_formatter() {
+        DateTimeFormatter f = DateTimeFormatters.pattern("M d");
+        String t = MonthDay.of(12, 3).toString(f);
+        assertEquals(t, "12 3");
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_toString_formatter_null() {
+        MonthDay.of(12, 3).toString(null);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/temporal/TCKOffsetDate.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,1949 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+9 * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.temporal;
+
+import static java.time.Month.DECEMBER;
+import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH;
+import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR;
+import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH;
+import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR;
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.DAY_OF_WEEK;
+import static java.time.temporal.ChronoField.DAY_OF_YEAR;
+import static java.time.temporal.ChronoField.EPOCH_DAY;
+import static java.time.temporal.ChronoField.EPOCH_MONTH;
+import static java.time.temporal.ChronoField.ERA;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.OFFSET_SECONDS;
+import static java.time.temporal.ChronoField.YEAR;
+import static java.time.temporal.ChronoField.YEAR_OF_ERA;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.Month;
+import java.time.Period;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatters;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.ISOChrono;
+import java.time.temporal.JulianFields;
+import java.time.temporal.OffsetDate;
+import java.time.temporal.OffsetDateTime;
+import java.time.temporal.Queries;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdder;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalSubtractor;
+import java.time.temporal.Year;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import tck.java.time.AbstractDateTimeTest;
+import test.java.time.MockSimplePeriod;
+
+/**
+ * Test OffsetDate.
+ */
+@Test
+public class TCKOffsetDate extends AbstractDateTimeTest {
+    private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1);
+    private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2);
+
+    private OffsetDate TEST_2007_07_15_PONE;
+
+    @BeforeMethod(groups={"tck","implementation"})
+    public void setUp() {
+        TEST_2007_07_15_PONE = OffsetDate.of(LocalDate.of(2007, 7, 15), OFFSET_PONE);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    protected List<TemporalAccessor> samples() {
+        TemporalAccessor[] array = {TEST_2007_07_15_PONE, OffsetDate.MIN, OffsetDate.MAX};
+        return Arrays.asList(array);
+    }
+
+    @Override
+    protected List<TemporalField> validFields() {
+        TemporalField[] array = {
+            DAY_OF_WEEK,
+            ALIGNED_DAY_OF_WEEK_IN_MONTH,
+            ALIGNED_DAY_OF_WEEK_IN_YEAR,
+            DAY_OF_MONTH,
+            DAY_OF_YEAR,
+            EPOCH_DAY,
+            ALIGNED_WEEK_OF_MONTH,
+            ALIGNED_WEEK_OF_YEAR,
+            MONTH_OF_YEAR,
+            EPOCH_MONTH,
+            YEAR_OF_ERA,
+            YEAR,
+            ERA,
+            OFFSET_SECONDS,
+            JulianFields.JULIAN_DAY,
+            JulianFields.MODIFIED_JULIAN_DAY,
+            JulianFields.RATA_DIE,
+        };
+        return Arrays.asList(array);
+    }
+
+    @Override
+    protected List<TemporalField> invalidFields() {
+        List<TemporalField> list = new ArrayList<>(Arrays.<TemporalField>asList(ChronoField.values()));
+        list.removeAll(validFields());
+        return list;
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_serialization() throws ClassNotFoundException, IOException {
+        assertSerializable(TEST_2007_07_15_PONE);
+        assertSerializable(OffsetDate.MIN);
+        assertSerializable(OffsetDate.MAX);
+    }
+
+    @Test
+    public void test_serialization_format() throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try (DataOutputStream dos = new DataOutputStream(baos) ) {
+            dos.writeByte(1);
+        }
+        byte[] bytes = baos.toByteArray();
+        ByteArrayOutputStream baosDate = new ByteArrayOutputStream();
+        try (DataOutputStream dos = new DataOutputStream(baosDate) ) {
+            dos.writeByte(3);
+            dos.writeInt(2012);
+            dos.writeByte(9);
+            dos.writeByte(16);
+        }
+        byte[] bytesDate = baosDate.toByteArray();
+        ByteArrayOutputStream baosOffset = new ByteArrayOutputStream();
+        try (DataOutputStream dos = new DataOutputStream(baosOffset) ) {
+            dos.writeByte(8);
+            dos.writeByte(4);  // quarter hours stored: 3600 / 900
+        }
+        byte[] bytesOffset = baosOffset.toByteArray();
+        assertSerializedBySer(OffsetDate.of(LocalDate.of(2012, 9, 16), ZoneOffset.ofHours(1)), bytes,
+                bytesDate, bytesOffset);
+    }
+
+    //-----------------------------------------------------------------------
+    // constants
+    //-----------------------------------------------------------------------
+    @Test
+    public void constant_MIN() {
+        check(OffsetDate.MIN, Year.MIN_VALUE, 1, 1, ZoneOffset.MAX);
+    }
+
+    @Test
+    public void constant_MAX() {
+        check(OffsetDate.MAX, Year.MAX_VALUE, 12, 31, ZoneOffset.MIN);
+    }
+
+    //-----------------------------------------------------------------------
+    // now()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void now() {
+        OffsetDate expected = OffsetDate.now(Clock.systemDefaultZone());
+        OffsetDate test = OffsetDate.now();
+        for (int i = 0; i < 100; i++) {
+            if (expected.equals(test)) {
+                return;
+            }
+            expected = OffsetDate.now(Clock.systemDefaultZone());
+            test = OffsetDate.now();
+        }
+        assertEquals(test, expected);
+    }
+
+    @Test(groups={"tck"})
+    public void now_Clock_allSecsInDay_utc() {
+        for (int i = 0; i < (2 * 24 * 60 * 60); i++) {
+            Instant instant = Instant.ofEpochSecond(i);
+            Clock clock = Clock.fixed(instant, ZoneOffset.UTC);
+            OffsetDate test = OffsetDate.now(clock);
+            check(test, 1970, 1, (i < 24 * 60 * 60 ? 1 : 2), ZoneOffset.UTC);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void now_Clock_allSecsInDay_beforeEpoch() {
+        for (int i =-1; i >= -(2 * 24 * 60 * 60); i--) {
+            Instant instant = Instant.ofEpochSecond(i);
+            Clock clock = Clock.fixed(instant, ZoneOffset.UTC);
+            OffsetDate test = OffsetDate.now(clock);
+            check(test, 1969, 12, (i >= -24 * 60 * 60 ? 31 : 30), ZoneOffset.UTC);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void now_Clock_offsets() {
+        Instant base = LocalDateTime.of(1970, 1, 1, 12, 0).toInstant(ZoneOffset.UTC);
+        for (int i = -9; i < 15; i++) {
+            ZoneOffset offset = ZoneOffset.ofHours(i);
+            Clock clock = Clock.fixed(base, offset);
+            OffsetDate test = OffsetDate.now(clock);
+            check(test, 1970, 1, (i >= 12 ? 2 : 1), offset);
+        }
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void now_Clock_nullZoneId() {
+        OffsetDate.now((ZoneId) null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void now_Clock_nullClock() {
+        OffsetDate.now((Clock) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // factories
+    //-----------------------------------------------------------------------
+    private void check(OffsetDate test, int y, int mo, int d, ZoneOffset offset) {
+        assertEquals(test.getDate(), LocalDate.of(y, mo, d));
+        assertEquals(test.getOffset(), offset);
+
+        assertEquals(test.getYear(), y);
+        assertEquals(test.getMonth().getValue(), mo);
+        assertEquals(test.getDayOfMonth(), d);
+
+        assertEquals(test, test);
+        assertEquals(test.hashCode(), test.hashCode());
+        assertEquals(OffsetDate.of(LocalDate.of(y, mo, d), offset), test);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_of_intMonthInt() {
+        OffsetDate test = OffsetDate.of(LocalDate.of(2007, Month.JULY, 15), OFFSET_PONE);
+        check(test, 2007, 7, 15, OFFSET_PONE);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_of_ints() {
+        OffsetDate test = OffsetDate.of(LocalDate.of(2007, 7, 15), OFFSET_PONE);
+        check(test, 2007, 7, 15, OFFSET_PONE);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_of_intsMonthOffset() {
+        assertEquals(TEST_2007_07_15_PONE, OffsetDate.of(LocalDate.of(2007, Month.JULY, 15), OFFSET_PONE));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_intsMonthOffset_dayTooLow() {
+        OffsetDate.of(LocalDate.of(2007, Month.JANUARY, 0), OFFSET_PONE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_intsMonthOffset_dayTooHigh() {
+        OffsetDate.of(LocalDate.of(2007, Month.JANUARY, 32), OFFSET_PONE);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_of_intsMonthOffset_nullMonth() {
+        OffsetDate.of(LocalDate.of(2007, null, 30), OFFSET_PONE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_intsMonthOffset_yearTooLow() {
+        OffsetDate.of(LocalDate.of(Integer.MIN_VALUE, Month.JANUARY, 1), OFFSET_PONE);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_of_intsMonthOffset_nullOffset() {
+        OffsetDate.of(LocalDate.of(2007, Month.JANUARY, 30), null);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_of_intsOffset() {
+        OffsetDate test = OffsetDate.of(LocalDate.of(2007, 7, 15), OFFSET_PONE);
+        check(test, 2007, 7, 15, OFFSET_PONE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_ints_dayTooLow() {
+        OffsetDate.of(LocalDate.of(2007, 1, 0), OFFSET_PONE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_ints_dayTooHigh() {
+        OffsetDate.of(LocalDate.of(2007, 1, 32), OFFSET_PONE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_ints_monthTooLow() {
+        OffsetDate.of(LocalDate.of(2007, 0, 1), OFFSET_PONE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_ints_monthTooHigh() {
+        OffsetDate.of(LocalDate.of(2007, 13, 1), OFFSET_PONE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_of_ints_yearTooLow() {
+        OffsetDate.of(LocalDate.of(Integer.MIN_VALUE, 1, 1), OFFSET_PONE);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_of_ints_nullOffset() {
+        OffsetDate.of(LocalDate.of(2007, 1, 1), (ZoneOffset) null);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_of_LocalDateZoneOffset() {
+        LocalDate localDate = LocalDate.of(2008, 6, 30);
+        OffsetDate test = OffsetDate.of(localDate, OFFSET_PONE);
+        check(test, 2008, 6, 30, OFFSET_PONE);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_of_LocalDateZoneOffset_nullDate() {
+        OffsetDate.of((LocalDate) null, OFFSET_PONE);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_of_LocalDateZoneOffset_nullOffset() {
+        LocalDate localDate = LocalDate.of(2008, 6, 30);
+        OffsetDate.of(localDate, (ZoneOffset) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // from(TemporalAccessor)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_from_TemporalAccessor_OD() {
+        assertEquals(OffsetDate.from(TEST_2007_07_15_PONE), TEST_2007_07_15_PONE);
+    }
+
+    @Test(groups={"tck"})
+    public void test_from_TemporalAccessor_ZDT() {
+        ZonedDateTime base = LocalDateTime.of(2007, 7, 15, 17, 30).atZone(OFFSET_PONE);
+        assertEquals(OffsetDate.from(base), TEST_2007_07_15_PONE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_from_TemporalAccessor_invalid_noDerive() {
+        OffsetDate.from(LocalTime.of(12, 30));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_from_TemporalAccessor_null() {
+        OffsetDate.from((TemporalAccessor) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // parse()
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="sampleToString", groups={"tck"})
+    public void factory_parse_validText(int y, int m, int d, String offsetId, String parsable) {
+        OffsetDate t = OffsetDate.parse(parsable);
+        assertNotNull(t, parsable);
+        assertEquals(t.getYear(), y, parsable);
+        assertEquals(t.getMonth().getValue(), m, parsable);
+        assertEquals(t.getDayOfMonth(), d, parsable);
+        assertEquals(t.getOffset(), ZoneOffset.of(offsetId));
+    }
+
+    @DataProvider(name="sampleBadParse")
+    Object[][] provider_sampleBadParse() {
+        return new Object[][]{
+                {"2008/07/05"},
+                {"10000-01-01"},
+                {"2008-1-1"},
+                {"2008--01"},
+                {"ABCD-02-01"},
+                {"2008-AB-01"},
+                {"2008-02-AB"},
+                {"-0000-02-01"},
+                {"2008-02-01Y"},
+                {"2008-02-01+19:00"},
+                {"2008-02-01+01/00"},
+                {"2008-02-01+1900"},
+                {"2008-02-01+01:60"},
+                {"2008-02-01+01:30:123"},
+                {"2008-02-01"},
+                {"2008-02-01+01:00[Europe/Paris]"},
+        };
+    }
+
+    @Test(dataProvider="sampleBadParse", expectedExceptions=DateTimeParseException.class, groups={"tck"})
+    public void factory_parse_invalidText(String unparsable) {
+        OffsetDate.parse(unparsable);
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"})
+    public void factory_parse_illegalValue() {
+        OffsetDate.parse("2008-06-32+01:00");
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"})
+    public void factory_parse_invalidValue() {
+        OffsetDate.parse("2008-06-31+01:00");
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_parse_nullText() {
+        OffsetDate.parse((String) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // parse(DateTimeFormatter)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_parse_formatter() {
+        DateTimeFormatter f = DateTimeFormatters.pattern("y M d XXX");
+        OffsetDate test = OffsetDate.parse("2010 12 3 +01:00", f);
+        assertEquals(test, OffsetDate.of(LocalDate.of(2010, 12, 3), ZoneOffset.ofHours(1)));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_parse_formatter_nullText() {
+        DateTimeFormatter f = DateTimeFormatters.pattern("y M d");
+        OffsetDate.parse((String) null, f);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_parse_formatter_nullFormatter() {
+        OffsetDate.parse("ANY", null);
+    }
+
+    //-----------------------------------------------------------------------
+    // constructor
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void constructor_nullDate() throws Throwable  {
+        Constructor<OffsetDate> con = OffsetDate.class.getDeclaredConstructor(LocalDate.class, ZoneOffset.class);
+        con.setAccessible(true);
+        try {
+            con.newInstance(null, OFFSET_PONE);
+        } catch (InvocationTargetException ex) {
+            throw ex.getCause();
+        }
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void constructor_nullOffset() throws Throwable  {
+        Constructor<OffsetDate> con = OffsetDate.class.getDeclaredConstructor(LocalDate.class, ZoneOffset.class);
+        con.setAccessible(true);
+        try {
+            con.newInstance(LocalDate.of(2008, 6, 30), null);
+        } catch (InvocationTargetException ex) {
+            throw ex.getCause();
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // basics
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sampleDates")
+    Object[][] provider_sampleDates() {
+        return new Object[][] {
+            {2008, 7, 5, OFFSET_PTWO},
+            {2007, 7, 5, OFFSET_PONE},
+            {2006, 7, 5, OFFSET_PTWO},
+            {2005, 7, 5, OFFSET_PONE},
+            {2004, 1, 1, OFFSET_PTWO},
+            {-1, 1, 2, OFFSET_PONE},
+            {999999, 11, 20, ZoneOffset.ofHoursMinutesSeconds(6, 9, 12)},
+        };
+    }
+
+    @Test(dataProvider="sampleDates", groups={"tck"})
+    public void test_get_OffsetDate(int y, int m, int d, ZoneOffset offset) {
+        LocalDate localDate = LocalDate.of(y, m, d);
+        OffsetDate a = OffsetDate.of(localDate, offset);
+
+        assertEquals(a.getDate(), localDate);
+        assertEquals(a.getOffset(), offset);
+        assertEquals(a.toString(), localDate.toString() + offset.toString());
+        assertEquals(a.getYear(), localDate.getYear());
+        assertEquals(a.getMonth(), localDate.getMonth());
+        assertEquals(a.getDayOfMonth(), localDate.getDayOfMonth());
+        assertEquals(a.getDayOfYear(), localDate.getDayOfYear());
+        assertEquals(a.getDayOfWeek(), localDate.getDayOfWeek());
+    }
+
+    //-----------------------------------------------------------------------
+    // get(TemporalField)
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_get_TemporalField() {
+        OffsetDate test = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE);
+        assertEquals(test.get(ChronoField.YEAR), 2008);
+        assertEquals(test.get(ChronoField.MONTH_OF_YEAR), 6);
+        assertEquals(test.get(ChronoField.DAY_OF_MONTH), 30);
+        assertEquals(test.get(ChronoField.DAY_OF_WEEK), 1);
+        assertEquals(test.get(ChronoField.DAY_OF_YEAR), 182);
+
+        assertEquals(test.get(ChronoField.OFFSET_SECONDS), 3600);
+    }
+
+    @Test
+    public void test_getLong_TemporalField() {
+        OffsetDate test = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE);
+        assertEquals(test.getLong(ChronoField.YEAR), 2008);
+        assertEquals(test.getLong(ChronoField.MONTH_OF_YEAR), 6);
+        assertEquals(test.getLong(ChronoField.DAY_OF_MONTH), 30);
+        assertEquals(test.getLong(ChronoField.DAY_OF_WEEK), 1);
+        assertEquals(test.getLong(ChronoField.DAY_OF_YEAR), 182);
+
+        assertEquals(test.getLong(ChronoField.OFFSET_SECONDS), 3600);
+    }
+
+    //-----------------------------------------------------------------------
+    // query(TemporalQuery)
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_query_chrono() {
+        assertEquals(TEST_2007_07_15_PONE.query(Queries.chrono()), ISOChrono.INSTANCE);
+        assertEquals(Queries.chrono().queryFrom(TEST_2007_07_15_PONE), ISOChrono.INSTANCE);
+    }
+
+    @Test
+    public void test_query_zoneId() {
+        assertEquals(TEST_2007_07_15_PONE.query(Queries.zoneId()), null);
+        assertEquals(Queries.zoneId().queryFrom(TEST_2007_07_15_PONE), null);
+    }
+
+    @Test
+    public void test_query_precision() {
+        assertEquals(TEST_2007_07_15_PONE.query(Queries.precision()), ChronoUnit.DAYS);
+        assertEquals(Queries.precision().queryFrom(TEST_2007_07_15_PONE), ChronoUnit.DAYS);
+    }
+
+    @Test
+    public void test_query_offset() {
+        assertEquals(TEST_2007_07_15_PONE.query(Queries.offset()), OFFSET_PONE);
+        assertEquals(Queries.offset().queryFrom(TEST_2007_07_15_PONE), OFFSET_PONE);
+    }
+
+    @Test
+    public void test_query_zone() {
+        assertEquals(TEST_2007_07_15_PONE.query(Queries.zone()), OFFSET_PONE);
+        assertEquals(Queries.zone().queryFrom(TEST_2007_07_15_PONE), OFFSET_PONE);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_query_null() {
+        TEST_2007_07_15_PONE.query(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // withOffset()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withOffset() {
+        OffsetDate base = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE);
+        OffsetDate test = base.withOffset(OFFSET_PTWO);
+        assertEquals(test.getDate(), base.getDate());
+        assertEquals(test.getOffset(), OFFSET_PTWO);
+    }
+
+    @Test(groups={"tck"})
+    public void test_withOffset_noChange() {
+        OffsetDate base = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE);
+        OffsetDate test = base.withOffset(OFFSET_PONE);
+        assertEquals(test, base);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_withOffset_null() {
+        TEST_2007_07_15_PONE.withOffset(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // with(WithAdjuster)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_with_adjustment() {
+        final OffsetDate sample = OffsetDate.of(LocalDate.of(2012, 3, 4), OFFSET_PONE);
+        TemporalAdjuster adjuster = new TemporalAdjuster() {
+            @Override
+            public Temporal adjustInto(Temporal dateTime) {
+                return sample;
+            }
+        };
+        assertEquals(TEST_2007_07_15_PONE.with(adjuster), sample);
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_adjustment_LocalDate() {
+        OffsetDate test = TEST_2007_07_15_PONE.with(LocalDate.of(2008, 6, 30));
+        assertEquals(test, OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_adjustment_OffsetDate() {
+        OffsetDate test = TEST_2007_07_15_PONE.with(OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PTWO));
+        assertEquals(test, OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PTWO));
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_adjustment_ZoneOffset() {
+        OffsetDate test = TEST_2007_07_15_PONE.with(OFFSET_PTWO);
+        assertEquals(test, OffsetDate.of(LocalDate.of(2007, 7, 15), OFFSET_PTWO));
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_adjustment_Month() {
+        OffsetDate test = TEST_2007_07_15_PONE.with(DECEMBER);
+        assertEquals(test, OffsetDate.of(LocalDate.of(2007, 12, 15), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_adjustment_offsetUnchanged() {
+        OffsetDate base = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE);
+        OffsetDate test = base.with(Year.of(2008));
+        assertEquals(test, base);
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_adjustment_noChange() {
+        LocalDate date = LocalDate.of(2008, 6, 30);
+        OffsetDate base = OffsetDate.of(date, OFFSET_PONE);
+        OffsetDate test = base.with(date);
+        assertEquals(test, base);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_with_adjustment_null() {
+        TEST_2007_07_15_PONE.with((TemporalAdjuster) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // with(TemporalField, long)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_with_TemporalField() {
+        OffsetDate test = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE);
+        assertEquals(test.with(ChronoField.YEAR, 2009), OffsetDate.of(LocalDate.of(2009, 6, 30), OFFSET_PONE));
+        assertEquals(test.with(ChronoField.MONTH_OF_YEAR, 7), OffsetDate.of(LocalDate.of(2008, 7, 30), OFFSET_PONE));
+        assertEquals(test.with(ChronoField.DAY_OF_MONTH, 1), OffsetDate.of(LocalDate.of(2008, 6, 1), OFFSET_PONE));
+        assertEquals(test.with(ChronoField.DAY_OF_WEEK, 2), OffsetDate.of(LocalDate.of(2008, 7, 1), OFFSET_PONE));
+        assertEquals(test.with(ChronoField.DAY_OF_YEAR, 183), OffsetDate.of(LocalDate.of(2008, 7, 1), OFFSET_PONE));
+
+        assertEquals(test.with(ChronoField.OFFSET_SECONDS, 7205), OffsetDate.of(LocalDate.of(2008, 6, 30), ZoneOffset.ofHoursMinutesSeconds(2, 0, 5)));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"} )
+    public void test_with_TemporalField_null() {
+        TEST_2007_07_15_PONE.with((TemporalField) null, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"} )
+    public void test_with_TemporalField_invalidField() {
+        TEST_2007_07_15_PONE.with(ChronoField.AMPM_OF_DAY, 0);
+    }
+
+    //-----------------------------------------------------------------------
+    // withYear()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withYear_int_normal() {
+        OffsetDate t = TEST_2007_07_15_PONE.withYear(2008);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2008, 7, 15), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_withYear_int_noChange() {
+        OffsetDate t = TEST_2007_07_15_PONE.withYear(2007);
+        assertEquals(t, TEST_2007_07_15_PONE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withYear_int_invalid() {
+        TEST_2007_07_15_PONE.withYear(Year.MIN_VALUE - 1);
+    }
+
+    @Test(groups={"tck"})
+    public void test_withYear_int_adjustDay() {
+        OffsetDate t = OffsetDate.of(LocalDate.of(2008, 2, 29), OFFSET_PONE).withYear(2007);
+        OffsetDate expected = OffsetDate.of(LocalDate.of(2007, 2, 28), OFFSET_PONE);
+        assertEquals(t, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // withMonth()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withMonth_int_normal() {
+        OffsetDate t = TEST_2007_07_15_PONE.withMonth(1);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2007, 1, 15), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_withMonth_int_noChange() {
+        OffsetDate t = TEST_2007_07_15_PONE.withMonth(7);
+        assertEquals(t, TEST_2007_07_15_PONE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withMonth_int_invalid() {
+        TEST_2007_07_15_PONE.withMonth(13);
+    }
+
+    @Test(groups={"tck"})
+    public void test_withMonth_int_adjustDay() {
+        OffsetDate t = OffsetDate.of(LocalDate.of(2007, 12, 31), OFFSET_PONE).withMonth(11);
+        OffsetDate expected = OffsetDate.of(LocalDate.of(2007, 11, 30), OFFSET_PONE);
+        assertEquals(t, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // withDayOfMonth()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withDayOfMonth_normal() {
+        OffsetDate t = TEST_2007_07_15_PONE.withDayOfMonth(1);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2007, 7, 1), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_withDayOfMonth_noChange() {
+        OffsetDate t = TEST_2007_07_15_PONE.withDayOfMonth(15);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2007, 7, 15), OFFSET_PONE));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withDayOfMonth_invalidForMonth() {
+        OffsetDate.of(LocalDate.of(2007, 11, 30), OFFSET_PONE).withDayOfMonth(31);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withDayOfMonth_invalidAlways() {
+        OffsetDate.of(LocalDate.of(2007, 11, 30), OFFSET_PONE).withDayOfMonth(32);
+    }
+
+    //-----------------------------------------------------------------------
+    // withDayOfYear(int)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withDayOfYear_normal() {
+        OffsetDate t = TEST_2007_07_15_PONE.withDayOfYear(33);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2007, 2, 2), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_withDayOfYear_noChange() {
+        OffsetDate t = TEST_2007_07_15_PONE.withDayOfYear(31 + 28 + 31 + 30 + 31 + 30 + 15);
+        assertEquals(t, TEST_2007_07_15_PONE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withDayOfYear_illegal() {
+        TEST_2007_07_15_PONE.withDayOfYear(367);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withDayOfYear_invalid() {
+        TEST_2007_07_15_PONE.withDayOfYear(366);
+    }
+
+    //-----------------------------------------------------------------------
+    // plus(PlusAdjuster)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plus_PlusAdjuster() {
+        MockSimplePeriod period = MockSimplePeriod.of(7, ChronoUnit.MONTHS);
+        OffsetDate t = TEST_2007_07_15_PONE.plus(period);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2008, 2, 15), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plus_PlusAdjuster_noChange() {
+        MockSimplePeriod period = MockSimplePeriod.of(0, ChronoUnit.MONTHS);
+        OffsetDate t = TEST_2007_07_15_PONE.plus(period);
+        assertEquals(t, TEST_2007_07_15_PONE);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plus_PlusAdjuster_zero() {
+        OffsetDate t = TEST_2007_07_15_PONE.plus(Period.ZERO);
+        assertEquals(t, TEST_2007_07_15_PONE);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_plus_PlusAdjuster_null() {
+        TEST_2007_07_15_PONE.plus((TemporalAdder) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusYears()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusYears_long_normal() {
+        OffsetDate t = TEST_2007_07_15_PONE.plusYears(1);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2008, 7, 15), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusYears_long_negative() {
+        OffsetDate t = TEST_2007_07_15_PONE.plusYears(-1);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2006, 7, 15), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusYears_long_noChange() {
+        OffsetDate t = TEST_2007_07_15_PONE.plusYears(0);
+        assertEquals(t, TEST_2007_07_15_PONE);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusYears_long_adjustDay() {
+        OffsetDate t = OffsetDate.of(LocalDate.of(2008, 2, 29), OFFSET_PONE).plusYears(1);
+        OffsetDate expected = OffsetDate.of(LocalDate.of(2009, 2, 28), OFFSET_PONE);
+        assertEquals(t, expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusYears_long_big() {
+        long years = 20L + Year.MAX_VALUE;
+        OffsetDate test = OffsetDate.of(LocalDate.of(-40, 6, 1), OFFSET_PONE).plusYears(years);
+        assertEquals(test, OffsetDate.of(LocalDate.of((int) (-40L + years), 6, 1), OFFSET_PONE));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusYears_long_invalidTooLarge() {
+        OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 1, 1), OFFSET_PONE).plusYears(1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusYears_long_invalidTooLargeMaxAddMax() {
+        OffsetDate test = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 1), OFFSET_PONE);
+        test.plusYears(Long.MAX_VALUE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusYears_long_invalidTooLargeMaxAddMin() {
+        OffsetDate test = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 1), OFFSET_PONE);
+        test.plusYears(Long.MIN_VALUE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusYears_long_invalidTooSmall() {
+        OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 1), OFFSET_PONE).plusYears(-1);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusMonths()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusMonths_long_normal() {
+        OffsetDate t = TEST_2007_07_15_PONE.plusMonths(1);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2007, 8, 15), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMonths_long_overYears() {
+        OffsetDate t = TEST_2007_07_15_PONE.plusMonths(25);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2009, 8, 15), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMonths_long_negative() {
+        OffsetDate t = TEST_2007_07_15_PONE.plusMonths(-1);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2007, 6, 15), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMonths_long_negativeAcrossYear() {
+        OffsetDate t = TEST_2007_07_15_PONE.plusMonths(-7);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2006, 12, 15), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMonths_long_negativeOverYears() {
+        OffsetDate t = TEST_2007_07_15_PONE.plusMonths(-31);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2004, 12, 15), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMonths_long_noChange() {
+        OffsetDate t = TEST_2007_07_15_PONE.plusMonths(0);
+        assertEquals(t, TEST_2007_07_15_PONE);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMonths_long_adjustDayFromLeapYear() {
+        OffsetDate t = OffsetDate.of(LocalDate.of(2008, 2, 29), OFFSET_PONE).plusMonths(12);
+        OffsetDate expected = OffsetDate.of(LocalDate.of(2009, 2, 28), OFFSET_PONE);
+        assertEquals(t, expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMonths_long_adjustDayFromMonthLength() {
+        OffsetDate t = OffsetDate.of(LocalDate.of(2007, 3, 31), OFFSET_PONE).plusMonths(1);
+        OffsetDate expected = OffsetDate.of(LocalDate.of(2007, 4, 30), OFFSET_PONE);
+        assertEquals(t, expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMonths_long_big() {
+        long months = 20L + Integer.MAX_VALUE;
+        OffsetDate test = OffsetDate.of(LocalDate.of(-40, 6, 1), OFFSET_PONE).plusMonths(months);
+        assertEquals(test, OffsetDate.of(LocalDate.of((int) (-40L + months / 12), 6 + (int) (months % 12), 1), OFFSET_PONE));
+    }
+
+    @Test(expectedExceptions={DateTimeException.class}, groups={"tck"})
+    public void test_plusMonths_long_invalidTooLarge() {
+        OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 1), OFFSET_PONE).plusMonths(1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusMonths_long_invalidTooLargeMaxAddMax() {
+        OffsetDate test = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 1), OFFSET_PONE);
+        test.plusMonths(Long.MAX_VALUE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusMonths_long_invalidTooLargeMaxAddMin() {
+        OffsetDate test = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 1), OFFSET_PONE);
+        test.plusMonths(Long.MIN_VALUE);
+    }
+
+    @Test(expectedExceptions={DateTimeException.class}, groups={"tck"})
+    public void test_plusMonths_long_invalidTooSmall() {
+        OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 1), OFFSET_PONE).plusMonths(-1);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusWeeks()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="samplePlusWeeksSymmetry")
+    Object[][] provider_samplePlusWeeksSymmetry() {
+        return new Object[][] {
+            {OffsetDate.of(LocalDate.of(-1, 1, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(-1, 2, 28), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(-1, 3, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(-1, 12, 31), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(0, 1, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(0, 2, 28), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(0, 2, 29), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(0, 3, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(0, 12, 31), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2007, 1, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2007, 2, 28), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2007, 3, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2007, 12, 31), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2008, 1, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2008, 2, 28), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2008, 2, 29), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2008, 3, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2008, 12, 31), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2099, 1, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2099, 2, 28), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2099, 3, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2099, 12, 31), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2100, 1, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2100, 2, 28), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2100, 3, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2100, 12, 31), OFFSET_PTWO)},
+        };
+    }
+
+    @Test(dataProvider="samplePlusWeeksSymmetry", groups={"tck"})
+    public void test_plusWeeks_symmetry(OffsetDate reference) {
+        for (int weeks = 0; weeks < 365 * 8; weeks++) {
+            OffsetDate t = reference.plusWeeks(weeks).plusWeeks(-weeks);
+            assertEquals(t, reference);
+
+            t = reference.plusWeeks(-weeks).plusWeeks(weeks);
+            assertEquals(t, reference);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusWeeks_normal() {
+        OffsetDate t = TEST_2007_07_15_PONE.plusWeeks(1);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2007, 7, 22), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusWeeks_overMonths() {
+        OffsetDate t = TEST_2007_07_15_PONE.plusWeeks(9);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2007, 9, 16), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusWeeks_overYears() {
+        OffsetDate t = OffsetDate.of(LocalDate.of(2006, 7, 16), OFFSET_PONE).plusWeeks(52);
+        assertEquals(t, TEST_2007_07_15_PONE);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusWeeks_overLeapYears() {
+        OffsetDate t = TEST_2007_07_15_PONE.plusYears(-1).plusWeeks(104);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2008, 7, 12), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusWeeks_negative() {
+        OffsetDate t = TEST_2007_07_15_PONE.plusWeeks(-1);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2007, 7, 8), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusWeeks_negativeAcrossYear() {
+        OffsetDate t = TEST_2007_07_15_PONE.plusWeeks(-28);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2006, 12, 31), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusWeeks_negativeOverYears() {
+        OffsetDate t = TEST_2007_07_15_PONE.plusWeeks(-104);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2005, 7, 17), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusWeeks_noChange() {
+        OffsetDate t = TEST_2007_07_15_PONE.plusWeeks(0);
+        assertEquals(t, TEST_2007_07_15_PONE);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusWeeks_maximum() {
+        OffsetDate t = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 24), OFFSET_PONE).plusWeeks(1);
+        OffsetDate expected = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 31), OFFSET_PONE);
+        assertEquals(t, expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusWeeks_minimum() {
+        OffsetDate t = OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 8), OFFSET_PONE).plusWeeks(-1);
+        OffsetDate expected = OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 1), OFFSET_PONE);
+        assertEquals(t, expected);
+    }
+
+    @Test(expectedExceptions={DateTimeException.class}, groups={"tck"})
+    public void test_plusWeeks_invalidTooLarge() {
+        OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 25), OFFSET_PONE).plusWeeks(1);
+    }
+
+    @Test(expectedExceptions={DateTimeException.class}, groups={"tck"})
+    public void test_plusWeeks_invalidTooSmall() {
+        OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 7), OFFSET_PONE).plusWeeks(-1);
+    }
+
+    @Test(expectedExceptions={ArithmeticException.class}, groups={"tck"})
+    public void test_plusWeeks_invalidMaxMinusMax() {
+        OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 25), OFFSET_PONE).plusWeeks(Long.MAX_VALUE);
+    }
+
+    @Test(expectedExceptions={ArithmeticException.class}, groups={"tck"})
+    public void test_plusWeeks_invalidMaxMinusMin() {
+        OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 25), OFFSET_PONE).plusWeeks(Long.MIN_VALUE);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusDays()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="samplePlusDaysSymmetry")
+    Object[][] provider_samplePlusDaysSymmetry() {
+        return new Object[][] {
+            {OffsetDate.of(LocalDate.of(-1, 1, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(-1, 2, 28), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(-1, 3, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(-1, 12, 31), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(0, 1, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(0, 2, 28), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(0, 2, 29), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(0, 3, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(0, 12, 31), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2007, 1, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2007, 2, 28), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2007, 3, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2007, 12, 31), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2008, 1, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2008, 2, 28), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2008, 2, 29), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2008, 3, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2008, 12, 31), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2099, 1, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2099, 2, 28), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2099, 3, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2099, 12, 31), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2100, 1, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2100, 2, 28), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2100, 3, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2100, 12, 31), OFFSET_PTWO)},
+        };
+    }
+
+    @Test(dataProvider="samplePlusDaysSymmetry", groups={"tck"})
+    public void test_plusDays_symmetry(OffsetDate reference) {
+        for (int days = 0; days < 365 * 8; days++) {
+            OffsetDate t = reference.plusDays(days).plusDays(-days);
+            assertEquals(t, reference);
+
+            t = reference.plusDays(-days).plusDays(days);
+            assertEquals(t, reference);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusDays_normal() {
+        OffsetDate t = TEST_2007_07_15_PONE.plusDays(1);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2007, 7, 16), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusDays_overMonths() {
+        OffsetDate t = TEST_2007_07_15_PONE.plusDays(62);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2007, 9, 15), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusDays_overYears() {
+        OffsetDate t = OffsetDate.of(LocalDate.of(2006, 7, 14), OFFSET_PONE).plusDays(366);
+        assertEquals(t, TEST_2007_07_15_PONE);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusDays_overLeapYears() {
+        OffsetDate t = TEST_2007_07_15_PONE.plusYears(-1).plusDays(365 + 366);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2008, 7, 15), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusDays_negative() {
+        OffsetDate t = TEST_2007_07_15_PONE.plusDays(-1);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2007, 7, 14), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusDays_negativeAcrossYear() {
+        OffsetDate t = TEST_2007_07_15_PONE.plusDays(-196);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2006, 12, 31), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusDays_negativeOverYears() {
+        OffsetDate t = TEST_2007_07_15_PONE.plusDays(-730);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2005, 7, 15), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusDays_noChange() {
+        OffsetDate t = TEST_2007_07_15_PONE.plusDays(0);
+        assertEquals(t, TEST_2007_07_15_PONE);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusDays_maximum() {
+        OffsetDate t = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 30), OFFSET_PONE).plusDays(1);
+        OffsetDate expected = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 31), OFFSET_PONE);
+        assertEquals(t, expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusDays_minimum() {
+        OffsetDate t = OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 2), OFFSET_PONE).plusDays(-1);
+        OffsetDate expected = OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 1), OFFSET_PONE);
+        assertEquals(t, expected);
+    }
+
+    @Test(expectedExceptions={DateTimeException.class}, groups={"tck"})
+    public void test_plusDays_invalidTooLarge() {
+        OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 31), OFFSET_PONE).plusDays(1);
+    }
+
+    @Test(expectedExceptions={DateTimeException.class}, groups={"tck"})
+    public void test_plusDays_invalidTooSmall() {
+        OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 1), OFFSET_PONE).plusDays(-1);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void test_plusDays_overflowTooLarge() {
+        OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 31), OFFSET_PONE).plusDays(Long.MAX_VALUE);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void test_plusDays_overflowTooSmall() {
+        OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 1), OFFSET_PONE).plusDays(Long.MIN_VALUE);
+    }
+
+    //-----------------------------------------------------------------------
+    // minus(MinusAdjuster)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minus_MinusAdjuster() {
+        MockSimplePeriod period = MockSimplePeriod.of(7, ChronoUnit.MONTHS);
+        OffsetDate t = TEST_2007_07_15_PONE.minus(period);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2006, 12, 15), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minus_MinusAdjuster_noChange() {
+        MockSimplePeriod period = MockSimplePeriod.of(0, ChronoUnit.MONTHS);
+        OffsetDate t = TEST_2007_07_15_PONE.minus(period);
+        assertEquals(t, TEST_2007_07_15_PONE);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minus_MinusAdjuster_zero() {
+        OffsetDate t = TEST_2007_07_15_PONE.minus(Period.ZERO);
+        assertEquals(t, TEST_2007_07_15_PONE);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_plus_MinusAdjuster_null() {
+        TEST_2007_07_15_PONE.minus((TemporalSubtractor) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusYears()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusYears_long_normal() {
+        OffsetDate t = TEST_2007_07_15_PONE.minusYears(1);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2006, 7, 15), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusYears_long_negative() {
+        OffsetDate t = TEST_2007_07_15_PONE.minusYears(-1);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2008, 7, 15), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusYears_long_noChange() {
+        OffsetDate t = TEST_2007_07_15_PONE.minusYears(0);
+        assertEquals(t, TEST_2007_07_15_PONE);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusYears_long_adjustDay() {
+        OffsetDate t = OffsetDate.of(LocalDate.of(2008, 2, 29), OFFSET_PONE).minusYears(1);
+        OffsetDate expected = OffsetDate.of(LocalDate.of(2007, 2, 28), OFFSET_PONE);
+        assertEquals(t, expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusYears_long_big() {
+        long years = 20L + Year.MAX_VALUE;
+        OffsetDate test = OffsetDate.of(LocalDate.of(40, 6, 1), OFFSET_PONE).minusYears(years);
+        assertEquals(test, OffsetDate.of(LocalDate.of((int) (40L - years), 6, 1), OFFSET_PONE));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minusYears_long_invalidTooLarge() {
+        OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 1, 1), OFFSET_PONE).minusYears(-1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minusYears_long_invalidTooLargeMaxAddMax() {
+        OffsetDate test = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 1), OFFSET_PONE);
+        test.minusYears(Long.MAX_VALUE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minusYears_long_invalidTooLargeMaxAddMin() {
+        OffsetDate test = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 1), OFFSET_PONE);
+        test.minusYears(Long.MIN_VALUE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minusYears_long_invalidTooSmall() {
+        OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 1), OFFSET_PONE).minusYears(1);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusMonths()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusMonths_long_normal() {
+        OffsetDate t = TEST_2007_07_15_PONE.minusMonths(1);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2007, 6, 15), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMonths_long_overYears() {
+        OffsetDate t = TEST_2007_07_15_PONE.minusMonths(25);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2005, 6, 15), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMonths_long_negative() {
+        OffsetDate t = TEST_2007_07_15_PONE.minusMonths(-1);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2007, 8, 15), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMonths_long_negativeAcrossYear() {
+        OffsetDate t = TEST_2007_07_15_PONE.minusMonths(-7);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2008, 2, 15), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMonths_long_negativeOverYears() {
+        OffsetDate t = TEST_2007_07_15_PONE.minusMonths(-31);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2010, 2, 15), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMonths_long_noChange() {
+        OffsetDate t = TEST_2007_07_15_PONE.minusMonths(0);
+        assertEquals(t, TEST_2007_07_15_PONE);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMonths_long_adjustDayFromLeapYear() {
+        OffsetDate t = OffsetDate.of(LocalDate.of(2008, 2, 29), OFFSET_PONE).minusMonths(12);
+        OffsetDate expected = OffsetDate.of(LocalDate.of(2007, 2, 28), OFFSET_PONE);
+        assertEquals(t, expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMonths_long_adjustDayFromMonthLength() {
+        OffsetDate t = OffsetDate.of(LocalDate.of(2007, 3, 31), OFFSET_PONE).minusMonths(1);
+        OffsetDate expected = OffsetDate.of(LocalDate.of(2007, 2, 28), OFFSET_PONE);
+        assertEquals(t, expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMonths_long_big() {
+        long months = 20L + Integer.MAX_VALUE;
+        OffsetDate test = OffsetDate.of(LocalDate.of(40, 6, 1), OFFSET_PONE).minusMonths(months);
+        assertEquals(test, OffsetDate.of(LocalDate.of((int) (40L - months / 12), 6 - (int) (months % 12), 1), OFFSET_PONE));
+    }
+
+    @Test(expectedExceptions={DateTimeException.class}, groups={"tck"})
+    public void test_minusMonths_long_invalidTooLarge() {
+        OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 1), OFFSET_PONE).minusMonths(-1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minusMonths_long_invalidTooLargeMaxAddMax() {
+        OffsetDate test = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 1), OFFSET_PONE);
+        test.minusMonths(Long.MAX_VALUE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minusMonths_long_invalidTooLargeMaxAddMin() {
+        OffsetDate test = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 1), OFFSET_PONE);
+        test.minusMonths(Long.MIN_VALUE);
+    }
+
+    @Test(expectedExceptions={DateTimeException.class}, groups={"tck"})
+    public void test_minusMonths_long_invalidTooSmall() {
+        OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 1), OFFSET_PONE).minusMonths(1);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusWeeks()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sampleMinusWeeksSymmetry")
+    Object[][] provider_sampleMinusWeeksSymmetry() {
+        return new Object[][] {
+            {OffsetDate.of(LocalDate.of(-1, 1, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(-1, 2, 28), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(-1, 3, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(-1, 12, 31), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(0, 1, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(0, 2, 28), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(0, 2, 29), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(0, 3, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(0, 12, 31), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2007, 1, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2007, 2, 28), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2007, 3, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2007, 12, 31), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2008, 1, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2008, 2, 28), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2008, 2, 29), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2008, 3, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2008, 12, 31), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2099, 1, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2099, 2, 28), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2099, 3, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2099, 12, 31), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2100, 1, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2100, 2, 28), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2100, 3, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2100, 12, 31), OFFSET_PTWO)},
+        };
+    }
+
+    @Test(dataProvider="sampleMinusWeeksSymmetry", groups={"tck"})
+    public void test_minusWeeks_symmetry(OffsetDate reference) {
+        for (int weeks = 0; weeks < 365 * 8; weeks++) {
+            OffsetDate t = reference.minusWeeks(weeks).minusWeeks(-weeks);
+            assertEquals(t, reference);
+
+            t = reference.minusWeeks(-weeks).minusWeeks(weeks);
+            assertEquals(t, reference);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusWeeks_normal() {
+        OffsetDate t = TEST_2007_07_15_PONE.minusWeeks(1);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2007, 7, 8), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusWeeks_overMonths() {
+        OffsetDate t = TEST_2007_07_15_PONE.minusWeeks(9);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2007, 5, 13), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusWeeks_overYears() {
+        OffsetDate t = OffsetDate.of(LocalDate.of(2008, 7, 13), OFFSET_PONE).minusWeeks(52);
+        assertEquals(t, TEST_2007_07_15_PONE);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusWeeks_overLeapYears() {
+        OffsetDate t = TEST_2007_07_15_PONE.minusYears(-1).minusWeeks(104);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2006, 7, 18), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusWeeks_negative() {
+        OffsetDate t = TEST_2007_07_15_PONE.minusWeeks(-1);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2007, 7, 22), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusWeeks_negativeAcrossYear() {
+        OffsetDate t = TEST_2007_07_15_PONE.minusWeeks(-28);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2008, 1, 27), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusWeeks_negativeOverYears() {
+        OffsetDate t = TEST_2007_07_15_PONE.minusWeeks(-104);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2009, 7, 12), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusWeeks_noChange() {
+        OffsetDate t = TEST_2007_07_15_PONE.minusWeeks(0);
+        assertEquals(t, TEST_2007_07_15_PONE);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusWeeks_maximum() {
+        OffsetDate t = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 24), OFFSET_PONE).minusWeeks(-1);
+        OffsetDate expected = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 31), OFFSET_PONE);
+        assertEquals(t, expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusWeeks_minimum() {
+        OffsetDate t = OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 8), OFFSET_PONE).minusWeeks(1);
+        OffsetDate expected = OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 1), OFFSET_PONE);
+        assertEquals(t, expected);
+    }
+
+    @Test(expectedExceptions={DateTimeException.class}, groups={"tck"})
+    public void test_minusWeeks_invalidTooLarge() {
+        OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 25), OFFSET_PONE).minusWeeks(-1);
+    }
+
+    @Test(expectedExceptions={DateTimeException.class}, groups={"tck"})
+    public void test_minusWeeks_invalidTooSmall() {
+        OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 7), OFFSET_PONE).minusWeeks(1);
+    }
+
+    @Test(expectedExceptions={ArithmeticException.class}, groups={"tck"})
+    public void test_minusWeeks_invalidMaxMinusMax() {
+        OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 25), OFFSET_PONE).minusWeeks(Long.MAX_VALUE);
+    }
+
+    @Test(expectedExceptions={ArithmeticException.class}, groups={"tck"})
+    public void test_minusWeeks_invalidMaxMinusMin() {
+        OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 25), OFFSET_PONE).minusWeeks(Long.MIN_VALUE);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusDays()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sampleMinusDaysSymmetry")
+    Object[][] provider_sampleMinusDaysSymmetry() {
+        return new Object[][] {
+            {OffsetDate.of(LocalDate.of(-1, 1, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(-1, 2, 28), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(-1, 3, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(-1, 12, 31), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(0, 1, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(0, 2, 28), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(0, 2, 29), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(0, 3, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(0, 12, 31), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2007, 1, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2007, 2, 28), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2007, 3, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2007, 12, 31), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2008, 1, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2008, 2, 28), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2008, 2, 29), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2008, 3, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2008, 12, 31), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2099, 1, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2099, 2, 28), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2099, 3, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2099, 12, 31), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2100, 1, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2100, 2, 28), OFFSET_PTWO)},
+            {OffsetDate.of(LocalDate.of(2100, 3, 1), OFFSET_PONE)},
+            {OffsetDate.of(LocalDate.of(2100, 12, 31), OFFSET_PTWO)},
+        };
+    }
+
+    @Test(dataProvider="sampleMinusDaysSymmetry", groups={"tck"})
+    public void test_minusDays_symmetry(OffsetDate reference) {
+        for (int days = 0; days < 365 * 8; days++) {
+            OffsetDate t = reference.minusDays(days).minusDays(-days);
+            assertEquals(t, reference);
+
+            t = reference.minusDays(-days).minusDays(days);
+            assertEquals(t, reference);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusDays_normal() {
+        OffsetDate t = TEST_2007_07_15_PONE.minusDays(1);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2007, 7, 14), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusDays_overMonths() {
+        OffsetDate t = TEST_2007_07_15_PONE.minusDays(62);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2007, 5, 14), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusDays_overYears() {
+        OffsetDate t = OffsetDate.of(LocalDate.of(2008, 7, 16), OFFSET_PONE).minusDays(367);
+        assertEquals(t, TEST_2007_07_15_PONE);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusDays_overLeapYears() {
+        OffsetDate t = TEST_2007_07_15_PONE.plusYears(2).minusDays(365 + 366);
+        assertEquals(t, TEST_2007_07_15_PONE);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusDays_negative() {
+        OffsetDate t = TEST_2007_07_15_PONE.minusDays(-1);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2007, 7, 16), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusDays_negativeAcrossYear() {
+        OffsetDate t = TEST_2007_07_15_PONE.minusDays(-169);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2007, 12, 31), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusDays_negativeOverYears() {
+        OffsetDate t = TEST_2007_07_15_PONE.minusDays(-731);
+        assertEquals(t, OffsetDate.of(LocalDate.of(2009, 7, 15), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusDays_noChange() {
+        OffsetDate t = TEST_2007_07_15_PONE.minusDays(0);
+        assertEquals(t, TEST_2007_07_15_PONE);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusDays_maximum() {
+        OffsetDate t = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 30), OFFSET_PONE).minusDays(-1);
+        OffsetDate expected = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 31), OFFSET_PONE);
+        assertEquals(t, expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusDays_minimum() {
+        OffsetDate t = OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 2), OFFSET_PONE).minusDays(1);
+        OffsetDate expected = OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 1), OFFSET_PONE);
+        assertEquals(t, expected);
+    }
+
+    @Test(expectedExceptions={DateTimeException.class}, groups={"tck"})
+    public void test_minusDays_invalidTooLarge() {
+        OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 31), OFFSET_PONE).minusDays(-1);
+    }
+
+    @Test(expectedExceptions={DateTimeException.class}, groups={"tck"})
+    public void test_minusDays_invalidTooSmall() {
+        OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 1), OFFSET_PONE).minusDays(1);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void test_minusDays_overflowTooLarge() {
+        OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 31), OFFSET_PONE).minusDays(Long.MIN_VALUE);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class, groups={"tck"})
+    public void test_minusDays_overflowTooSmall() {
+        OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 1), OFFSET_PONE).minusDays(Long.MAX_VALUE);
+    }
+
+    //-----------------------------------------------------------------------
+    // atTime()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_atTime_Local() {
+        OffsetDate t = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PTWO);
+        assertEquals(t.atTime(LocalTime.of(11, 30)),
+                OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30), OFFSET_PTWO));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_atTime_Local_nullLocalTime() {
+        OffsetDate t = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PTWO);
+        t.atTime((LocalTime) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // getDate()
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="sampleDates", groups={"tck"})
+    public void test_getDate(int year, int month, int day, ZoneOffset offset) {
+        LocalDate t = LocalDate.of(year, month, day);
+        assertEquals(OffsetDate.of(LocalDate.of(year, month, day), offset).getDate(), t);
+    }
+
+    //-----------------------------------------------------------------------
+    // compareTo()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_compareTo_date() {
+        OffsetDate a = OffsetDate.of(LocalDate.of(2008, 6, 29), OFFSET_PONE);
+        OffsetDate b = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE);  // a is before b due to date
+        assertEquals(a.compareTo(b) < 0, true);
+        assertEquals(b.compareTo(a) > 0, true);
+        assertEquals(a.compareTo(a) == 0, true);
+        assertEquals(b.compareTo(b) == 0, true);
+        assertEquals(a.atTime(LocalTime.MIDNIGHT).toInstant().compareTo(b.atTime(LocalTime.MIDNIGHT).toInstant()) < 0, true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_compareTo_offset() {
+        OffsetDate a = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PTWO);
+        OffsetDate b = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE);  // a is before b due to offset
+        assertEquals(a.compareTo(b) < 0, true);
+        assertEquals(b.compareTo(a) > 0, true);
+        assertEquals(a.compareTo(a) == 0, true);
+        assertEquals(b.compareTo(b) == 0, true);
+        assertEquals(a.atTime(LocalTime.MIDNIGHT).toInstant().compareTo(b.atTime(LocalTime.MIDNIGHT).toInstant()) < 0, true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_compareTo_both() {
+        OffsetDate a = OffsetDate.of(LocalDate.of(2008, 6, 29), OFFSET_PTWO);
+        OffsetDate b = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE);  // a is before b on instant scale
+        assertEquals(a.compareTo(b) < 0, true);
+        assertEquals(b.compareTo(a) > 0, true);
+        assertEquals(a.compareTo(a) == 0, true);
+        assertEquals(b.compareTo(b) == 0, true);
+        assertEquals(a.atTime(LocalTime.MIDNIGHT).toInstant().compareTo(b.atTime(LocalTime.MIDNIGHT).toInstant()) < 0, true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_compareTo_24hourDifference() {
+        OffsetDate a = OffsetDate.of(LocalDate.of(2008, 6, 29), ZoneOffset.ofHours(-12));
+        OffsetDate b = OffsetDate.of(LocalDate.of(2008, 6, 30), ZoneOffset.ofHours(12));  // a is before b despite being same time-line time
+        assertEquals(a.compareTo(b) < 0, true);
+        assertEquals(b.compareTo(a) > 0, true);
+        assertEquals(a.compareTo(a) == 0, true);
+        assertEquals(b.compareTo(b) == 0, true);
+        assertEquals(a.atTime(LocalTime.MIDNIGHT).toInstant().compareTo(b.atTime(LocalTime.MIDNIGHT).toInstant()) == 0, true);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_compareTo_null() {
+        OffsetDate a = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE);
+        a.compareTo(null);
+    }
+
+    @Test(expectedExceptions=ClassCastException.class, groups={"tck"})
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public void compareToNonOffsetDate() {
+       Comparable c = TEST_2007_07_15_PONE;
+       c.compareTo(new Object());
+    }
+
+    //-----------------------------------------------------------------------
+    // isAfter() / isBefore() / isEqual()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_isBeforeIsAfterIsEqual1() {
+        OffsetDate a = OffsetDate.of(LocalDate.of(2008, 6, 29), OFFSET_PONE);
+        OffsetDate b = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE);  // a is before b due to time
+        assertEquals(a.isBefore(b), true);
+        assertEquals(a.isEqual(b), false);
+        assertEquals(a.isAfter(b), false);
+
+        assertEquals(b.isBefore(a), false);
+        assertEquals(b.isEqual(a), false);
+        assertEquals(b.isAfter(a), true);
+
+        assertEquals(a.isBefore(a), false);
+        assertEquals(b.isBefore(b), false);
+
+        assertEquals(a.isEqual(a), true);
+        assertEquals(b.isEqual(b), true);
+
+        assertEquals(a.isAfter(a), false);
+        assertEquals(b.isAfter(b), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_isBeforeIsAfterIsEqual2() {
+        OffsetDate a = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PTWO);
+        OffsetDate b = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE);  // a is before b due to offset
+        assertEquals(a.isBefore(b), true);
+        assertEquals(a.isEqual(b), false);
+        assertEquals(a.isAfter(b), false);
+
+        assertEquals(b.isBefore(a), false);
+        assertEquals(b.isEqual(a), false);
+        assertEquals(b.isAfter(a), true);
+
+        assertEquals(a.isBefore(a), false);
+        assertEquals(b.isBefore(b), false);
+
+        assertEquals(a.isEqual(a), true);
+        assertEquals(b.isEqual(b), true);
+
+        assertEquals(a.isAfter(a), false);
+        assertEquals(b.isAfter(b), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_isBeforeIsAfterIsEqual_instantComparison() {
+        OffsetDate a = OffsetDate.of(LocalDate.of(2008, 6, 30), ZoneOffset.ofHours(12));
+        OffsetDate b = OffsetDate.of(LocalDate.of(2008, 6, 29), ZoneOffset.ofHours(-12));  // a is same instant as b
+        assertEquals(a.isBefore(b), false);
+        assertEquals(a.isEqual(b), true);
+        assertEquals(a.isAfter(b), false);
+
+        assertEquals(b.isBefore(a), false);
+        assertEquals(b.isEqual(a), true);
+        assertEquals(b.isAfter(a), false);
+
+        assertEquals(a.isBefore(a), false);
+        assertEquals(b.isBefore(b), false);
+
+        assertEquals(a.isEqual(a), true);
+        assertEquals(b.isEqual(b), true);
+
+        assertEquals(a.isAfter(a), false);
+        assertEquals(b.isAfter(b), false);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_isBefore_null() {
+        OffsetDate a = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE);
+        a.isBefore(null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_isAfter_null() {
+        OffsetDate a = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE);
+        a.isAfter(null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_isEqual_null() {
+        OffsetDate a = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE);
+        a.isEqual(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // equals() / hashCode()
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="sampleDates", groups={"tck"})
+    public void test_equals_true(int y, int m, int d, ZoneOffset offset) {
+        OffsetDate a = OffsetDate.of(LocalDate.of(y, m, d), offset);
+        OffsetDate b = OffsetDate.of(LocalDate.of(y, m, d), offset);
+        assertEquals(a.equals(b), true);
+        assertEquals(a.hashCode() == b.hashCode(), true);
+    }
+    @Test(dataProvider="sampleDates", groups={"tck"})
+    public void test_equals_false_year_differs(int y, int m, int d, ZoneOffset offset) {
+        OffsetDate a = OffsetDate.of(LocalDate.of(y, m, d), offset);
+        OffsetDate b = OffsetDate.of(LocalDate.of(y + 1, m, d), offset);
+        assertEquals(a.equals(b), false);
+    }
+
+    @Test(dataProvider="sampleDates", groups={"tck"})
+    public void test_equals_false_month_differs(int y, int m, int d, ZoneOffset offset) {
+        OffsetDate a = OffsetDate.of(LocalDate.of(y, m, d), offset);
+        OffsetDate b = OffsetDate.of(LocalDate.of(y, m + 1, d), offset);
+        assertEquals(a.equals(b), false);
+    }
+
+    @Test(dataProvider="sampleDates", groups={"tck"})
+    public void test_equals_false_day_differs(int y, int m, int d, ZoneOffset offset) {
+        OffsetDate a = OffsetDate.of(LocalDate.of(y, m, d), offset);
+        OffsetDate b = OffsetDate.of(LocalDate.of(y, m, d + 1), offset);
+        assertEquals(a.equals(b), false);
+    }
+
+    @Test(dataProvider="sampleDates", groups={"tck"})
+    public void test_equals_false_offset_differs(int y, int m, int d, ZoneOffset ignored) {
+        OffsetDate a = OffsetDate.of(LocalDate.of(y, m, d), OFFSET_PONE);
+        OffsetDate b = OffsetDate.of(LocalDate.of(y, m, d), OFFSET_PTWO);
+        assertEquals(a.equals(b), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_itself_true() {
+        assertEquals(TEST_2007_07_15_PONE.equals(TEST_2007_07_15_PONE), true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_string_false() {
+        assertEquals(TEST_2007_07_15_PONE.equals("2007-07-15"), false);
+    }
+
+    //-----------------------------------------------------------------------
+    // toString()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sampleToString")
+    Object[][] provider_sampleToString() {
+        return new Object[][] {
+            {2008, 7, 5, "Z", "2008-07-05Z"},
+            {2008, 7, 5, "+00", "2008-07-05Z"},
+            {2008, 7, 5, "+0000", "2008-07-05Z"},
+            {2008, 7, 5, "+00:00", "2008-07-05Z"},
+            {2008, 7, 5, "+000000", "2008-07-05Z"},
+            {2008, 7, 5, "+00:00:00", "2008-07-05Z"},
+            {2008, 7, 5, "-00", "2008-07-05Z"},
+            {2008, 7, 5, "-0000", "2008-07-05Z"},
+            {2008, 7, 5, "-00:00", "2008-07-05Z"},
+            {2008, 7, 5, "-000000", "2008-07-05Z"},
+            {2008, 7, 5, "-00:00:00", "2008-07-05Z"},
+            {2008, 7, 5, "+01", "2008-07-05+01:00"},
+            {2008, 7, 5, "+0100", "2008-07-05+01:00"},
+            {2008, 7, 5, "+01:00", "2008-07-05+01:00"},
+            {2008, 7, 5, "+010000", "2008-07-05+01:00"},
+            {2008, 7, 5, "+01:00:00", "2008-07-05+01:00"},
+            {2008, 7, 5, "+0130", "2008-07-05+01:30"},
+            {2008, 7, 5, "+01:30", "2008-07-05+01:30"},
+            {2008, 7, 5, "+013000", "2008-07-05+01:30"},
+            {2008, 7, 5, "+01:30:00", "2008-07-05+01:30"},
+            {2008, 7, 5, "+013040", "2008-07-05+01:30:40"},
+            {2008, 7, 5, "+01:30:40", "2008-07-05+01:30:40"},
+        };
+    }
+
+    @Test(dataProvider="sampleToString", groups={"tck"})
+    public void test_toString(int y, int m, int d, String offsetId, String expected) {
+        OffsetDate t = OffsetDate.of(LocalDate.of(y, m, d), ZoneOffset.of(offsetId));
+        String str = t.toString();
+        assertEquals(str, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // toString(DateTimeFormatter)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_toString_formatter() {
+        DateTimeFormatter f = DateTimeFormatters.pattern("y M d");
+        String t = OffsetDate.of(LocalDate.of(2010, 12, 3), OFFSET_PONE).toString(f);
+        assertEquals(t, "2010 12 3");
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_toString_formatter_null() {
+        OffsetDate.of(LocalDate.of(2010, 12, 3), OFFSET_PONE).toString(null);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/temporal/TCKOffsetDateTime.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,1488 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.temporal;
+
+import static java.time.Month.DECEMBER;
+import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH;
+import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR;
+import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH;
+import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR;
+import static java.time.temporal.ChronoField.AMPM_OF_DAY;
+import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_AMPM;
+import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_DAY;
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.DAY_OF_WEEK;
+import static java.time.temporal.ChronoField.DAY_OF_YEAR;
+import static java.time.temporal.ChronoField.EPOCH_DAY;
+import static java.time.temporal.ChronoField.EPOCH_MONTH;
+import static java.time.temporal.ChronoField.ERA;
+import static java.time.temporal.ChronoField.HOUR_OF_AMPM;
+import static java.time.temporal.ChronoField.HOUR_OF_DAY;
+import static java.time.temporal.ChronoField.INSTANT_SECONDS;
+import static java.time.temporal.ChronoField.MICRO_OF_DAY;
+import static java.time.temporal.ChronoField.MICRO_OF_SECOND;
+import static java.time.temporal.ChronoField.MILLI_OF_DAY;
+import static java.time.temporal.ChronoField.MILLI_OF_SECOND;
+import static java.time.temporal.ChronoField.MINUTE_OF_DAY;
+import static java.time.temporal.ChronoField.MINUTE_OF_HOUR;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.NANO_OF_DAY;
+import static java.time.temporal.ChronoField.NANO_OF_SECOND;
+import static java.time.temporal.ChronoField.OFFSET_SECONDS;
+import static java.time.temporal.ChronoField.SECOND_OF_DAY;
+import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
+import static java.time.temporal.ChronoField.YEAR;
+import static java.time.temporal.ChronoField.YEAR_OF_ERA;
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.NANOS;
+import static java.time.temporal.ChronoUnit.SECONDS;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.Month;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatters;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.ISOChrono;
+import java.time.temporal.JulianFields;
+import java.time.temporal.OffsetDate;
+import java.time.temporal.OffsetDateTime;
+import java.time.temporal.OffsetTime;
+import java.time.temporal.Queries;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.Year;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import tck.java.time.AbstractDateTimeTest;
+import test.java.time.MockSimplePeriod;
+
+/**
+ * Test OffsetDateTime.
+ */
+@Test
+public class TCKOffsetDateTime extends AbstractDateTimeTest {
+
+    private static final ZoneId ZONE_PARIS = ZoneId.of("Europe/Paris");
+    private static final ZoneId ZONE_GAZA = ZoneId.of("Asia/Gaza");
+    private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1);
+    private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2);
+    private static final ZoneOffset OFFSET_MONE = ZoneOffset.ofHours(-1);
+    private static final ZoneOffset OFFSET_MTWO = ZoneOffset.ofHours(-2);
+    private OffsetDateTime TEST_2008_6_30_11_30_59_000000500;
+
+    @BeforeMethod(groups={"tck","implementation"})
+    public void setUp() {
+        TEST_2008_6_30_11_30_59_000000500 = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59, 500), OFFSET_PONE);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    protected List<TemporalAccessor> samples() {
+        TemporalAccessor[] array = {TEST_2008_6_30_11_30_59_000000500, OffsetDateTime.MIN, OffsetDateTime.MAX};
+        return Arrays.asList(array);
+    }
+
+    @Override
+    protected List<TemporalField> validFields() {
+        TemporalField[] array = {
+            NANO_OF_SECOND,
+            NANO_OF_DAY,
+            MICRO_OF_SECOND,
+            MICRO_OF_DAY,
+            MILLI_OF_SECOND,
+            MILLI_OF_DAY,
+            SECOND_OF_MINUTE,
+            SECOND_OF_DAY,
+            MINUTE_OF_HOUR,
+            MINUTE_OF_DAY,
+            CLOCK_HOUR_OF_AMPM,
+            HOUR_OF_AMPM,
+            CLOCK_HOUR_OF_DAY,
+            HOUR_OF_DAY,
+            AMPM_OF_DAY,
+            DAY_OF_WEEK,
+            ALIGNED_DAY_OF_WEEK_IN_MONTH,
+            ALIGNED_DAY_OF_WEEK_IN_YEAR,
+            DAY_OF_MONTH,
+            DAY_OF_YEAR,
+            EPOCH_DAY,
+            ALIGNED_WEEK_OF_MONTH,
+            ALIGNED_WEEK_OF_YEAR,
+            MONTH_OF_YEAR,
+            EPOCH_MONTH,
+            YEAR_OF_ERA,
+            YEAR,
+            ERA,
+            OFFSET_SECONDS,
+            INSTANT_SECONDS,
+            JulianFields.JULIAN_DAY,
+            JulianFields.MODIFIED_JULIAN_DAY,
+            JulianFields.RATA_DIE,
+        };
+        return Arrays.asList(array);
+    }
+
+    @Override
+    protected List<TemporalField> invalidFields() {
+        List<TemporalField> list = new ArrayList<>(Arrays.<TemporalField>asList(ChronoField.values()));
+        list.removeAll(validFields());
+        return list;
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_serialization() throws Exception {
+        assertSerializable(TEST_2008_6_30_11_30_59_000000500);
+        assertSerializable(OffsetDateTime.MIN);
+        assertSerializable(OffsetDateTime.MAX);
+    }
+
+    @Test
+    public void test_serialization_format() throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try (DataOutputStream dos = new DataOutputStream(baos) ) {
+            dos.writeByte(3);
+        }
+        byte[] bytes = baos.toByteArray();
+        ByteArrayOutputStream baosDateTime = new ByteArrayOutputStream();
+        try (DataOutputStream dos = new DataOutputStream(baosDateTime) ) {
+            dos.writeByte(5);
+            dos.writeInt(2012);
+            dos.writeByte(9);
+            dos.writeByte(16);
+            dos.writeByte(22);
+            dos.writeByte(17);
+            dos.writeByte(59);
+            dos.writeInt(464_000_000);
+        }
+        byte[] bytesDateTime = baosDateTime.toByteArray();
+        ByteArrayOutputStream baosOffset = new ByteArrayOutputStream();
+        try (DataOutputStream dos = new DataOutputStream(baosOffset) ) {
+            dos.writeByte(8);
+            dos.writeByte(4);  // quarter hours stored: 3600 / 900
+        }
+        byte[] bytesOffset = baosOffset.toByteArray();
+        LocalDateTime ldt = LocalDateTime.of(2012, 9, 16, 22, 17, 59, 464_000_000);
+        assertSerializedBySer(OffsetDateTime.of(ldt, ZoneOffset.ofHours(1)), bytes, bytesDateTime, bytesOffset);
+    }
+
+    //-----------------------------------------------------------------------
+    // constants
+    //-----------------------------------------------------------------------
+    @Test
+    public void constant_MIN() {
+        check(OffsetDateTime.MIN, Year.MIN_VALUE, 1, 1, 0, 0, 0, 0, ZoneOffset.MAX);
+    }
+
+    @Test
+    public void constant_MAX() {
+        check(OffsetDateTime.MAX, Year.MAX_VALUE, 12, 31, 23, 59, 59, 999999999, ZoneOffset.MIN);
+    }
+
+    //-----------------------------------------------------------------------
+    // now()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void now() {
+        OffsetDateTime expected = OffsetDateTime.now(Clock.systemDefaultZone());
+        OffsetDateTime test = OffsetDateTime.now();
+        long diff = Math.abs(test.getTime().toNanoOfDay() - expected.getTime().toNanoOfDay());
+        if (diff >= 100000000) {
+            // may be date change
+            expected = OffsetDateTime.now(Clock.systemDefaultZone());
+            test = OffsetDateTime.now();
+            diff = Math.abs(test.getTime().toNanoOfDay() - expected.getTime().toNanoOfDay());
+        }
+        assertTrue(diff < 100000000);  // less than 0.1 secs
+    }
+
+    //-----------------------------------------------------------------------
+    // now(Clock)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void now_Clock_allSecsInDay_utc() {
+        for (int i = 0; i < (2 * 24 * 60 * 60); i++) {
+            Instant instant = Instant.ofEpochSecond(i).plusNanos(123456789L);
+            Clock clock = Clock.fixed(instant, ZoneOffset.UTC);
+            OffsetDateTime test = OffsetDateTime.now(clock);
+            assertEquals(test.getYear(), 1970);
+            assertEquals(test.getMonth(), Month.JANUARY);
+            assertEquals(test.getDayOfMonth(), (i < 24 * 60 * 60 ? 1 : 2));
+            assertEquals(test.getHour(), (i / (60 * 60)) % 24);
+            assertEquals(test.getMinute(), (i / 60) % 60);
+            assertEquals(test.getSecond(), i % 60);
+            assertEquals(test.getNano(), 123456789);
+            assertEquals(test.getOffset(), ZoneOffset.UTC);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void now_Clock_allSecsInDay_offset() {
+        for (int i = 0; i < (2 * 24 * 60 * 60); i++) {
+            Instant instant = Instant.ofEpochSecond(i).plusNanos(123456789L);
+            Clock clock = Clock.fixed(instant.minusSeconds(OFFSET_PONE.getTotalSeconds()), OFFSET_PONE);
+            OffsetDateTime test = OffsetDateTime.now(clock);
+            assertEquals(test.getYear(), 1970);
+            assertEquals(test.getMonth(), Month.JANUARY);
+            assertEquals(test.getDayOfMonth(), (i < 24 * 60 * 60) ? 1 : 2);
+            assertEquals(test.getHour(), (i / (60 * 60)) % 24);
+            assertEquals(test.getMinute(), (i / 60) % 60);
+            assertEquals(test.getSecond(), i % 60);
+            assertEquals(test.getNano(), 123456789);
+            assertEquals(test.getOffset(), OFFSET_PONE);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void now_Clock_allSecsInDay_beforeEpoch() {
+        LocalTime expected = LocalTime.MIDNIGHT.plusNanos(123456789L);
+        for (int i =-1; i >= -(24 * 60 * 60); i--) {
+            Instant instant = Instant.ofEpochSecond(i).plusNanos(123456789L);
+            Clock clock = Clock.fixed(instant, ZoneOffset.UTC);
+            OffsetDateTime test = OffsetDateTime.now(clock);
+            assertEquals(test.getYear(), 1969);
+            assertEquals(test.getMonth(), Month.DECEMBER);
+            assertEquals(test.getDayOfMonth(), 31);
+            expected = expected.minusSeconds(1);
+            assertEquals(test.getTime(), expected);
+            assertEquals(test.getOffset(), ZoneOffset.UTC);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void now_Clock_offsets() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(1970, 1, 1), LocalTime.of(12, 0), ZoneOffset.UTC);
+        for (int i = -9; i < 15; i++) {
+            ZoneOffset offset = ZoneOffset.ofHours(i);
+            Clock clock = Clock.fixed(base.toInstant(), offset);
+            OffsetDateTime test = OffsetDateTime.now(clock);
+            assertEquals(test.getHour(), (12 + i) % 24);
+            assertEquals(test.getMinute(), 0);
+            assertEquals(test.getSecond(), 0);
+            assertEquals(test.getNano(), 0);
+            assertEquals(test.getOffset(), offset);
+        }
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void now_Clock_nullZoneId() {
+        OffsetDateTime.now((ZoneId) null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void now_Clock_nullClock() {
+        OffsetDateTime.now((Clock) null);
+    }
+
+    //-----------------------------------------------------------------------
+    private void check(OffsetDateTime test, int y, int mo, int d, int h, int m, int s, int n, ZoneOffset offset) {
+        assertEquals(test.getYear(), y);
+        assertEquals(test.getMonth().getValue(), mo);
+        assertEquals(test.getDayOfMonth(), d);
+        assertEquals(test.getHour(), h);
+        assertEquals(test.getMinute(), m);
+        assertEquals(test.getSecond(), s);
+        assertEquals(test.getNano(), n);
+        assertEquals(test.getOffset(), offset);
+        assertEquals(test, test);
+        assertEquals(test.hashCode(), test.hashCode());
+        assertEquals(OffsetDateTime.of(LocalDateTime.of(y, mo, d, h, m, s, n), offset), test);
+    }
+
+    //-----------------------------------------------------------------------
+    // dateTime factories
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_of_intMonthIntHM() {
+        OffsetDateTime test = OffsetDateTime.of(LocalDate.of(2008, Month.JUNE, 30),
+                LocalTime.of(11, 30), OFFSET_PONE);
+        check(test, 2008, 6, 30, 11, 30, 0, 0, OFFSET_PONE);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_of_intMonthIntHMS() {
+        OffsetDateTime test = OffsetDateTime.of(LocalDate.of(2008, Month.JUNE, 30),
+                LocalTime.of(11, 30, 10), OFFSET_PONE);
+        check(test, 2008, 6, 30, 11, 30, 10, 0, OFFSET_PONE);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_of_intMonthIntHMSN() {
+        OffsetDateTime test = OffsetDateTime.of(LocalDate.of(2008, Month.JUNE, 30),
+                LocalTime.of(11, 30, 10, 500), OFFSET_PONE);
+        check(test, 2008, 6, 30, 11, 30, 10, 500, OFFSET_PONE);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_of_intsHM() {
+        OffsetDateTime test = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30), OFFSET_PONE);
+        check(test, 2008, 6, 30, 11, 30, 0, 0, OFFSET_PONE);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_of_intsHMS() {
+        OffsetDateTime test = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 10), OFFSET_PONE);
+        check(test, 2008, 6, 30, 11, 30, 10, 0, OFFSET_PONE);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_of_intsHMSN() {
+        OffsetDateTime test = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 10, 500), OFFSET_PONE);
+        check(test, 2008, 6, 30, 11, 30, 10, 500, OFFSET_PONE);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_of_LocalDateLocalTimeZoneOffset() {
+        LocalDate date = LocalDate.of(2008, 6, 30);
+        LocalTime time = LocalTime.of(11, 30, 10, 500);
+        OffsetDateTime test = OffsetDateTime.of(date, time, OFFSET_PONE);
+        check(test, 2008, 6, 30, 11, 30, 10, 500, OFFSET_PONE);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_of_LocalDateLocalTimeZoneOffset_nullLocalDate() {
+        LocalTime time = LocalTime.of(11, 30, 10, 500);
+        OffsetDateTime.of((LocalDate) null, time, OFFSET_PONE);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_of_LocalDateLocalTimeZoneOffset_nullLocalTime() {
+        LocalDate date = LocalDate.of(2008, 6, 30);
+        OffsetDateTime.of(date, (LocalTime) null, OFFSET_PONE);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_of_LocalDateLocalTimeZoneOffset_nullOffset() {
+        LocalDate date = LocalDate.of(2008, 6, 30);
+        LocalTime time = LocalTime.of(11, 30, 10, 500);
+        OffsetDateTime.of(date, time, (ZoneOffset) null);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_of_LocalDateTimeZoneOffset() {
+        LocalDateTime dt = LocalDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 10, 500));
+        OffsetDateTime test = OffsetDateTime.of(dt, OFFSET_PONE);
+        check(test, 2008, 6, 30, 11, 30, 10, 500, OFFSET_PONE);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_of_LocalDateTimeZoneOffset_nullProvider() {
+        OffsetDateTime.of((LocalDateTime) null, OFFSET_PONE);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_of_LocalDateTimeZoneOffset_nullOffset() {
+        LocalDateTime dt = LocalDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 10, 500));
+        OffsetDateTime.of(dt, (ZoneOffset) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // from()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_factory_CalendricalObject() {
+        assertEquals(OffsetDateTime.from(
+                OffsetDateTime.of(LocalDate.of(2007, 7, 15), LocalTime.of(17, 30), OFFSET_PONE)),
+                OffsetDateTime.of(LocalDate.of(2007, 7, 15), LocalTime.of(17, 30), OFFSET_PONE));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_CalendricalObject_invalid_noDerive() {
+        OffsetDateTime.from(LocalTime.of(12, 30));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_factory_Calendricals_null() {
+        OffsetDateTime.from((TemporalAccessor) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // parse()
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="sampleToString", groups={"tck"})
+    public void test_parse(int y, int month, int d, int h, int m, int s, int n, String offsetId, String text) {
+        OffsetDateTime t = OffsetDateTime.parse(text);
+        assertEquals(t.getYear(), y);
+        assertEquals(t.getMonth().getValue(), month);
+        assertEquals(t.getDayOfMonth(), d);
+        assertEquals(t.getHour(), h);
+        assertEquals(t.getMinute(), m);
+        assertEquals(t.getSecond(), s);
+        assertEquals(t.getNano(), n);
+        assertEquals(t.getOffset().getId(), offsetId);
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"})
+    public void factory_parse_illegalValue() {
+        OffsetDateTime.parse("2008-06-32T11:15+01:00");
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"})
+    public void factory_parse_invalidValue() {
+        OffsetDateTime.parse("2008-06-31T11:15+01:00");
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_parse_nullText() {
+        OffsetDateTime.parse((String) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // parse(DateTimeFormatter)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_parse_formatter() {
+        DateTimeFormatter f = DateTimeFormatters.pattern("y M d H m s XXX");
+        OffsetDateTime test = OffsetDateTime.parse("2010 12 3 11 30 0 +01:00", f);
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2010, 12, 3), LocalTime.of(11, 30), ZoneOffset.ofHours(1)));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_parse_formatter_nullText() {
+        DateTimeFormatter f = DateTimeFormatters.pattern("y M d H m s");
+        OffsetDateTime.parse((String) null, f);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_parse_formatter_nullFormatter() {
+        OffsetDateTime.parse("ANY", null);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void constructor_nullTime() throws Throwable  {
+        Constructor<OffsetDateTime> con = OffsetDateTime.class.getDeclaredConstructor(LocalDateTime.class, ZoneOffset.class);
+        con.setAccessible(true);
+        try {
+            con.newInstance(null, OFFSET_PONE);
+        } catch (InvocationTargetException ex) {
+            throw ex.getCause();
+        }
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void constructor_nullOffset() throws Throwable  {
+        Constructor<OffsetDateTime> con = OffsetDateTime.class.getDeclaredConstructor(LocalDateTime.class, ZoneOffset.class);
+        con.setAccessible(true);
+        try {
+            con.newInstance(LocalDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30)), null);
+        } catch (InvocationTargetException ex) {
+            throw ex.getCause();
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // basics
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sampleTimes")
+    Object[][] provider_sampleTimes() {
+        return new Object[][] {
+            {2008, 6, 30, 11, 30, 20, 500, OFFSET_PONE},
+            {2008, 6, 30, 11, 0, 0, 0, OFFSET_PONE},
+            {2008, 6, 30, 23, 59, 59, 999999999, OFFSET_PONE},
+            {-1, 1, 1, 0, 0, 0, 0, OFFSET_PONE},
+        };
+    }
+
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_get(int y, int o, int d, int h, int m, int s, int n, ZoneOffset offset) {
+        LocalDate localDate = LocalDate.of(y, o, d);
+        LocalTime localTime = LocalTime.of(h, m, s, n);
+        LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);
+        OffsetDateTime a = OffsetDateTime.of(localDateTime, offset);
+
+        assertEquals(a.getYear(), localDate.getYear());
+        assertEquals(a.getMonth(), localDate.getMonth());
+        assertEquals(a.getDayOfMonth(), localDate.getDayOfMonth());
+        assertEquals(a.getDayOfYear(), localDate.getDayOfYear());
+        assertEquals(a.getDayOfWeek(), localDate.getDayOfWeek());
+
+        assertEquals(a.getHour(), localDateTime.getHour());
+        assertEquals(a.getMinute(), localDateTime.getMinute());
+        assertEquals(a.getSecond(), localDateTime.getSecond());
+        assertEquals(a.getNano(), localDateTime.getNano());
+
+        assertEquals(a.toOffsetDate(), OffsetDate.of(localDate, offset));
+        assertEquals(a.toOffsetTime(), OffsetTime.of(localTime, offset));
+        assertEquals(a.toString(), localDateTime.toString() + offset.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    // get(TemporalField)
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_get_TemporalField() {
+        OffsetDateTime test = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(12, 30, 40, 987654321), OFFSET_PONE);
+        assertEquals(test.get(ChronoField.YEAR), 2008);
+        assertEquals(test.get(ChronoField.MONTH_OF_YEAR), 6);
+        assertEquals(test.get(ChronoField.DAY_OF_MONTH), 30);
+        assertEquals(test.get(ChronoField.DAY_OF_WEEK), 1);
+        assertEquals(test.get(ChronoField.DAY_OF_YEAR), 182);
+
+        assertEquals(test.get(ChronoField.HOUR_OF_DAY), 12);
+        assertEquals(test.get(ChronoField.MINUTE_OF_HOUR), 30);
+        assertEquals(test.get(ChronoField.SECOND_OF_MINUTE), 40);
+        assertEquals(test.get(ChronoField.NANO_OF_SECOND), 987654321);
+        assertEquals(test.get(ChronoField.HOUR_OF_AMPM), 0);
+        assertEquals(test.get(ChronoField.AMPM_OF_DAY), 1);
+
+        assertEquals(test.get(ChronoField.OFFSET_SECONDS), 3600);
+    }
+
+    @Test
+    public void test_getLong_TemporalField() {
+        OffsetDateTime test = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(12, 30, 40, 987654321), OFFSET_PONE);
+        assertEquals(test.getLong(ChronoField.YEAR), 2008);
+        assertEquals(test.getLong(ChronoField.MONTH_OF_YEAR), 6);
+        assertEquals(test.getLong(ChronoField.DAY_OF_MONTH), 30);
+        assertEquals(test.getLong(ChronoField.DAY_OF_WEEK), 1);
+        assertEquals(test.getLong(ChronoField.DAY_OF_YEAR), 182);
+
+        assertEquals(test.getLong(ChronoField.HOUR_OF_DAY), 12);
+        assertEquals(test.getLong(ChronoField.MINUTE_OF_HOUR), 30);
+        assertEquals(test.getLong(ChronoField.SECOND_OF_MINUTE), 40);
+        assertEquals(test.getLong(ChronoField.NANO_OF_SECOND), 987654321);
+        assertEquals(test.getLong(ChronoField.HOUR_OF_AMPM), 0);
+        assertEquals(test.getLong(ChronoField.AMPM_OF_DAY), 1);
+
+        assertEquals(test.getLong(ChronoField.INSTANT_SECONDS), test.toEpochSecond());
+        assertEquals(test.getLong(ChronoField.OFFSET_SECONDS), 3600);
+    }
+
+    //-----------------------------------------------------------------------
+    // query(TemporalQuery)
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_query_chrono() {
+        assertEquals(TEST_2008_6_30_11_30_59_000000500.query(Queries.chrono()), ISOChrono.INSTANCE);
+        assertEquals(Queries.chrono().queryFrom(TEST_2008_6_30_11_30_59_000000500), ISOChrono.INSTANCE);
+    }
+
+    @Test
+    public void test_query_zoneId() {
+        assertEquals(TEST_2008_6_30_11_30_59_000000500.query(Queries.zoneId()), null);
+        assertEquals(Queries.zoneId().queryFrom(TEST_2008_6_30_11_30_59_000000500), null);
+    }
+
+    @Test
+    public void test_query_precision() {
+        assertEquals(TEST_2008_6_30_11_30_59_000000500.query(Queries.precision()), NANOS);
+        assertEquals(Queries.precision().queryFrom(TEST_2008_6_30_11_30_59_000000500), NANOS);
+    }
+
+    @Test
+    public void test_query_offset() {
+        assertEquals(TEST_2008_6_30_11_30_59_000000500.query(Queries.offset()), OFFSET_PONE);
+        assertEquals(Queries.offset().queryFrom(TEST_2008_6_30_11_30_59_000000500), OFFSET_PONE);
+    }
+
+    @Test
+    public void test_query_zone() {
+        assertEquals(TEST_2008_6_30_11_30_59_000000500.query(Queries.zone()), OFFSET_PONE);
+        assertEquals(Queries.zone().queryFrom(TEST_2008_6_30_11_30_59_000000500), OFFSET_PONE);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_query_null() {
+        TEST_2008_6_30_11_30_59_000000500.query(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // with(WithAdjuster)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_with_adjustment() {
+        final OffsetDateTime sample = OffsetDateTime.of(LocalDate.of(2012, 3, 4), LocalTime.of(23, 5), OFFSET_PONE);
+        TemporalAdjuster adjuster = new TemporalAdjuster() {
+            @Override
+            public Temporal adjustInto(Temporal dateTime) {
+                return sample;
+            }
+        };
+        assertEquals(TEST_2008_6_30_11_30_59_000000500.with(adjuster), sample);
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_adjustment_LocalDate() {
+        OffsetDateTime test = TEST_2008_6_30_11_30_59_000000500.with(LocalDate.of(2012, 9, 3));
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2012, 9, 3), LocalTime.of(11, 30, 59, 500), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_adjustment_LocalTime() {
+        OffsetDateTime test = TEST_2008_6_30_11_30_59_000000500.with(LocalTime.of(19, 15));
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(19, 15), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_adjustment_LocalDateTime() {
+        OffsetDateTime test = TEST_2008_6_30_11_30_59_000000500.with(LocalDateTime.of(LocalDate.of(2012, 9, 3), LocalTime.of(19, 15)));
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2012, 9, 3), LocalTime.of(19, 15), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_adjustment_OffsetDate() {
+        OffsetDateTime test = TEST_2008_6_30_11_30_59_000000500.with(OffsetDate.of(LocalDate.of(2012, 9, 3), OFFSET_PTWO));
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2012, 9, 3), LocalTime.of(11, 30, 59, 500), OFFSET_PTWO));
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_adjustment_OffsetTime() {
+        OffsetDateTime test = TEST_2008_6_30_11_30_59_000000500.with(OffsetTime.of(LocalTime.of(19, 15), OFFSET_PTWO));
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(19, 15), OFFSET_PTWO));
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_adjustment_OffsetDateTime() {
+        OffsetDateTime test = TEST_2008_6_30_11_30_59_000000500.with(OffsetDateTime.of(LocalDate.of(2012, 9, 3), LocalTime.of(19, 15), OFFSET_PTWO));
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2012, 9, 3), LocalTime.of(19, 15), OFFSET_PTWO));
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_adjustment_Month() {
+        OffsetDateTime test = TEST_2008_6_30_11_30_59_000000500.with(DECEMBER);
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 12, 30),LocalTime.of(11, 30, 59, 500), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_adjustment_ZoneOffset() {
+        OffsetDateTime test = TEST_2008_6_30_11_30_59_000000500.with(OFFSET_PTWO);
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59, 500), OFFSET_PTWO));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_with_adjustment_null() {
+        TEST_2008_6_30_11_30_59_000000500.with((TemporalAdjuster) null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_withOffsetSameLocal_null() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        base.withOffsetSameLocal(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // withOffsetSameInstant()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withOffsetSameInstant() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.withOffsetSameInstant(OFFSET_PTWO);
+        OffsetDateTime expected = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(12, 30, 59), OFFSET_PTWO);
+        assertEquals(test, expected);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_withOffsetSameInstant_null() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        base.withOffsetSameInstant(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // withYear()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withYear_normal() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.withYear(2007);
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2007, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE));
+    }
+
+    //-----------------------------------------------------------------------
+    // withMonth()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withMonth_normal() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.withMonth(1);
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 1, 30), LocalTime.of(11, 30, 59), OFFSET_PONE));
+    }
+
+    //-----------------------------------------------------------------------
+    // withDayOfMonth()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withDayOfMonth_normal() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.withDayOfMonth(15);
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 15), LocalTime.of(11, 30, 59), OFFSET_PONE));
+    }
+
+    //-----------------------------------------------------------------------
+    // withDayOfYear(int)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withDayOfYear_normal() {
+        OffsetDateTime t = TEST_2008_6_30_11_30_59_000000500.withDayOfYear(33);
+        assertEquals(t, OffsetDateTime.of(LocalDate.of(2008, 2, 2), LocalTime.of(11, 30, 59, 500), OFFSET_PONE));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withDayOfYear_illegal() {
+        TEST_2008_6_30_11_30_59_000000500.withDayOfYear(367);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withDayOfYear_invalid() {
+        OffsetDateTime.of(LocalDate.of(2007, 2, 2), LocalTime.of(11, 30), OFFSET_PONE).withDayOfYear(366);
+    }
+
+    //-----------------------------------------------------------------------
+    // withHour()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withHour_normal() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.withHour(15);
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(15, 30, 59), OFFSET_PONE));
+    }
+
+    //-----------------------------------------------------------------------
+    // withMinute()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withMinute_normal() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.withMinute(15);
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 15, 59), OFFSET_PONE));
+    }
+
+    //-----------------------------------------------------------------------
+    // withSecond()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withSecond_normal() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.withSecond(15);
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 15), OFFSET_PONE));
+    }
+
+    //-----------------------------------------------------------------------
+    // withNano()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withNanoOfSecond_normal() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59, 1), OFFSET_PONE);
+        OffsetDateTime test = base.withNano(15);
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59, 15), OFFSET_PONE));
+    }
+
+    //-----------------------------------------------------------------------
+    // truncatedTo(TemporalUnit)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_truncatedTo_normal() {
+        assertEquals(TEST_2008_6_30_11_30_59_000000500.truncatedTo(NANOS), TEST_2008_6_30_11_30_59_000000500);
+        assertEquals(TEST_2008_6_30_11_30_59_000000500.truncatedTo(SECONDS), TEST_2008_6_30_11_30_59_000000500.withNano(0));
+        assertEquals(TEST_2008_6_30_11_30_59_000000500.truncatedTo(DAYS), TEST_2008_6_30_11_30_59_000000500.with(LocalTime.MIDNIGHT));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_truncatedTo_null() {
+        TEST_2008_6_30_11_30_59_000000500.truncatedTo(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // plus(Period)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plus_Period() {
+        MockSimplePeriod period = MockSimplePeriod.of(7, ChronoUnit.MONTHS);
+        OffsetDateTime t = TEST_2008_6_30_11_30_59_000000500.plus(period);
+        assertEquals(t, OffsetDateTime.of(LocalDate.of(2009, 1, 30), LocalTime.of(11, 30, 59, 500), OFFSET_PONE));
+    }
+
+    //-----------------------------------------------------------------------
+    // plus(Duration)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plus_Duration() {
+        Duration dur = Duration.ofSeconds(62, 3);
+        OffsetDateTime t = TEST_2008_6_30_11_30_59_000000500.plus(dur);
+        assertEquals(t, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 32, 1, 503), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plus_Duration_zero() {
+        OffsetDateTime t = TEST_2008_6_30_11_30_59_000000500.plus(Duration.ZERO);
+        assertEquals(t, TEST_2008_6_30_11_30_59_000000500);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_plus_Duration_null() {
+        TEST_2008_6_30_11_30_59_000000500.plus((Duration) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusYears()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusYears() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.plusYears(1);
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2009, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE));
+    }
+
+    //-----------------------------------------------------------------------
+    // plusMonths()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusMonths() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.plusMonths(1);
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 7, 30), LocalTime.of(11, 30, 59), OFFSET_PONE));
+    }
+
+    //-----------------------------------------------------------------------
+    // plusWeeks()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusWeeks() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.plusWeeks(1);
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 7, 7), LocalTime.of(11, 30, 59), OFFSET_PONE));
+    }
+
+    //-----------------------------------------------------------------------
+    // plusDays()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusDays() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.plusDays(1);
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 7, 1), LocalTime.of(11, 30, 59), OFFSET_PONE));
+    }
+
+    //-----------------------------------------------------------------------
+    // plusHours()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusHours() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.plusHours(13);
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 7, 1), LocalTime.of(0, 30, 59), OFFSET_PONE));
+    }
+
+    //-----------------------------------------------------------------------
+    // plusMinutes()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusMinutes() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.plusMinutes(30);
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(12, 0, 59), OFFSET_PONE));
+    }
+
+    //-----------------------------------------------------------------------
+    // plusSeconds()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusSeconds() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.plusSeconds(1);
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 31, 0), OFFSET_PONE));
+    }
+
+    //-----------------------------------------------------------------------
+    // plusNanos()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusNanos() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59, 0), OFFSET_PONE);
+        OffsetDateTime test = base.plusNanos(1);
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59, 1), OFFSET_PONE));
+    }
+
+    //-----------------------------------------------------------------------
+    // minus(Period)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minus_Period() {
+        MockSimplePeriod period = MockSimplePeriod.of(7, ChronoUnit.MONTHS);
+        OffsetDateTime t = TEST_2008_6_30_11_30_59_000000500.minus(period);
+        assertEquals(t, OffsetDateTime.of(LocalDate.of(2007, 11, 30), LocalTime.of(11, 30, 59, 500), OFFSET_PONE));
+    }
+
+    //-----------------------------------------------------------------------
+    // minus(Duration)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minus_Duration() {
+        Duration dur = Duration.ofSeconds(62, 3);
+        OffsetDateTime t = TEST_2008_6_30_11_30_59_000000500.minus(dur);
+        assertEquals(t, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 29, 57, 497), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minus_Duration_zero() {
+        OffsetDateTime t = TEST_2008_6_30_11_30_59_000000500.minus(Duration.ZERO);
+        assertEquals(t, TEST_2008_6_30_11_30_59_000000500);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_minus_Duration_null() {
+        TEST_2008_6_30_11_30_59_000000500.minus((Duration) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusYears()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusYears() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.minusYears(1);
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2007, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE));
+    }
+
+    //-----------------------------------------------------------------------
+    // minusMonths()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusMonths() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.minusMonths(1);
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 5, 30), LocalTime.of(11, 30, 59), OFFSET_PONE));
+    }
+
+    //-----------------------------------------------------------------------
+    // minusWeeks()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusWeeks() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.minusWeeks(1);
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 23), LocalTime.of(11, 30, 59), OFFSET_PONE));
+    }
+
+    //-----------------------------------------------------------------------
+    // minusDays()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusDays() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.minusDays(1);
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 29), LocalTime.of(11, 30, 59), OFFSET_PONE));
+    }
+
+    //-----------------------------------------------------------------------
+    // minusHours()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusHours() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.minusHours(13);
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 29), LocalTime.of(22, 30, 59), OFFSET_PONE));
+    }
+
+    //-----------------------------------------------------------------------
+    // minusMinutes()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusMinutes() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.minusMinutes(30);
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 0, 59), OFFSET_PONE));
+    }
+
+    //-----------------------------------------------------------------------
+    // minusSeconds()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusSeconds() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.minusSeconds(1);
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 58), OFFSET_PONE));
+    }
+
+    //-----------------------------------------------------------------------
+    // minusNanos()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusNanos() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59, 0), OFFSET_PONE);
+        OffsetDateTime test = base.minusNanos(1);
+        assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 58, 999999999), OFFSET_PONE));
+    }
+
+    //-----------------------------------------------------------------------
+    // atZoneSameInstant()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_atZone() {
+        OffsetDateTime t = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30), OFFSET_MTWO);
+        assertEquals(t.atZoneSameInstant(ZONE_PARIS),
+                ZonedDateTime.of(LocalDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(15, 30)), ZONE_PARIS));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_atZone_nullTimeZone() {
+        OffsetDateTime t = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30), OFFSET_PTWO);
+        t.atZoneSameInstant((ZoneId) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // atZoneSimilarLocal()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_atZoneSimilarLocal() {
+        OffsetDateTime t = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30), OFFSET_MTWO);
+        assertEquals(t.atZoneSimilarLocal(ZONE_PARIS),
+                ZonedDateTime.of(LocalDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30)), ZONE_PARIS));
+    }
+
+    @Test(groups={"tck"})
+    public void test_atZoneSimilarLocal_dstGap() {
+        OffsetDateTime t = OffsetDateTime.of(LocalDate.of(2007, 4, 1), LocalTime.of(0, 0), OFFSET_MTWO);
+        assertEquals(t.atZoneSimilarLocal(ZONE_GAZA),
+                ZonedDateTime.of(LocalDateTime.of(LocalDate.of(2007, 4, 1), LocalTime.of(1, 0)), ZONE_GAZA));
+    }
+
+    @Test(groups={"tck"})
+    public void test_atZone_dstOverlapSummer() {
+        OffsetDateTime t = OffsetDateTime.of(LocalDate.of(2007, 10, 28), LocalTime.of(2, 30), OFFSET_PTWO);
+        assertEquals(t.atZoneSimilarLocal(ZONE_PARIS).getDateTime(), t.getDateTime());
+        assertEquals(t.atZoneSimilarLocal(ZONE_PARIS).getOffset(), OFFSET_PTWO);
+        assertEquals(t.atZoneSimilarLocal(ZONE_PARIS).getZone(), ZONE_PARIS);
+    }
+
+    @Test(groups={"tck"})
+    public void test_atZone_dstOverlapWinter() {
+        OffsetDateTime t = OffsetDateTime.of(LocalDate.of(2007, 10, 28), LocalTime.of(2, 30), OFFSET_PONE);
+        assertEquals(t.atZoneSimilarLocal(ZONE_PARIS).getDateTime(), t.getDateTime());
+        assertEquals(t.atZoneSimilarLocal(ZONE_PARIS).getOffset(), OFFSET_PONE);
+        assertEquals(t.atZoneSimilarLocal(ZONE_PARIS).getZone(), ZONE_PARIS);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_atZoneSimilarLocal_nullTimeZone() {
+        OffsetDateTime t = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30), OFFSET_PTWO);
+        t.atZoneSimilarLocal((ZoneId) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // toEpochSecond()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_toEpochSecond_afterEpoch() {
+        for (int i = 0; i < 100000; i++) {
+            OffsetDateTime a = OffsetDateTime.of(LocalDate.of(1970, 1, 1), LocalTime.of(0, 0), ZoneOffset.UTC).plusSeconds(i);
+            assertEquals(a.toEpochSecond(), i);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_toEpochSecond_beforeEpoch() {
+        for (int i = 0; i < 100000; i++) {
+            OffsetDateTime a = OffsetDateTime.of(LocalDate.of(1970, 1, 1), LocalTime.of(0, 0), ZoneOffset.UTC).minusSeconds(i);
+            assertEquals(a.toEpochSecond(), -i);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // compareTo()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_compareTo_timeMins() {
+        OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 29, 3), OFFSET_PONE);
+        OffsetDateTime b = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 2), OFFSET_PONE);  // a is before b due to time
+        assertEquals(a.compareTo(b) < 0, true);
+        assertEquals(b.compareTo(a) > 0, true);
+        assertEquals(a.compareTo(a) == 0, true);
+        assertEquals(b.compareTo(b) == 0, true);
+        assertEquals(a.toInstant().compareTo(b.toInstant()) < 0, true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_compareTo_timeSecs() {
+        OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 29, 2), OFFSET_PONE);
+        OffsetDateTime b = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 29, 3), OFFSET_PONE);  // a is before b due to time
+        assertEquals(a.compareTo(b) < 0, true);
+        assertEquals(b.compareTo(a) > 0, true);
+        assertEquals(a.compareTo(a) == 0, true);
+        assertEquals(b.compareTo(b) == 0, true);
+        assertEquals(a.toInstant().compareTo(b.toInstant()) < 0, true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_compareTo_timeNanos() {
+        OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 29, 40, 4), OFFSET_PONE);
+        OffsetDateTime b = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 29, 40, 5), OFFSET_PONE);  // a is before b due to time
+        assertEquals(a.compareTo(b) < 0, true);
+        assertEquals(b.compareTo(a) > 0, true);
+        assertEquals(a.compareTo(a) == 0, true);
+        assertEquals(b.compareTo(b) == 0, true);
+        assertEquals(a.toInstant().compareTo(b.toInstant()) < 0, true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_compareTo_offset() {
+        OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30), OFFSET_PTWO);
+        OffsetDateTime b = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30), OFFSET_PONE);  // a is before b due to offset
+        assertEquals(a.compareTo(b) < 0, true);
+        assertEquals(b.compareTo(a) > 0, true);
+        assertEquals(a.compareTo(a) == 0, true);
+        assertEquals(b.compareTo(b) == 0, true);
+        assertEquals(a.toInstant().compareTo(b.toInstant()) < 0, true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_compareTo_offsetNanos() {
+        OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 40, 6), OFFSET_PTWO);
+        OffsetDateTime b = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 40, 5), OFFSET_PONE);  // a is before b due to offset
+        assertEquals(a.compareTo(b) < 0, true);
+        assertEquals(b.compareTo(a) > 0, true);
+        assertEquals(a.compareTo(a) == 0, true);
+        assertEquals(b.compareTo(b) == 0, true);
+        assertEquals(a.toInstant().compareTo(b.toInstant()) < 0, true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_compareTo_both() {
+        OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 50), OFFSET_PTWO);
+        OffsetDateTime b = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 20), OFFSET_PONE);  // a is before b on instant scale
+        assertEquals(a.compareTo(b) < 0, true);
+        assertEquals(b.compareTo(a) > 0, true);
+        assertEquals(a.compareTo(a) == 0, true);
+        assertEquals(b.compareTo(b) == 0, true);
+        assertEquals(a.toInstant().compareTo(b.toInstant()) < 0, true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_compareTo_bothNanos() {
+        OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 20, 40, 4), OFFSET_PTWO);
+        OffsetDateTime b = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(10, 20, 40, 5), OFFSET_PONE);  // a is before b on instant scale
+        assertEquals(a.compareTo(b) < 0, true);
+        assertEquals(b.compareTo(a) > 0, true);
+        assertEquals(a.compareTo(a) == 0, true);
+        assertEquals(b.compareTo(b) == 0, true);
+        assertEquals(a.toInstant().compareTo(b.toInstant()) < 0, true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_compareTo_hourDifference() {
+        OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(10, 0), OFFSET_PONE);
+        OffsetDateTime b = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 0), OFFSET_PTWO);  // a is before b despite being same time-line time
+        assertEquals(a.compareTo(b) < 0, true);
+        assertEquals(b.compareTo(a) > 0, true);
+        assertEquals(a.compareTo(a) == 0, true);
+        assertEquals(b.compareTo(b) == 0, true);
+        assertEquals(a.toInstant().compareTo(b.toInstant()) == 0, true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_compareTo_max() {
+        OffsetDateTime a = OffsetDateTime.of(LocalDate.of(Year.MAX_VALUE, 12, 31), LocalTime.of(23, 59), OFFSET_MONE);
+        OffsetDateTime b = OffsetDateTime.of(LocalDate.of(Year.MAX_VALUE, 12, 31), LocalTime.of(23, 59), OFFSET_MTWO);  // a is before b due to offset
+        assertEquals(a.compareTo(b) < 0, true);
+        assertEquals(b.compareTo(a) > 0, true);
+        assertEquals(a.compareTo(a) == 0, true);
+        assertEquals(b.compareTo(b) == 0, true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_compareTo_min() {
+        OffsetDateTime a = OffsetDateTime.of(LocalDate.of(Year.MIN_VALUE, 1, 1), LocalTime.of(0, 0), OFFSET_PTWO);
+        OffsetDateTime b = OffsetDateTime.of(LocalDate.of(Year.MIN_VALUE, 1, 1), LocalTime.of(0, 0), OFFSET_PONE);  // a is before b due to offset
+        assertEquals(a.compareTo(b) < 0, true);
+        assertEquals(b.compareTo(a) > 0, true);
+        assertEquals(a.compareTo(a) == 0, true);
+        assertEquals(b.compareTo(b) == 0, true);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_compareTo_null() {
+        OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        a.compareTo(null);
+    }
+
+    @Test(expectedExceptions=ClassCastException.class, groups={"tck"})
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public void compareToNonOffsetDateTime() {
+       Comparable c = TEST_2008_6_30_11_30_59_000000500;
+       c.compareTo(new Object());
+    }
+
+    //-----------------------------------------------------------------------
+    // isAfter() / isBefore() / isEqual()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_isBeforeIsAfterIsEqual1() {
+        OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 58, 3), OFFSET_PONE);
+        OffsetDateTime b = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59, 2), OFFSET_PONE);  // a is before b due to time
+        assertEquals(a.isBefore(b), true);
+        assertEquals(a.isEqual(b), false);
+        assertEquals(a.isAfter(b), false);
+
+        assertEquals(b.isBefore(a), false);
+        assertEquals(b.isEqual(a), false);
+        assertEquals(b.isAfter(a), true);
+
+        assertEquals(a.isBefore(a), false);
+        assertEquals(b.isBefore(b), false);
+
+        assertEquals(a.isEqual(a), true);
+        assertEquals(b.isEqual(b), true);
+
+        assertEquals(a.isAfter(a), false);
+        assertEquals(b.isAfter(b), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_isBeforeIsAfterIsEqual2() {
+        OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59, 2), OFFSET_PONE);
+        OffsetDateTime b = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59, 3), OFFSET_PONE);  // a is before b due to time
+        assertEquals(a.isBefore(b), true);
+        assertEquals(a.isEqual(b), false);
+        assertEquals(a.isAfter(b), false);
+
+        assertEquals(b.isBefore(a), false);
+        assertEquals(b.isEqual(a), false);
+        assertEquals(b.isAfter(a), true);
+
+        assertEquals(a.isBefore(a), false);
+        assertEquals(b.isBefore(b), false);
+
+        assertEquals(a.isEqual(a), true);
+        assertEquals(b.isEqual(b), true);
+
+        assertEquals(a.isAfter(a), false);
+        assertEquals(b.isAfter(b), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_isBeforeIsAfterIsEqual_instantComparison() {
+        OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(10, 0), OFFSET_PONE);
+        OffsetDateTime b = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 0), OFFSET_PTWO);  // a is same instant as b
+        assertEquals(a.isBefore(b), false);
+        assertEquals(a.isEqual(b), true);
+        assertEquals(a.isAfter(b), false);
+
+        assertEquals(b.isBefore(a), false);
+        assertEquals(b.isEqual(a), true);
+        assertEquals(b.isAfter(a), false);
+
+        assertEquals(a.isBefore(a), false);
+        assertEquals(b.isBefore(b), false);
+
+        assertEquals(a.isEqual(a), true);
+        assertEquals(b.isEqual(b), true);
+
+        assertEquals(a.isAfter(a), false);
+        assertEquals(b.isAfter(b), false);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_isBefore_null() {
+        OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        a.isBefore(null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_isEqual_null() {
+        OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        a.isEqual(null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_isAfter_null() {
+        OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        a.isAfter(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // equals() / hashCode()
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_equals_true(int y, int o, int d, int h, int m, int s, int n, ZoneOffset ignored) {
+        OffsetDateTime a = OffsetDateTime.of(LocalDate.of(y, o, d), LocalTime.of(h, m, s, n), OFFSET_PONE);
+        OffsetDateTime b = OffsetDateTime.of(LocalDate.of(y, o, d), LocalTime.of(h, m, s, n), OFFSET_PONE);
+        assertEquals(a.equals(b), true);
+        assertEquals(a.hashCode() == b.hashCode(), true);
+    }
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_equals_false_year_differs(int y, int o, int d, int h, int m, int s, int n, ZoneOffset ignored) {
+        OffsetDateTime a = OffsetDateTime.of(LocalDate.of(y, o, d), LocalTime.of(h, m, s, n), OFFSET_PONE);
+        OffsetDateTime b = OffsetDateTime.of(LocalDate.of(y + 1, o, d), LocalTime.of(h, m, s, n), OFFSET_PONE);
+        assertEquals(a.equals(b), false);
+    }
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_equals_false_hour_differs(int y, int o, int d, int h, int m, int s, int n, ZoneOffset ignored) {
+        h = (h == 23 ? 22 : h);
+        OffsetDateTime a = OffsetDateTime.of(LocalDate.of(y, o, d), LocalTime.of(h, m, s, n), OFFSET_PONE);
+        OffsetDateTime b = OffsetDateTime.of(LocalDate.of(y, o, d), LocalTime.of(h + 1, m, s, n), OFFSET_PONE);
+        assertEquals(a.equals(b), false);
+    }
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_equals_false_minute_differs(int y, int o, int d, int h, int m, int s, int n, ZoneOffset ignored) {
+        m = (m == 59 ? 58 : m);
+        OffsetDateTime a = OffsetDateTime.of(LocalDate.of(y, o, d), LocalTime.of(h, m, s, n), OFFSET_PONE);
+        OffsetDateTime b = OffsetDateTime.of(LocalDate.of(y, o, d), LocalTime.of(h, m + 1, s, n), OFFSET_PONE);
+        assertEquals(a.equals(b), false);
+    }
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_equals_false_second_differs(int y, int o, int d, int h, int m, int s, int n, ZoneOffset ignored) {
+        s = (s == 59 ? 58 : s);
+        OffsetDateTime a = OffsetDateTime.of(LocalDate.of(y, o, d), LocalTime.of(h, m, s, n), OFFSET_PONE);
+        OffsetDateTime b = OffsetDateTime.of(LocalDate.of(y, o, d), LocalTime.of(h, m, s + 1, n), OFFSET_PONE);
+        assertEquals(a.equals(b), false);
+    }
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_equals_false_nano_differs(int y, int o, int d, int h, int m, int s, int n, ZoneOffset ignored) {
+        n = (n == 999999999 ? 999999998 : n);
+        OffsetDateTime a = OffsetDateTime.of(LocalDate.of(y, o, d), LocalTime.of(h, m, s, n), OFFSET_PONE);
+        OffsetDateTime b = OffsetDateTime.of(LocalDate.of(y, o, d), LocalTime.of(h, m, s, n + 1), OFFSET_PONE);
+        assertEquals(a.equals(b), false);
+    }
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_equals_false_offset_differs(int y, int o, int d, int h, int m, int s, int n, ZoneOffset ignored) {
+        OffsetDateTime a = OffsetDateTime.of(LocalDate.of(y, o, d), LocalTime.of(h, m, s, n), OFFSET_PONE);
+        OffsetDateTime b = OffsetDateTime.of(LocalDate.of(y, o, d), LocalTime.of(h, m, s, n), OFFSET_PTWO);
+        assertEquals(a.equals(b), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_itself_true() {
+        assertEquals(TEST_2008_6_30_11_30_59_000000500.equals(TEST_2008_6_30_11_30_59_000000500), true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_string_false() {
+        assertEquals(TEST_2008_6_30_11_30_59_000000500.equals("2007-07-15"), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_null_false() {
+        assertEquals(TEST_2008_6_30_11_30_59_000000500.equals(null), false);
+    }
+
+    //-----------------------------------------------------------------------
+    // toString()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sampleToString")
+    Object[][] provider_sampleToString() {
+        return new Object[][] {
+            {2008, 6, 30, 11, 30, 59, 0, "Z", "2008-06-30T11:30:59Z"},
+            {2008, 6, 30, 11, 30, 59, 0, "+01:00", "2008-06-30T11:30:59+01:00"},
+            {2008, 6, 30, 11, 30, 59, 999000000, "Z", "2008-06-30T11:30:59.999Z"},
+            {2008, 6, 30, 11, 30, 59, 999000000, "+01:00", "2008-06-30T11:30:59.999+01:00"},
+            {2008, 6, 30, 11, 30, 59, 999000, "Z", "2008-06-30T11:30:59.000999Z"},
+            {2008, 6, 30, 11, 30, 59, 999000, "+01:00", "2008-06-30T11:30:59.000999+01:00"},
+            {2008, 6, 30, 11, 30, 59, 999, "Z", "2008-06-30T11:30:59.000000999Z"},
+            {2008, 6, 30, 11, 30, 59, 999, "+01:00", "2008-06-30T11:30:59.000000999+01:00"},
+        };
+    }
+
+    @Test(dataProvider="sampleToString", groups={"tck"})
+    public void test_toString(int y, int o, int d, int h, int m, int s, int n, String offsetId, String expected) {
+        OffsetDateTime t = OffsetDateTime.of(LocalDate.of(y, o, d), LocalTime.of(h, m, s, n), ZoneOffset.of(offsetId));
+        String str = t.toString();
+        assertEquals(str, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // toString(DateTimeFormatter)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_toString_formatter() {
+        DateTimeFormatter f = DateTimeFormatters.pattern("y M d H m s");
+        String t = OffsetDateTime.of(LocalDate.of(2010, 12, 3), LocalTime.of(11, 30), OFFSET_PONE).toString(f);
+        assertEquals(t, "2010 12 3 11 30 0");
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_toString_formatter_null() {
+        OffsetDateTime.of(LocalDate.of(2010, 12, 3), LocalTime.of(11, 30), OFFSET_PONE).toString(null);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/temporal/TCKOffsetTime.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,1325 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.temporal;
+
+import static java.time.temporal.ChronoField.AMPM_OF_DAY;
+import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_AMPM;
+import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_DAY;
+import static java.time.temporal.ChronoField.HOUR_OF_AMPM;
+import static java.time.temporal.ChronoField.HOUR_OF_DAY;
+import static java.time.temporal.ChronoField.MICRO_OF_DAY;
+import static java.time.temporal.ChronoField.MICRO_OF_SECOND;
+import static java.time.temporal.ChronoField.MILLI_OF_DAY;
+import static java.time.temporal.ChronoField.MILLI_OF_SECOND;
+import static java.time.temporal.ChronoField.MINUTE_OF_DAY;
+import static java.time.temporal.ChronoField.MINUTE_OF_HOUR;
+import static java.time.temporal.ChronoField.NANO_OF_DAY;
+import static java.time.temporal.ChronoField.NANO_OF_SECOND;
+import static java.time.temporal.ChronoField.OFFSET_SECONDS;
+import static java.time.temporal.ChronoField.SECOND_OF_DAY;
+import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.NANOS;
+import static java.time.temporal.ChronoUnit.SECONDS;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.Period;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatters;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.JulianFields;
+import java.time.temporal.OffsetDate;
+import java.time.temporal.OffsetDateTime;
+import java.time.temporal.OffsetTime;
+import java.time.temporal.Queries;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdder;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.TemporalSubtractor;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import tck.java.time.AbstractDateTimeTest;
+import test.java.time.MockSimplePeriod;
+
+/**
+ * Test OffsetTime.
+ */
+@Test
+public class TCKOffsetTime extends AbstractDateTimeTest {
+
+    private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1);
+    private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2);
+    private static final LocalDate DATE = LocalDate.of(2008, 12, 3);
+    private OffsetTime TEST_11_30_59_500_PONE;
+
+    @BeforeMethod(groups={"tck","implementation"})
+    public void setUp() {
+        TEST_11_30_59_500_PONE = OffsetTime.of(LocalTime.of(11, 30, 59, 500), OFFSET_PONE);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    protected List<TemporalAccessor> samples() {
+        TemporalAccessor[] array = {TEST_11_30_59_500_PONE, OffsetTime.MIN, OffsetTime.MAX};
+        return Arrays.asList(array);
+    }
+
+    @Override
+    protected List<TemporalField> validFields() {
+        TemporalField[] array = {
+            NANO_OF_SECOND,
+            NANO_OF_DAY,
+            MICRO_OF_SECOND,
+            MICRO_OF_DAY,
+            MILLI_OF_SECOND,
+            MILLI_OF_DAY,
+            SECOND_OF_MINUTE,
+            SECOND_OF_DAY,
+            MINUTE_OF_HOUR,
+            MINUTE_OF_DAY,
+            CLOCK_HOUR_OF_AMPM,
+            HOUR_OF_AMPM,
+            CLOCK_HOUR_OF_DAY,
+            HOUR_OF_DAY,
+            AMPM_OF_DAY,
+            OFFSET_SECONDS,
+        };
+        return Arrays.asList(array);
+    }
+
+    @Override
+    protected List<TemporalField> invalidFields() {
+        List<TemporalField> list = new ArrayList<>(Arrays.<TemporalField>asList(ChronoField.values()));
+        list.removeAll(validFields());
+        list.add(JulianFields.JULIAN_DAY);
+        list.add(JulianFields.MODIFIED_JULIAN_DAY);
+        list.add(JulianFields.RATA_DIE);
+        return list;
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_serialization() throws Exception {
+        assertSerializable(TEST_11_30_59_500_PONE);
+        assertSerializable(OffsetTime.MIN);
+        assertSerializable(OffsetTime.MAX);
+    }
+
+    @Test
+    public void test_serialization_format() throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try (DataOutputStream dos = new DataOutputStream(baos) ) {
+            dos.writeByte(2);
+        }
+        byte[] bytes = baos.toByteArray();
+        ByteArrayOutputStream baosTime = new ByteArrayOutputStream();
+        try (DataOutputStream dos = new DataOutputStream(baosTime) ) {
+            dos.writeByte(4);
+            dos.writeByte(22);
+            dos.writeByte(17);
+            dos.writeByte(59);
+            dos.writeInt(464_000_000);
+        }
+        byte[] bytesTime = baosTime.toByteArray();
+        ByteArrayOutputStream baosOffset = new ByteArrayOutputStream();
+        try (DataOutputStream dos = new DataOutputStream(baosOffset) ) {
+            dos.writeByte(8);
+            dos.writeByte(4);  // quarter hours stored: 3600 / 900
+        }
+        byte[] bytesOffset = baosOffset.toByteArray();
+        assertSerializedBySer(OffsetTime.of(LocalTime.of(22, 17, 59, 464_000_000), ZoneOffset.ofHours(1)), bytes,
+                bytesTime, bytesOffset);
+    }
+
+    //-----------------------------------------------------------------------
+    // constants
+    //-----------------------------------------------------------------------
+    @Test
+    public void constant_MIN() {
+        check(OffsetTime.MIN, 0, 0, 0, 0, ZoneOffset.MAX);
+    }
+
+    @Test
+    public void constant_MAX() {
+        check(OffsetTime.MAX, 23, 59, 59, 999999999, ZoneOffset.MIN);
+    }
+
+    //-----------------------------------------------------------------------
+    // now()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void now() {
+        ZonedDateTime nowDT = ZonedDateTime.now();
+
+        OffsetTime expected = OffsetTime.now(Clock.systemDefaultZone());
+        OffsetTime test = OffsetTime.now();
+        long diff = Math.abs(test.getTime().toNanoOfDay() - expected.getTime().toNanoOfDay());
+        assertTrue(diff < 100000000);  // less than 0.1 secs
+        assertEquals(test.getOffset(), nowDT.getOffset());
+    }
+
+    //-----------------------------------------------------------------------
+    // now(Clock)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void now_Clock_allSecsInDay() {
+        for (int i = 0; i < (2 * 24 * 60 * 60); i++) {
+            Instant instant = Instant.ofEpochSecond(i, 8);
+            Clock clock = Clock.fixed(instant, ZoneOffset.UTC);
+            OffsetTime test = OffsetTime.now(clock);
+            assertEquals(test.getHour(), (i / (60 * 60)) % 24);
+            assertEquals(test.getMinute(), (i / 60) % 60);
+            assertEquals(test.getSecond(), i % 60);
+            assertEquals(test.getNano(), 8);
+            assertEquals(test.getOffset(), ZoneOffset.UTC);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void now_Clock_beforeEpoch() {
+        for (int i =-1; i >= -(24 * 60 * 60); i--) {
+            Instant instant = Instant.ofEpochSecond(i, 8);
+            Clock clock = Clock.fixed(instant, ZoneOffset.UTC);
+            OffsetTime test = OffsetTime.now(clock);
+            assertEquals(test.getHour(), ((i + 24 * 60 * 60) / (60 * 60)) % 24);
+            assertEquals(test.getMinute(), ((i + 24 * 60 * 60) / 60) % 60);
+            assertEquals(test.getSecond(), (i + 24 * 60 * 60) % 60);
+            assertEquals(test.getNano(), 8);
+            assertEquals(test.getOffset(), ZoneOffset.UTC);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void now_Clock_offsets() {
+        Instant base = LocalDateTime.of(1970, 1, 1, 12, 0).toInstant(ZoneOffset.UTC);
+        for (int i = -9; i < 15; i++) {
+            ZoneOffset offset = ZoneOffset.ofHours(i);
+            Clock clock = Clock.fixed(base, offset);
+            OffsetTime test = OffsetTime.now(clock);
+            assertEquals(test.getHour(), (12 + i) % 24);
+            assertEquals(test.getMinute(), 0);
+            assertEquals(test.getSecond(), 0);
+            assertEquals(test.getNano(), 0);
+            assertEquals(test.getOffset(), offset);
+        }
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void now_Clock_nullZoneId() {
+        OffsetTime.now((ZoneId) null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void now_Clock_nullClock() {
+        OffsetTime.now((Clock) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // factories
+    //-----------------------------------------------------------------------
+    private void check(OffsetTime test, int h, int m, int s, int n, ZoneOffset offset) {
+        assertEquals(test.getTime(), LocalTime.of(h, m, s, n));
+        assertEquals(test.getOffset(), offset);
+
+        assertEquals(test.getHour(), h);
+        assertEquals(test.getMinute(), m);
+        assertEquals(test.getSecond(), s);
+        assertEquals(test.getNano(), n);
+
+        assertEquals(test, test);
+        assertEquals(test.hashCode(), test.hashCode());
+        assertEquals(OffsetTime.of(LocalTime.of(h, m, s, n), offset), test);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_intsHM() {
+        OffsetTime test = OffsetTime.of(LocalTime.of(11, 30), OFFSET_PONE);
+        check(test, 11, 30, 0, 0, OFFSET_PONE);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_intsHMS() {
+        OffsetTime test = OffsetTime.of(LocalTime.of(11, 30, 10), OFFSET_PONE);
+        check(test, 11, 30, 10, 0, OFFSET_PONE);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_intsHMSN() {
+        OffsetTime test = OffsetTime.of(LocalTime.of(11, 30, 10, 500), OFFSET_PONE);
+        check(test, 11, 30, 10, 500, OFFSET_PONE);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_LocalTimeZoneOffset() {
+        LocalTime localTime = LocalTime.of(11, 30, 10, 500);
+        OffsetTime test = OffsetTime.of(localTime, OFFSET_PONE);
+        check(test, 11, 30, 10, 500, OFFSET_PONE);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_LocalTimeZoneOffset_nullTime() {
+        OffsetTime.of((LocalTime) null, OFFSET_PONE);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_LocalTimeZoneOffset_nullOffset() {
+        LocalTime localTime = LocalTime.of(11, 30, 10, 500);
+        OffsetTime.of(localTime, (ZoneOffset) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // ofInstant()
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_ofInstant_nullInstant() {
+        OffsetTime.ofInstant((Instant) null, ZoneOffset.UTC);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_ofInstant_nullOffset() {
+        Instant instant = Instant.ofEpochSecond(0L);
+        OffsetTime.ofInstant(instant, (ZoneOffset) null);
+    }
+
+    @Test(groups={"tck"})
+    public void factory_ofInstant_allSecsInDay() {
+        for (int i = 0; i < (2 * 24 * 60 * 60); i++) {
+            Instant instant = Instant.ofEpochSecond(i, 8);
+            OffsetTime test = OffsetTime.ofInstant(instant, ZoneOffset.UTC);
+            assertEquals(test.getHour(), (i / (60 * 60)) % 24);
+            assertEquals(test.getMinute(), (i / 60) % 60);
+            assertEquals(test.getSecond(), i % 60);
+            assertEquals(test.getNano(), 8);
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void factory_ofInstant_beforeEpoch() {
+        for (int i =-1; i >= -(24 * 60 * 60); i--) {
+            Instant instant = Instant.ofEpochSecond(i, 8);
+            OffsetTime test = OffsetTime.ofInstant(instant, ZoneOffset.UTC);
+            assertEquals(test.getHour(), ((i + 24 * 60 * 60) / (60 * 60)) % 24);
+            assertEquals(test.getMinute(), ((i + 24 * 60 * 60) / 60) % 60);
+            assertEquals(test.getSecond(), (i + 24 * 60 * 60) % 60);
+            assertEquals(test.getNano(), 8);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_ofInstant_maxYear() {
+        OffsetTime test = OffsetTime.ofInstant(Instant.MAX, ZoneOffset.UTC);
+        assertEquals(test.getHour(), 23);
+        assertEquals(test.getMinute(), 59);
+        assertEquals(test.getSecond(), 59);
+        assertEquals(test.getNano(), 999_999_999);
+    }
+
+    @Test(groups={"tck"})
+    public void factory_ofInstant_minYear() {
+        OffsetTime test = OffsetTime.ofInstant(Instant.MIN, ZoneOffset.UTC);
+        assertEquals(test.getHour(), 0);
+        assertEquals(test.getMinute(), 0);
+        assertEquals(test.getSecond(), 0);
+        assertEquals(test.getNano(), 0);
+    }
+
+    //-----------------------------------------------------------------------
+    // from(TemporalAccessor)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_from_TemporalAccessor_OT() {
+        assertEquals(OffsetTime.from(OffsetTime.of(LocalTime.of(17, 30), OFFSET_PONE)), OffsetTime.of(LocalTime.of(17, 30), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_from_TemporalAccessor_ZDT() {
+        ZonedDateTime base = LocalDateTime.of(2007, 7, 15, 11, 30, 59, 500).atZone(OFFSET_PONE);
+        assertEquals(OffsetTime.from(base), TEST_11_30_59_500_PONE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void factory_from_TemporalAccessor_invalid_noDerive() {
+        OffsetTime.from(LocalDate.of(2007, 7, 15));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_from_TemporalAccessor_null() {
+        OffsetTime.from((TemporalAccessor) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // parse()
+    //-----------------------------------------------------------------------
+    @Test(dataProvider = "sampleToString", groups={"tck"})
+    public void factory_parse_validText(int h, int m, int s, int n, String offsetId, String parsable) {
+        OffsetTime t = OffsetTime.parse(parsable);
+        assertNotNull(t, parsable);
+        check(t, h, m, s, n, ZoneOffset.of(offsetId));
+    }
+
+    @DataProvider(name="sampleBadParse")
+    Object[][] provider_sampleBadParse() {
+        return new Object[][]{
+                {"00;00"},
+                {"12-00"},
+                {"-01:00"},
+                {"00:00:00-09"},
+                {"00:00:00,09"},
+                {"00:00:abs"},
+                {"11"},
+                {"11:30"},
+                {"11:30+01:00[Europe/Paris]"},
+        };
+    }
+
+    @Test(dataProvider = "sampleBadParse", expectedExceptions={DateTimeParseException.class}, groups={"tck"})
+    public void factory_parse_invalidText(String unparsable) {
+        OffsetTime.parse(unparsable);
+    }
+
+    //-----------------------------------------------------------------------s
+    @Test(expectedExceptions={DateTimeParseException.class}, groups={"tck"})
+    public void factory_parse_illegalHour() {
+        OffsetTime.parse("25:00+01:00");
+    }
+
+    @Test(expectedExceptions={DateTimeParseException.class}, groups={"tck"})
+    public void factory_parse_illegalMinute() {
+        OffsetTime.parse("12:60+01:00");
+    }
+
+    @Test(expectedExceptions={DateTimeParseException.class}, groups={"tck"})
+    public void factory_parse_illegalSecond() {
+        OffsetTime.parse("12:12:60+01:00");
+    }
+
+    //-----------------------------------------------------------------------
+    // parse(DateTimeFormatter)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_parse_formatter() {
+        DateTimeFormatter f = DateTimeFormatters.pattern("H m s XXX");
+        OffsetTime test = OffsetTime.parse("11 30 0 +01:00", f);
+        assertEquals(test, OffsetTime.of(LocalTime.of(11, 30), ZoneOffset.ofHours(1)));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_parse_formatter_nullText() {
+        DateTimeFormatter f = DateTimeFormatters.pattern("y M d H m s");
+        OffsetTime.parse((String) null, f);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_parse_formatter_nullFormatter() {
+        OffsetTime.parse("ANY", null);
+    }
+
+    //-----------------------------------------------------------------------
+    // constructor
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void constructor_nullTime() throws Throwable  {
+        Constructor<OffsetTime> con = OffsetTime.class.getDeclaredConstructor(LocalTime.class, ZoneOffset.class);
+        con.setAccessible(true);
+        try {
+            con.newInstance(null, OFFSET_PONE);
+        } catch (InvocationTargetException ex) {
+            throw ex.getCause();
+        }
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void constructor_nullOffset() throws Throwable  {
+        Constructor<OffsetTime> con = OffsetTime.class.getDeclaredConstructor(LocalTime.class, ZoneOffset.class);
+        con.setAccessible(true);
+        try {
+            con.newInstance(LocalTime.of(11, 30), null);
+        } catch (InvocationTargetException ex) {
+            throw ex.getCause();
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // basics
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sampleTimes")
+    Object[][] provider_sampleTimes() {
+        return new Object[][] {
+            {11, 30, 20, 500, OFFSET_PONE},
+            {11, 0, 0, 0, OFFSET_PONE},
+            {23, 59, 59, 999999999, OFFSET_PONE},
+        };
+    }
+
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_get(int h, int m, int s, int n, ZoneOffset offset) {
+        LocalTime localTime = LocalTime.of(h, m, s, n);
+        OffsetTime a = OffsetTime.of(localTime, offset);
+
+        assertEquals(a.getTime(), localTime);
+        assertEquals(a.getOffset(), offset);
+        assertEquals(a.toString(), localTime.toString() + offset.toString());
+        assertEquals(a.getHour(), localTime.getHour());
+        assertEquals(a.getMinute(), localTime.getMinute());
+        assertEquals(a.getSecond(), localTime.getSecond());
+        assertEquals(a.getNano(), localTime.getNano());
+    }
+
+    //-----------------------------------------------------------------------
+    // get(TemporalField)
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_get_TemporalField() {
+        OffsetTime test = OffsetTime.of(LocalTime.of(12, 30, 40, 987654321), OFFSET_PONE);
+        assertEquals(test.get(ChronoField.HOUR_OF_DAY), 12);
+        assertEquals(test.get(ChronoField.MINUTE_OF_HOUR), 30);
+        assertEquals(test.get(ChronoField.SECOND_OF_MINUTE), 40);
+        assertEquals(test.get(ChronoField.NANO_OF_SECOND), 987654321);
+        assertEquals(test.get(ChronoField.HOUR_OF_AMPM), 0);
+        assertEquals(test.get(ChronoField.AMPM_OF_DAY), 1);
+
+        assertEquals(test.get(ChronoField.OFFSET_SECONDS), 3600);
+    }
+
+    @Test
+    public void test_getLong_TemporalField() {
+        OffsetTime test = OffsetTime.of(LocalTime.of(12, 30, 40, 987654321), OFFSET_PONE);
+        assertEquals(test.getLong(ChronoField.HOUR_OF_DAY), 12);
+        assertEquals(test.getLong(ChronoField.MINUTE_OF_HOUR), 30);
+        assertEquals(test.getLong(ChronoField.SECOND_OF_MINUTE), 40);
+        assertEquals(test.getLong(ChronoField.NANO_OF_SECOND), 987654321);
+        assertEquals(test.getLong(ChronoField.HOUR_OF_AMPM), 0);
+        assertEquals(test.getLong(ChronoField.AMPM_OF_DAY), 1);
+
+        assertEquals(test.getLong(ChronoField.OFFSET_SECONDS), 3600);
+    }
+
+    //-----------------------------------------------------------------------
+    // query(TemporalQuery)
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_query_chrono() {
+        assertEquals(TEST_11_30_59_500_PONE.query(Queries.chrono()), null);
+        assertEquals(Queries.chrono().queryFrom(TEST_11_30_59_500_PONE), null);
+    }
+
+    @Test
+    public void test_query_zoneId() {
+        assertEquals(TEST_11_30_59_500_PONE.query(Queries.zoneId()), null);
+        assertEquals(Queries.zoneId().queryFrom(TEST_11_30_59_500_PONE), null);
+    }
+
+    @Test
+    public void test_query_precision() {
+        assertEquals(TEST_11_30_59_500_PONE.query(Queries.precision()), NANOS);
+        assertEquals(Queries.precision().queryFrom(TEST_11_30_59_500_PONE), NANOS);
+    }
+
+    @Test
+    public void test_query_offset() {
+        assertEquals(TEST_11_30_59_500_PONE.query(Queries.offset()), OFFSET_PONE);
+        assertEquals(Queries.offset().queryFrom(TEST_11_30_59_500_PONE), OFFSET_PONE);
+    }
+
+    @Test
+    public void test_query_zone() {
+        assertEquals(TEST_11_30_59_500_PONE.query(Queries.zone()), OFFSET_PONE);
+        assertEquals(Queries.zone().queryFrom(TEST_11_30_59_500_PONE), OFFSET_PONE);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_query_null() {
+        TEST_11_30_59_500_PONE.query(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // withOffsetSameLocal()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withOffsetSameLocal() {
+        OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetTime test = base.withOffsetSameLocal(OFFSET_PTWO);
+        assertEquals(test.getTime(), base.getTime());
+        assertEquals(test.getOffset(), OFFSET_PTWO);
+    }
+
+    @Test(groups={"tck"})
+    public void test_withOffsetSameLocal_noChange() {
+        OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetTime test = base.withOffsetSameLocal(OFFSET_PONE);
+        assertEquals(test, base);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_withOffsetSameLocal_null() {
+        OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);
+        base.withOffsetSameLocal(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // withOffsetSameInstant()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withOffsetSameInstant() {
+        OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetTime test = base.withOffsetSameInstant(OFFSET_PTWO);
+        OffsetTime expected = OffsetTime.of(LocalTime.of(12, 30, 59), OFFSET_PTWO);
+        assertEquals(test, expected);
+    }
+
+    @Test(groups={"tck"})
+    public void test_withOffsetSameInstant_noChange() {
+        OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetTime test = base.withOffsetSameInstant(OFFSET_PONE);
+        assertEquals(test, base);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_withOffsetSameInstant_null() {
+        OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);
+        base.withOffsetSameInstant(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // with(WithAdjuster)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_with_adjustment() {
+        final OffsetTime sample = OffsetTime.of(LocalTime.of(23, 5), OFFSET_PONE);
+        TemporalAdjuster adjuster = new TemporalAdjuster() {
+            @Override
+            public Temporal adjustInto(Temporal dateTime) {
+                return sample;
+            }
+        };
+        assertEquals(TEST_11_30_59_500_PONE.with(adjuster), sample);
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_adjustment_LocalTime() {
+        OffsetTime test = TEST_11_30_59_500_PONE.with(LocalTime.of(13, 30));
+        assertEquals(test, OffsetTime.of(LocalTime.of(13, 30), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_adjustment_OffsetTime() {
+        OffsetTime test = TEST_11_30_59_500_PONE.with(OffsetTime.of(LocalTime.of(13, 35), OFFSET_PTWO));
+        assertEquals(test, OffsetTime.of(LocalTime.of(13, 35), OFFSET_PTWO));
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_adjustment_ZoneOffset() {
+        OffsetTime test = TEST_11_30_59_500_PONE.with(OFFSET_PTWO);
+        assertEquals(test, OffsetTime.of(LocalTime.of(11, 30, 59, 500), OFFSET_PTWO));
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_adjustment_AmPm() {
+        OffsetTime test = TEST_11_30_59_500_PONE.with(new TemporalAdjuster() {
+            @Override
+            public Temporal adjustInto(Temporal dateTime) {
+                return dateTime.with(HOUR_OF_DAY, 23);
+            }
+        });
+        assertEquals(test, OffsetTime.of(LocalTime.of(23, 30, 59, 500), OFFSET_PONE));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_with_adjustment_null() {
+        TEST_11_30_59_500_PONE.with((TemporalAdjuster) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // with(TemporalField, long)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_with_TemporalField() {
+        OffsetTime test = OffsetTime.of(LocalTime.of(12, 30, 40, 987654321), OFFSET_PONE);
+        assertEquals(test.with(ChronoField.HOUR_OF_DAY, 15), OffsetTime.of(LocalTime.of(15, 30, 40, 987654321), OFFSET_PONE));
+        assertEquals(test.with(ChronoField.MINUTE_OF_HOUR, 50), OffsetTime.of(LocalTime.of(12, 50, 40, 987654321), OFFSET_PONE));
+        assertEquals(test.with(ChronoField.SECOND_OF_MINUTE, 50), OffsetTime.of(LocalTime.of(12, 30, 50, 987654321), OFFSET_PONE));
+        assertEquals(test.with(ChronoField.NANO_OF_SECOND, 12345), OffsetTime.of(LocalTime.of(12, 30, 40, 12345), OFFSET_PONE));
+        assertEquals(test.with(ChronoField.HOUR_OF_AMPM, 6), OffsetTime.of(LocalTime.of(18, 30, 40, 987654321), OFFSET_PONE));
+        assertEquals(test.with(ChronoField.AMPM_OF_DAY, 0), OffsetTime.of(LocalTime.of(0, 30, 40, 987654321), OFFSET_PONE));
+
+        assertEquals(test.with(ChronoField.OFFSET_SECONDS, 7205), OffsetTime.of(LocalTime.of(12, 30, 40, 987654321), ZoneOffset.ofHoursMinutesSeconds(2, 0, 5)));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"} )
+    public void test_with_TemporalField_null() {
+        TEST_11_30_59_500_PONE.with((TemporalField) null, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"} )
+    public void test_with_TemporalField_invalidField() {
+        TEST_11_30_59_500_PONE.with(ChronoField.YEAR, 0);
+    }
+
+    //-----------------------------------------------------------------------
+    // withHour()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withHour_normal() {
+        OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetTime test = base.withHour(15);
+        assertEquals(test, OffsetTime.of(LocalTime.of(15, 30, 59), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_withHour_noChange() {
+        OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetTime test = base.withHour(11);
+        assertEquals(test, base);
+    }
+
+    //-----------------------------------------------------------------------
+    // withMinute()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withMinute_normal() {
+        OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetTime test = base.withMinute(15);
+        assertEquals(test, OffsetTime.of(LocalTime.of(11, 15, 59), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_withMinute_noChange() {
+        OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetTime test = base.withMinute(30);
+        assertEquals(test, base);
+    }
+
+    //-----------------------------------------------------------------------
+    // withSecond()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withSecond_normal() {
+        OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetTime test = base.withSecond(15);
+        assertEquals(test, OffsetTime.of(LocalTime.of(11, 30, 15), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_withSecond_noChange() {
+        OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetTime test = base.withSecond(59);
+        assertEquals(test, base);
+    }
+
+    //-----------------------------------------------------------------------
+    // withNano()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withNanoOfSecond_normal() {
+        OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59, 1), OFFSET_PONE);
+        OffsetTime test = base.withNano(15);
+        assertEquals(test, OffsetTime.of(LocalTime.of(11, 30, 59, 15), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_withNanoOfSecond_noChange() {
+        OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59, 1), OFFSET_PONE);
+        OffsetTime test = base.withNano(1);
+        assertEquals(test, base);
+    }
+
+    //-----------------------------------------------------------------------
+    // truncatedTo(TemporalUnit)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_truncatedTo_normal() {
+        assertEquals(TEST_11_30_59_500_PONE.truncatedTo(NANOS), TEST_11_30_59_500_PONE);
+        assertEquals(TEST_11_30_59_500_PONE.truncatedTo(SECONDS), TEST_11_30_59_500_PONE.withNano(0));
+        assertEquals(TEST_11_30_59_500_PONE.truncatedTo(DAYS), TEST_11_30_59_500_PONE.with(LocalTime.MIDNIGHT));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_truncatedTo_null() {
+        TEST_11_30_59_500_PONE.truncatedTo(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // plus(PlusAdjuster)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plus_PlusAdjuster() {
+        MockSimplePeriod period = MockSimplePeriod.of(7, ChronoUnit.MINUTES);
+        OffsetTime t = TEST_11_30_59_500_PONE.plus(period);
+        assertEquals(t, OffsetTime.of(LocalTime.of(11, 37, 59, 500), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plus_PlusAdjuster_noChange() {
+        OffsetTime t = TEST_11_30_59_500_PONE.plus(MockSimplePeriod.of(0, SECONDS));
+        assertEquals(t, TEST_11_30_59_500_PONE);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plus_PlusAdjuster_zero() {
+        OffsetTime t = TEST_11_30_59_500_PONE.plus(Period.ZERO);
+        assertEquals(t, TEST_11_30_59_500_PONE);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_plus_PlusAdjuster_null() {
+        TEST_11_30_59_500_PONE.plus((TemporalAdder) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusHours()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusHours() {
+        OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetTime test = base.plusHours(13);
+        assertEquals(test, OffsetTime.of(LocalTime.of(0, 30, 59), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusHours_zero() {
+        OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetTime test = base.plusHours(0);
+        assertEquals(test, base);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusMinutes()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusMinutes() {
+        OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetTime test = base.plusMinutes(30);
+        assertEquals(test, OffsetTime.of(LocalTime.of(12, 0, 59), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMinutes_zero() {
+        OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetTime test = base.plusMinutes(0);
+        assertEquals(test, base);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusSeconds()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusSeconds() {
+        OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetTime test = base.plusSeconds(1);
+        assertEquals(test, OffsetTime.of(LocalTime.of(11, 31, 0), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusSeconds_zero() {
+        OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetTime test = base.plusSeconds(0);
+        assertEquals(test, base);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusNanos()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusNanos() {
+        OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59, 0), OFFSET_PONE);
+        OffsetTime test = base.plusNanos(1);
+        assertEquals(test, OffsetTime.of(LocalTime.of(11, 30, 59, 1), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusNanos_zero() {
+        OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetTime test = base.plusNanos(0);
+        assertEquals(test, base);
+    }
+
+    //-----------------------------------------------------------------------
+    // minus(MinusAdjuster)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minus_MinusAdjuster() {
+        MockSimplePeriod period = MockSimplePeriod.of(7, ChronoUnit.MINUTES);
+        OffsetTime t = TEST_11_30_59_500_PONE.minus(period);
+        assertEquals(t, OffsetTime.of(LocalTime.of(11, 23, 59, 500), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minus_MinusAdjuster_noChange() {
+        OffsetTime t = TEST_11_30_59_500_PONE.minus(MockSimplePeriod.of(0, SECONDS));
+        assertEquals(t, TEST_11_30_59_500_PONE);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minus_MinusAdjuster_zero() {
+        OffsetTime t = TEST_11_30_59_500_PONE.minus(Period.ZERO);
+        assertEquals(t, TEST_11_30_59_500_PONE);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_minus_MinusAdjuster_null() {
+        TEST_11_30_59_500_PONE.minus((TemporalSubtractor) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusHours()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusHours() {
+        OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetTime test = base.minusHours(-13);
+        assertEquals(test, OffsetTime.of(LocalTime.of(0, 30, 59), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusHours_zero() {
+        OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetTime test = base.minusHours(0);
+        assertEquals(test, base);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusMinutes()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusMinutes() {
+        OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetTime test = base.minusMinutes(50);
+        assertEquals(test, OffsetTime.of(LocalTime.of(10, 40, 59), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMinutes_zero() {
+        OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetTime test = base.minusMinutes(0);
+        assertEquals(test, base);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusSeconds()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusSeconds() {
+        OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetTime test = base.minusSeconds(60);
+        assertEquals(test, OffsetTime.of(LocalTime.of(11, 29, 59), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusSeconds_zero() {
+        OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetTime test = base.minusSeconds(0);
+        assertEquals(test, base);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusNanos()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusNanos() {
+        OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59, 0), OFFSET_PONE);
+        OffsetTime test = base.minusNanos(1);
+        assertEquals(test, OffsetTime.of(LocalTime.of(11, 30, 58, 999999999), OFFSET_PONE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusNanos_zero() {
+        OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetTime test = base.minusNanos(0);
+        assertEquals(test, base);
+    }
+
+    //-----------------------------------------------------------------------
+    // compareTo()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_compareTo_time() {
+        OffsetTime a = OffsetTime.of(LocalTime.of(11, 29), OFFSET_PONE);
+        OffsetTime b = OffsetTime.of(LocalTime.of(11, 30), OFFSET_PONE);  // a is before b due to time
+        assertEquals(a.compareTo(b) < 0, true);
+        assertEquals(b.compareTo(a) > 0, true);
+        assertEquals(a.compareTo(a) == 0, true);
+        assertEquals(b.compareTo(b) == 0, true);
+        assertEquals(convertInstant(a).compareTo(convertInstant(b)) < 0, true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_compareTo_offset() {
+        OffsetTime a = OffsetTime.of(LocalTime.of(11, 30), OFFSET_PTWO);
+        OffsetTime b = OffsetTime.of(LocalTime.of(11, 30), OFFSET_PONE);  // a is before b due to offset
+        assertEquals(a.compareTo(b) < 0, true);
+        assertEquals(b.compareTo(a) > 0, true);
+        assertEquals(a.compareTo(a) == 0, true);
+        assertEquals(b.compareTo(b) == 0, true);
+        assertEquals(convertInstant(a).compareTo(convertInstant(b)) < 0, true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_compareTo_both() {
+        OffsetTime a = OffsetTime.of(LocalTime.of(11, 50), OFFSET_PTWO);
+        OffsetTime b = OffsetTime.of(LocalTime.of(11, 20), OFFSET_PONE);  // a is before b on instant scale
+        assertEquals(a.compareTo(b) < 0, true);
+        assertEquals(b.compareTo(a) > 0, true);
+        assertEquals(a.compareTo(a) == 0, true);
+        assertEquals(b.compareTo(b) == 0, true);
+        assertEquals(convertInstant(a).compareTo(convertInstant(b)) < 0, true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_compareTo_bothNearStartOfDay() {
+        OffsetTime a = OffsetTime.of(LocalTime.of(0, 10), OFFSET_PONE);
+        OffsetTime b = OffsetTime.of(LocalTime.of(2, 30), OFFSET_PTWO);  // a is before b on instant scale
+        assertEquals(a.compareTo(b) < 0, true);
+        assertEquals(b.compareTo(a) > 0, true);
+        assertEquals(a.compareTo(a) == 0, true);
+        assertEquals(b.compareTo(b) == 0, true);
+        assertEquals(convertInstant(a).compareTo(convertInstant(b)) < 0, true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_compareTo_hourDifference() {
+        OffsetTime a = OffsetTime.of(LocalTime.of(10, 0), OFFSET_PONE);
+        OffsetTime b = OffsetTime.of(LocalTime.of(11, 0), OFFSET_PTWO);  // a is before b despite being same time-line time
+        assertEquals(a.compareTo(b) < 0, true);
+        assertEquals(b.compareTo(a) > 0, true);
+        assertEquals(a.compareTo(a) == 0, true);
+        assertEquals(b.compareTo(b) == 0, true);
+        assertEquals(convertInstant(a).compareTo(convertInstant(b)) == 0, true);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_compareTo_null() {
+        OffsetTime a = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);
+        a.compareTo(null);
+    }
+
+    @Test(expectedExceptions=ClassCastException.class, groups={"tck"})
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public void compareToNonOffsetTime() {
+       Comparable c = TEST_11_30_59_500_PONE;
+       c.compareTo(new Object());
+    }
+
+    private Instant convertInstant(OffsetTime ot) {
+        return DATE.atTime(ot.getTime()).toInstant(ot.getOffset());
+    }
+
+    //-----------------------------------------------------------------------
+    // isAfter() / isBefore() / isEqual()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_isBeforeIsAfterIsEqual1() {
+        OffsetTime a = OffsetTime.of(LocalTime.of(11, 30, 58), OFFSET_PONE);
+        OffsetTime b = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);  // a is before b due to time
+        assertEquals(a.isBefore(b), true);
+        assertEquals(a.isEqual(b), false);
+        assertEquals(a.isAfter(b), false);
+
+        assertEquals(b.isBefore(a), false);
+        assertEquals(b.isEqual(a), false);
+        assertEquals(b.isAfter(a), true);
+
+        assertEquals(a.isBefore(a), false);
+        assertEquals(b.isBefore(b), false);
+
+        assertEquals(a.isEqual(a), true);
+        assertEquals(b.isEqual(b), true);
+
+        assertEquals(a.isAfter(a), false);
+        assertEquals(b.isAfter(b), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_isBeforeIsAfterIsEqual1nanos() {
+        OffsetTime a = OffsetTime.of(LocalTime.of(11, 30, 59, 3), OFFSET_PONE);
+        OffsetTime b = OffsetTime.of(LocalTime.of(11, 30, 59, 4), OFFSET_PONE);  // a is before b due to time
+        assertEquals(a.isBefore(b), true);
+        assertEquals(a.isEqual(b), false);
+        assertEquals(a.isAfter(b), false);
+
+        assertEquals(b.isBefore(a), false);
+        assertEquals(b.isEqual(a), false);
+        assertEquals(b.isAfter(a), true);
+
+        assertEquals(a.isBefore(a), false);
+        assertEquals(b.isBefore(b), false);
+
+        assertEquals(a.isEqual(a), true);
+        assertEquals(b.isEqual(b), true);
+
+        assertEquals(a.isAfter(a), false);
+        assertEquals(b.isAfter(b), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_isBeforeIsAfterIsEqual2() {
+        OffsetTime a = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PTWO);
+        OffsetTime b = OffsetTime.of(LocalTime.of(11, 30, 58), OFFSET_PONE);  // a is before b due to offset
+        assertEquals(a.isBefore(b), true);
+        assertEquals(a.isEqual(b), false);
+        assertEquals(a.isAfter(b), false);
+
+        assertEquals(b.isBefore(a), false);
+        assertEquals(b.isEqual(a), false);
+        assertEquals(b.isAfter(a), true);
+
+        assertEquals(a.isBefore(a), false);
+        assertEquals(b.isBefore(b), false);
+
+        assertEquals(a.isEqual(a), true);
+        assertEquals(b.isEqual(b), true);
+
+        assertEquals(a.isAfter(a), false);
+        assertEquals(b.isAfter(b), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_isBeforeIsAfterIsEqual2nanos() {
+        OffsetTime a = OffsetTime.of(LocalTime.of(11, 30, 59, 4), ZoneOffset.ofTotalSeconds(OFFSET_PONE.getTotalSeconds() + 1));
+        OffsetTime b = OffsetTime.of(LocalTime.of(11, 30, 59, 3), OFFSET_PONE);  // a is before b due to offset
+        assertEquals(a.isBefore(b), true);
+        assertEquals(a.isEqual(b), false);
+        assertEquals(a.isAfter(b), false);
+
+        assertEquals(b.isBefore(a), false);
+        assertEquals(b.isEqual(a), false);
+        assertEquals(b.isAfter(a), true);
+
+        assertEquals(a.isBefore(a), false);
+        assertEquals(b.isBefore(b), false);
+
+        assertEquals(a.isEqual(a), true);
+        assertEquals(b.isEqual(b), true);
+
+        assertEquals(a.isAfter(a), false);
+        assertEquals(b.isAfter(b), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_isBeforeIsAfterIsEqual_instantComparison() {
+        OffsetTime a = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PTWO);
+        OffsetTime b = OffsetTime.of(LocalTime.of(10, 30, 59), OFFSET_PONE);  // a is same instant as b
+        assertEquals(a.isBefore(b), false);
+        assertEquals(a.isEqual(b), true);
+        assertEquals(a.isAfter(b), false);
+
+        assertEquals(b.isBefore(a), false);
+        assertEquals(b.isEqual(a), true);
+        assertEquals(b.isAfter(a), false);
+
+        assertEquals(a.isBefore(a), false);
+        assertEquals(b.isBefore(b), false);
+
+        assertEquals(a.isEqual(a), true);
+        assertEquals(b.isEqual(b), true);
+
+        assertEquals(a.isAfter(a), false);
+        assertEquals(b.isAfter(b), false);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_isBefore_null() {
+        OffsetTime a = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);
+        a.isBefore(null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_isAfter_null() {
+        OffsetTime a = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);
+        a.isAfter(null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_isEqual_null() {
+        OffsetTime a = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE);
+        a.isEqual(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // equals() / hashCode()
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_equals_true(int h, int m, int s, int n, ZoneOffset ignored) {
+        OffsetTime a = OffsetTime.of(LocalTime.of(h, m, s, n), OFFSET_PONE);
+        OffsetTime b = OffsetTime.of(LocalTime.of(h, m, s, n), OFFSET_PONE);
+        assertEquals(a.equals(b), true);
+        assertEquals(a.hashCode() == b.hashCode(), true);
+    }
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_equals_false_hour_differs(int h, int m, int s, int n, ZoneOffset ignored) {
+        h = (h == 23 ? 22 : h);
+        OffsetTime a = OffsetTime.of(LocalTime.of(h, m, s, n), OFFSET_PONE);
+        OffsetTime b = OffsetTime.of(LocalTime.of(h + 1, m, s, n), OFFSET_PONE);
+        assertEquals(a.equals(b), false);
+    }
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_equals_false_minute_differs(int h, int m, int s, int n, ZoneOffset ignored) {
+        m = (m == 59 ? 58 : m);
+        OffsetTime a = OffsetTime.of(LocalTime.of(h, m, s, n), OFFSET_PONE);
+        OffsetTime b = OffsetTime.of(LocalTime.of(h, m + 1, s, n), OFFSET_PONE);
+        assertEquals(a.equals(b), false);
+    }
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_equals_false_second_differs(int h, int m, int s, int n, ZoneOffset ignored) {
+        s = (s == 59 ? 58 : s);
+        OffsetTime a = OffsetTime.of(LocalTime.of(h, m, s, n), OFFSET_PONE);
+        OffsetTime b = OffsetTime.of(LocalTime.of(h, m, s + 1, n), OFFSET_PONE);
+        assertEquals(a.equals(b), false);
+    }
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_equals_false_nano_differs(int h, int m, int s, int n, ZoneOffset ignored) {
+        n = (n == 999999999 ? 999999998 : n);
+        OffsetTime a = OffsetTime.of(LocalTime.of(h, m, s, n), OFFSET_PONE);
+        OffsetTime b = OffsetTime.of(LocalTime.of(h, m, s, n + 1), OFFSET_PONE);
+        assertEquals(a.equals(b), false);
+    }
+    @Test(dataProvider="sampleTimes", groups={"tck"})
+    public void test_equals_false_offset_differs(int h, int m, int s, int n, ZoneOffset ignored) {
+        OffsetTime a = OffsetTime.of(LocalTime.of(h, m, s, n), OFFSET_PONE);
+        OffsetTime b = OffsetTime.of(LocalTime.of(h, m, s, n), OFFSET_PTWO);
+        assertEquals(a.equals(b), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_itself_true() {
+        assertEquals(TEST_11_30_59_500_PONE.equals(TEST_11_30_59_500_PONE), true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_string_false() {
+        assertEquals(TEST_11_30_59_500_PONE.equals("2007-07-15"), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_null_false() {
+        assertEquals(TEST_11_30_59_500_PONE.equals(null), false);
+    }
+
+    //-----------------------------------------------------------------------
+    // toString()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sampleToString")
+    Object[][] provider_sampleToString() {
+        return new Object[][] {
+            {11, 30, 59, 0, "Z", "11:30:59Z"},
+            {11, 30, 59, 0, "+01:00", "11:30:59+01:00"},
+            {11, 30, 59, 999000000, "Z", "11:30:59.999Z"},
+            {11, 30, 59, 999000000, "+01:00", "11:30:59.999+01:00"},
+            {11, 30, 59, 999000, "Z", "11:30:59.000999Z"},
+            {11, 30, 59, 999000, "+01:00", "11:30:59.000999+01:00"},
+            {11, 30, 59, 999, "Z", "11:30:59.000000999Z"},
+            {11, 30, 59, 999, "+01:00", "11:30:59.000000999+01:00"},
+        };
+    }
+
+    @Test(dataProvider="sampleToString", groups={"tck"})
+    public void test_toString(int h, int m, int s, int n, String offsetId, String expected) {
+        OffsetTime t = OffsetTime.of(LocalTime.of(h, m, s, n), ZoneOffset.of(offsetId));
+        String str = t.toString();
+        assertEquals(str, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // toString(DateTimeFormatter)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_toString_formatter() {
+        DateTimeFormatter f = DateTimeFormatters.pattern("H m s");
+        String t = OffsetTime.of(LocalTime.of(11, 30), OFFSET_PONE).toString(f);
+        assertEquals(t, "11 30 0");
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_toString_formatter_null() {
+        OffsetTime.of(LocalTime.of(11, 30), OFFSET_PONE).toString(null);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/temporal/TCKSimplePeriod.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.temporal;
+
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.MONTHS;
+import static java.time.temporal.ChronoUnit.NANOS;
+import static java.time.temporal.ChronoUnit.SECONDS;
+import static java.time.temporal.ChronoUnit.YEARS;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertSame;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import java.time.LocalDate;
+import java.time.Period;
+import java.time.temporal.ISOFields;
+import java.time.temporal.SimplePeriod;
+import java.time.temporal.TemporalUnit;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import tck.java.time.AbstractTCKTest;
+
+/**
+ * Test.
+ */
+@Test
+public class TCKSimplePeriod extends AbstractTCKTest {
+
+    private static final SimplePeriod TEST_12_MONTHS = SimplePeriod.of(12, MONTHS);
+
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="samples")
+    public void test_serialization(long amount, TemporalUnit unit) throws ClassNotFoundException, IOException {
+        SimplePeriod test = SimplePeriod.of(amount, unit);
+        assertSerializable(test);
+    }
+
+    @Test
+    public void test_serialization_format_zoneOffset() throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try (DataOutputStream dos = new DataOutputStream(baos) ) {
+            dos.writeByte(10);
+            dos.writeLong(12);
+        }
+        byte[] bytes = baos.toByteArray();
+        assertSerializedBySer(TEST_12_MONTHS, bytes, new byte[0]);
+    }
+
+    //-----------------------------------------------------------------------
+    // of(long, TenmporalUnit)
+    //-----------------------------------------------------------------------
+    @DataProvider(name="samples")
+    Object[][] data_samples() {
+        return new Object[][] {
+                {0, YEARS},
+                {1, YEARS},
+                {-1, YEARS},
+                {2, MONTHS},
+                {-2, MONTHS},
+                {43, ISOFields.WEEK_BASED_YEARS},
+                {Long.MAX_VALUE, NANOS},
+                {Long.MIN_VALUE, NANOS},
+        };
+    }
+
+    @Test(dataProvider="samples")
+    public void factory_of(long amount, TemporalUnit unit) {
+        SimplePeriod test = SimplePeriod.of(amount, unit);
+        assertEquals(test.getAmount(), amount);
+        assertEquals(test.getUnit(), unit);
+    }
+
+    //-----------------------------------------------------------------------
+    // addTo()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="addTo")
+    Object[][] data_addTo() {
+        return new Object[][] {
+            {SimplePeriod.of(0, DAYS),  date(2012, 6, 30), date(2012, 6, 30)},
+
+            {SimplePeriod.of(1, DAYS),  date(2012, 6, 30), date(2012, 7, 1)},
+            {SimplePeriod.of(-1, DAYS),  date(2012, 6, 30), date(2012, 6, 29)},
+
+            {SimplePeriod.of(2, DAYS),  date(2012, 6, 30), date(2012, 7, 2)},
+            {SimplePeriod.of(-2, DAYS),  date(2012, 6, 30), date(2012, 6, 28)},
+
+            {SimplePeriod.of(3, MONTHS),  date(2012, 5, 31), date(2012, 8, 31)},
+            {SimplePeriod.of(4, MONTHS),  date(2012, 5, 31), date(2012, 9, 30)},
+            {SimplePeriod.of(-3, MONTHS),  date(2012, 5, 31), date(2012, 2, 29)},
+            {SimplePeriod.of(-4, MONTHS),  date(2012, 5, 31), date(2012, 1, 31)},
+        };
+    }
+
+    @Test(dataProvider="addTo")
+    public void test_addTo(SimplePeriod period, LocalDate baseDate, LocalDate expected) {
+        assertEquals(period.addTo(baseDate), expected);
+    }
+
+    @Test(dataProvider="addTo")
+    public void test_addTo_usingLocalDatePlus(SimplePeriod period, LocalDate baseDate, LocalDate expected) {
+        assertEquals(baseDate.plus(period), expected);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_addTo_nullZero() {
+        SimplePeriod.of(0, DAYS).addTo(null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_addTo_nullNonZero() {
+        SimplePeriod.of(2, DAYS).addTo(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // subtractFrom()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="subtractFrom")
+    Object[][] data_subtractFrom() {
+        return new Object[][] {
+            {SimplePeriod.of(0, DAYS),  date(2012, 6, 30), date(2012, 6, 30)},
+
+            {SimplePeriod.of(1, DAYS),  date(2012, 6, 30), date(2012, 6, 29)},
+            {SimplePeriod.of(-1, DAYS),  date(2012, 6, 30), date(2012, 7, 1)},
+
+            {SimplePeriod.of(2, DAYS),  date(2012, 6, 30), date(2012, 6, 28)},
+            {SimplePeriod.of(-2, DAYS),  date(2012, 6, 30), date(2012, 7, 2)},
+
+            {SimplePeriod.of(3, MONTHS),  date(2012, 5, 31), date(2012, 2, 29)},
+            {SimplePeriod.of(4, MONTHS),  date(2012, 5, 31), date(2012, 1, 31)},
+            {SimplePeriod.of(-3, MONTHS),  date(2012, 5, 31), date(2012, 8, 31)},
+            {SimplePeriod.of(-4, MONTHS),  date(2012, 5, 31), date(2012, 9, 30)},
+        };
+    }
+
+    @Test(dataProvider="subtractFrom")
+    public void test_subtractFrom(SimplePeriod period, LocalDate baseDate, LocalDate expected) {
+        assertEquals(period.subtractFrom(baseDate), expected);
+    }
+
+    @Test(dataProvider="subtractFrom")
+    public void test_subtractFrom_usingLocalDateMinus(SimplePeriod period, LocalDate baseDate, LocalDate expected) {
+        assertEquals(baseDate.minus(period), expected);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_subtractFrom_nullZero() {
+        SimplePeriod.of(0, DAYS).subtractFrom(null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_subtractFrom_nullNonZero() {
+        SimplePeriod.of(2, DAYS).subtractFrom(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // abs()
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="samples")
+    public void test_abs(long amount, TemporalUnit unit) {
+        SimplePeriod test = SimplePeriod.of(amount, unit);
+        if (amount >= 0) {
+            assertSame(test.abs(), test);  // spec requires assertSame
+        } else if (amount == Long.MIN_VALUE) {
+            // ignore, separately tested
+        } else {
+            assertEquals(test.abs(), SimplePeriod.of(-amount, unit));
+        }
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_abs_minValue() {
+        SimplePeriod.of(Long.MIN_VALUE, SECONDS).abs();
+    }
+
+    //-----------------------------------------------------------------------
+    // equals() / hashCode()
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="samples")
+    public void test_equals(long amount, TemporalUnit unit) {
+        SimplePeriod test1 = SimplePeriod.of(amount, unit);
+        SimplePeriod test2 = SimplePeriod.of(amount, unit);
+        assertEquals(test1, test2);
+    }
+
+    @Test(dataProvider="samples")
+    public void test_equals_self(long amount, TemporalUnit unit) {
+        SimplePeriod test = SimplePeriod.of(amount, unit);
+        assertEquals(test.equals(test), true);
+    }
+
+    public void test_equals_null() {
+        assertEquals(TEST_12_MONTHS.equals(null), false);
+    }
+
+    public void test_equals_otherClass() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6);
+        assertEquals(test.equals(""), false);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_hashCode() {
+        SimplePeriod test5 = SimplePeriod.of(5, DAYS);
+        SimplePeriod test6 = SimplePeriod.of(6, DAYS);
+        SimplePeriod test5M = SimplePeriod.of(5, MONTHS);
+        SimplePeriod test5Y = SimplePeriod.of(5, YEARS);
+        assertEquals(test5.hashCode() == test5.hashCode(), true);
+        assertEquals(test5.hashCode() == test6.hashCode(), false);
+        assertEquals(test5.hashCode() == test5M.hashCode(), false);
+        assertEquals(test5.hashCode() == test5Y.hashCode(), false);
+    }
+
+    //-----------------------------------------------------------------------
+    // toString()
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="samples")
+    public void test_toString(long amount, TemporalUnit unit) {
+        SimplePeriod test = SimplePeriod.of(amount, unit);
+        assertEquals(test.toString(), amount + " " + unit.getName());
+    }
+
+    private static LocalDate date(int y, int m, int d) {
+        return LocalDate.of(y, m, d);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/temporal/TCKWeekFields.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.temporal;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.fail;
+
+import static java.time.temporal.ChronoField.DAY_OF_WEEK;
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.DAY_OF_YEAR;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.YEAR;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+import java.time.temporal.TemporalField;
+import java.time.format.DateTimeBuilder;
+import java.time.temporal.ValueRange;
+import java.time.temporal.WeekFields;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test WeekFields.
+ */
+@Test
+public class TCKWeekFields {
+
+    @Test(groups={"tck"})
+    public void test_WeekFieldsOf() {
+        for (DayOfWeek dow : DayOfWeek.values()) {
+            for (int minDays = 1; minDays <= 7; minDays++) {
+                WeekFields week = WeekFields.of(dow, minDays);
+                assertEquals(week.getFirstDayOfWeek(), dow, "Incorrect firstDayOfWeek");
+                assertEquals(week.getMinimalDaysInFirstWeek(), minDays, "Incorrect MinimalDaysInFirstWeek");
+            }
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_DayOfWeek() {
+        LocalDate day = LocalDate.of(2000, 1, 10);  // Known to be ISO Monday
+        for (DayOfWeek firstDayOfWeek : DayOfWeek.values()) {
+            for (int minDays = 1; minDays <= 7; minDays++) {
+                WeekFields week = WeekFields.of(firstDayOfWeek, minDays);
+                TemporalField f = week.dayOfWeek();
+                //System.out.printf("  Week: %s; field: %s%n", week, f);
+
+                for (int i = 1; i <= 7; i++) {
+                    //System.out.printf("  ISO Dow: %s, WeekDOW ordinal: %s%n", day.getDayOfWeek(), day.get(f));
+                    assertEquals(day.get(f), (7 + day.getDayOfWeek().getValue() - firstDayOfWeek.getValue()) % 7 + 1);
+                    day = day.plusDays(1);
+                }
+            }
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_WeekOfMonth() {
+        for (DayOfWeek firstDayOfWeek : DayOfWeek.values()) {
+            for (int minDays = 1; minDays <= 7; minDays++) {
+                LocalDate day = LocalDate.of(2012, 12, 31);  // Known to be ISO Monday
+                WeekFields week = WeekFields.of(firstDayOfWeek, minDays);
+                TemporalField dowField = week.dayOfWeek();
+                TemporalField womField = week.weekOfMonth();
+                //System.err.printf("%n  Week: %s; dowField: %s, domField: %s%n", week, dowField, womField);
+
+                DayOfWeek isoDOW = day.getDayOfWeek();
+                int dow = (7 + isoDOW.getValue() - firstDayOfWeek.getValue()) % 7 + 1;
+
+                for (int i = 1; i <= 15; i++) {
+                    int actualDOW = day.get(dowField);
+                    int actualWOM = day.get(womField);
+
+                    // Verify that the combination of day of week and week of month can be used
+                    // to reconstruct the same date.
+                    LocalDate day1 = day.withDayOfMonth(1);
+                    int offset = - (day1.get(dowField) - 1);
+                    //System.err.printf("   refDay: %s%n", day1.plusDays(offset));
+                    int week1 = day1.get(womField);
+                    if (week1 == 0) {
+                        // week of the 1st is partial; start with first full week
+                        offset += 7;
+                    }
+                    //System.err.printf("   refDay2: %s, offset: %d, week1: %d%n", day1.plusDays(offset), offset, week1);
+                    offset += actualDOW - 1;
+                    //System.err.printf("   refDay3: %s%n", day1.plusDays(offset));
+                    offset += (actualWOM - 1) * 7;
+                    //System.err.printf("   refDay4: %s%n", day1.plusDays(offset));
+                    LocalDate result = day1.plusDays(offset);
+
+                    if (!day.equals(result)) {
+                        System.err.printf("FAIL ISO Dow: %s, offset: %s, actualDOW: %s, actualWOM: %s, expected: %s, result: %s%n",
+                                day.getDayOfWeek(), offset, actualDOW, actualWOM, day, result);
+                    }
+                    assertEquals(result, day, "Incorrect dayOfWeek or weekOfMonth: "
+                            + String.format("%s, ISO Dow: %s, offset: %s, actualDOW: %s, actualWOM: %s, expected: %s, result: %s%n",
+                            week, day.getDayOfWeek(), offset, actualDOW, actualWOM, day, result));
+                    day = day.plusDays(1);
+                }
+            }
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_WeekOfYear() {
+        for (DayOfWeek firstDayOfWeek : DayOfWeek.values()) {
+            for (int minDays = 1; minDays <= 7; minDays++) {
+                LocalDate day = LocalDate.of(2012, 12, 31);  // Known to be ISO Monday
+                WeekFields week = WeekFields.of(firstDayOfWeek, minDays);
+                TemporalField dowField = week.dayOfWeek();
+                TemporalField woyField = week.weekOfYear();
+                //System.err.printf("%n  Year: %s; dowField: %s, woyField: %s%n", week, dowField, woyField);
+
+                DayOfWeek isoDOW = day.getDayOfWeek();
+                int dow = (7 + isoDOW.getValue() - firstDayOfWeek.getValue()) % 7 + 1;
+
+                for (int i = 1; i <= 15; i++) {
+                    int actualDOW = day.get(dowField);
+                    int actualWOY = day.get(woyField);
+
+                    // Verify that the combination of day of week and week of month can be used
+                    // to reconstruct the same date.
+                    LocalDate day1 = day.withDayOfYear(1);
+                    int offset = - (day1.get(dowField) - 1);
+                    //System.err.printf("   refDay: %s%n", day1.plusDays(offset));
+                    int week1 = day1.get(woyField);
+                    if (week1 == 0) {
+                        // week of the 1st is partial; start with first full week
+                        offset += 7;
+                    }
+                    //System.err.printf("   refDay2: %s, offset: %d, week1: %d%n", day1.plusDays(offset), offset, week1);
+                    offset += actualDOW - 1;
+                    //System.err.printf("   refDay3: %s%n", day1.plusDays(offset));
+                    offset += (actualWOY - 1) * 7;
+                    //System.err.printf("   refDay4: %s%n", day1.plusDays(offset));
+                    LocalDate result = day1.plusDays(offset);
+
+
+                    if (!day.equals(result)) {
+                        System.err.printf("FAIL  ISO Dow: %s, offset: %s, actualDOW: %s, actualWOY: %s, expected: %s, result: %s%n",
+                                day.getDayOfWeek(), offset, actualDOW, actualWOY, day, result);
+                    }
+                    assertEquals(result, day, "Incorrect dayOfWeek or weekOfYear "
+                            + String.format("%s, ISO Dow: %s, offset: %s, actualDOW: %s, actualWOM: %s, expected: %s, result: %s%n",
+                            week, day.getDayOfWeek(), offset, actualDOW, actualWOY, day, result));
+                    day = day.plusDays(1);
+                }
+            }
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_fieldRanges() {
+        for (DayOfWeek firstDayOfWeek : DayOfWeek.values()) {
+            for (int minDays = 1; minDays <= 7; minDays++) {
+                WeekFields weekDef = WeekFields.of(firstDayOfWeek, minDays);
+                TemporalField dowField = weekDef.dayOfWeek();
+                TemporalField womField = weekDef.weekOfMonth();
+                TemporalField woyField = weekDef.weekOfYear();
+
+                LocalDate day = LocalDate.of(2012, 11, 30);
+                LocalDate endDay = LocalDate.of(2013, 1, 2);
+                while (day.isBefore(endDay)) {
+                    LocalDate last = day.with(DAY_OF_MONTH, day.lengthOfMonth());
+                    int lastWOM = last.get(womField);
+                    LocalDate first = day.with(DAY_OF_MONTH, 1);
+                    int firstWOM = first.get(womField);
+                    ValueRange rangeWOM = day.range(womField);
+                    assertEquals(rangeWOM.getMinimum(), firstWOM,
+                            "Range min should be same as WeekOfMonth for first day of month: "
+                            + first + ", " + weekDef);
+                    assertEquals(rangeWOM.getMaximum(), lastWOM,
+                            "Range max should be same as WeekOfMonth for last day of month: "
+                            + last + ", " + weekDef);
+
+                    last = day.with(DAY_OF_YEAR, day.lengthOfYear());
+                    int lastWOY = last.get(woyField);
+                    first = day.with(DAY_OF_YEAR, 1);
+                    int firstWOY = first.get(woyField);
+                    ValueRange rangeWOY = day.range(woyField);
+                    assertEquals(rangeWOY.getMinimum(), firstWOY,
+                            "Range min should be same as WeekOfYear for first day of Year: "
+                            + day + ", " + weekDef);
+                    assertEquals(rangeWOY.getMaximum(), lastWOY,
+                            "Range max should be same as WeekOfYear for last day of Year: "
+                            + day + ", " + weekDef);
+
+                    day = day.plusDays(1);
+                }
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // withDayOfWeek()
+    //-----------------------------------------------------------------------
+    @Test(groups = {"tck"})
+    public void test_withDayOfWeek() {
+        for (DayOfWeek firstDayOfWeek : DayOfWeek.values()) {
+            for (int minDays = 1; minDays <= 7; minDays++) {
+                LocalDate day = LocalDate.of(2012, 12, 15);  // Safely in the middle of a month
+                WeekFields week = WeekFields.of(firstDayOfWeek, minDays);
+
+                TemporalField dowField = week.dayOfWeek();
+                TemporalField womField = week.weekOfMonth();
+                TemporalField woyField = week.weekOfYear();
+                int wom = day.get(womField);
+                int woy = day.get(woyField);
+                for (int dow = 1; dow <= 7; dow++) {
+                    LocalDate result = day.with(dowField, dow);
+                    if (result.get(dowField) != dow) {
+                        System.err.printf(" DOW actual: %d, expected: %d, week:%s%n",
+                                result.get(dowField), dow, week);
+                    }
+                    if (result.get(womField) != wom) {
+                        System.err.printf(" WOM actual: %d, expected: %d, week:%s%n",
+                                result.get(womField), wom, week);
+                    }
+                    if (result.get(woyField) != woy) {
+                        System.err.printf(" WOY actual: %d, expected: %d, week:%s%n",
+                                result.get(woyField), woy, week);
+                    }
+                    assertEquals(result.get(dowField), dow, String.format("Incorrect new Day of week: %s", result));
+                    assertEquals(result.get(womField), wom, "Week of Month should not change");
+                    assertEquals(result.get(woyField), woy, "Week of Year should not change");
+                }
+            }
+        }
+    }
+
+    @Test()
+    public void test_computedFieldResolver() {
+        // For all starting days of week, for all minDays, for two weeks in Dec 2012
+        // Test that when supplied with partial values, that the resolver
+        // fills in the month
+        for (DayOfWeek firstDayOfWeek : DayOfWeek.values()) {
+            for (int minDays = 1; minDays <= 7; minDays++) {
+                LocalDate day = LocalDate.of(2012, 12, 15);  // Safely in the middle of a month
+                WeekFields week = WeekFields.of(firstDayOfWeek, minDays);
+
+                TemporalField dowField = week.dayOfWeek();
+                TemporalField womField = week.weekOfMonth();
+                TemporalField woyField = week.weekOfYear();
+                int wom = day.get(womField);
+                int woy = day.get(woyField);
+                for (int dow = 1; dow <= 15; dow++) {
+                    // Test that with dayOfWeek and Week of month it computes the day of month
+                    DateTimeBuilder builder = new DateTimeBuilder();
+                    builder.addFieldValue(YEAR, day.get(YEAR));
+                    builder.addFieldValue(MONTH_OF_YEAR, day.get(MONTH_OF_YEAR));
+                    builder.addFieldValue(DAY_OF_WEEK, day.get(DAY_OF_WEEK));
+                    builder.addFieldValue(dowField, day.get(dowField));
+                    builder.addFieldValue(womField, day.get(womField));
+
+                    boolean res1 = dowField.resolve(builder, day.get(dowField));
+                    boolean res2 = womField.resolve(builder, day.get(womField));
+                    assertEquals(day.get(DAY_OF_MONTH), day.get(DAY_OF_MONTH));
+                    assertEquals(day.get(DAY_OF_YEAR), day.get(DAY_OF_YEAR));
+
+                    day = day.plusDays(1);
+                }
+                day = LocalDate.of(2012, 12, 15);  // Safely in the middle of a month
+                for (int dow = 1; dow <= 15; dow++) {
+                    // Test that with dayOfWeek and Week of year it computes the day of year
+                    DateTimeBuilder builder = new DateTimeBuilder();
+                    builder.addFieldValue(YEAR, day.get(YEAR));
+                    builder.addFieldValue(DAY_OF_WEEK, day.get(DAY_OF_WEEK));
+                    builder.addFieldValue(dowField, day.get(dowField));
+                    builder.addFieldValue(woyField, day.get(woyField));
+
+                    boolean res1 = dowField.resolve(builder, day.get(dowField));
+                    boolean res2 = woyField.resolve(builder, day.get(woyField));
+
+                    assertEquals(day.get(DAY_OF_MONTH), day.get(DAY_OF_MONTH));
+                    assertEquals(day.get(DAY_OF_YEAR), day.get(DAY_OF_YEAR));
+
+                    day = day.plusDays(1);
+                }
+            }
+        }
+    }
+
+    @Test(groups = {"tck"})
+    public void test_WeekFieldsSingleton() throws IOException, ClassNotFoundException {
+        for (DayOfWeek firstDayOfWeek : DayOfWeek.values()) {
+            for (int minDays = 1; minDays <= 7; minDays++) {
+                WeekFields weekDef = WeekFields.of(firstDayOfWeek, minDays);
+                WeekFields weekDef2 = WeekFields.of(firstDayOfWeek, minDays);
+                assertSame(weekDef2, weekDef, "WeekFields same parameters should be same instance");
+                try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                     ObjectOutputStream oos = new ObjectOutputStream(baos)) {
+                    oos.writeObject(weekDef);
+
+                    ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(
+                        baos.toByteArray()));
+                    WeekFields result = (WeekFields)ois.readObject();
+                    assertSame(result, weekDef, "Deserialized object same as serialized.");
+                }
+                // Exceptions will be handled as failures by TestNG
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/temporal/TCKYear.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,781 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.temporal;
+
+import static java.time.temporal.ChronoField.ERA;
+import static java.time.temporal.ChronoField.YEAR;
+import static java.time.temporal.ChronoField.YEAR_OF_ERA;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.Month;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatters;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.JulianFields;
+import java.time.temporal.MonthDay;
+import java.time.temporal.OffsetDateTime;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalField;
+import java.time.temporal.Year;
+import java.time.temporal.YearMonth;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import tck.java.time.AbstractDateTimeTest;
+
+/**
+ * Test Year.
+ */
+@Test
+public class TCKYear extends AbstractDateTimeTest {
+
+    private static final Year TEST_2008 = Year.of(2008);
+
+    @BeforeMethod
+    public void setUp() {
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    protected List<TemporalAccessor> samples() {
+        TemporalAccessor[] array = {TEST_2008, };
+        return Arrays.asList(array);
+    }
+
+    @Override
+    protected List<TemporalField> validFields() {
+        TemporalField[] array = {
+            YEAR_OF_ERA,
+            YEAR,
+            ERA,
+        };
+        return Arrays.asList(array);
+    }
+
+    @Override
+    protected List<TemporalField> invalidFields() {
+        List<TemporalField> list = new ArrayList<>(Arrays.<TemporalField>asList(ChronoField.values()));
+        list.removeAll(validFields());
+        list.add(JulianFields.JULIAN_DAY);
+        list.add(JulianFields.MODIFIED_JULIAN_DAY);
+        list.add(JulianFields.RATA_DIE);
+        return list;
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_serialization() throws Exception {
+        assertSerializable(Year.of(2));
+        assertSerializable(Year.of(0));
+        assertSerializable(Year.of(-2));
+    }
+
+    @Test
+    public void test_serialization_format() throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try (DataOutputStream dos = new DataOutputStream(baos) ) {
+            dos.writeByte(4);
+            dos.writeInt(2012);
+        }
+        byte[] bytes = baos.toByteArray();
+        assertSerializedBySer(Year.of(2012), bytes);
+    }
+
+    //-----------------------------------------------------------------------
+    // now()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void now() {
+        Year expected = Year.now(Clock.systemDefaultZone());
+        Year test = Year.now();
+        for (int i = 0; i < 100; i++) {
+            if (expected.equals(test)) {
+                return;
+            }
+            expected = Year.now(Clock.systemDefaultZone());
+            test = Year.now();
+        }
+        assertEquals(test, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // now(ZoneId)
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void now_ZoneId_nullZoneId() {
+        Year.now((ZoneId) null);
+    }
+
+    @Test(groups={"tck"})
+    public void now_ZoneId() {
+        ZoneId zone = ZoneId.of("UTC+01:02:03");
+        Year expected = Year.now(Clock.system(zone));
+        Year test = Year.now(zone);
+        for (int i = 0; i < 100; i++) {
+            if (expected.equals(test)) {
+                return;
+            }
+            expected = Year.now(Clock.system(zone));
+            test = Year.now(zone);
+        }
+        assertEquals(test, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // now(Clock)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void now_Clock() {
+        Instant instant = OffsetDateTime.of(LocalDate.of(2010, 12, 31), LocalTime.of(0, 0), ZoneOffset.UTC).toInstant();
+        Clock clock = Clock.fixed(instant, ZoneOffset.UTC);
+        Year test = Year.now(clock);
+        assertEquals(test.getValue(), 2010);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void now_Clock_nullClock() {
+        Year.now((Clock) null);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_factory_int_singleton() {
+        for (int i = -4; i <= 2104; i++) {
+            Year test = Year.of(i);
+            assertEquals(test.getValue(), i);
+            assertEquals(Year.of(i), test);
+        }
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_int_tooLow() {
+        Year.of(Year.MIN_VALUE - 1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_int_tooHigh() {
+        Year.of(Year.MAX_VALUE + 1);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_factory_CalendricalObject() {
+        assertEquals(Year.from(LocalDate.of(2007, 7, 15)), Year.of(2007));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_CalendricalObject_invalid_noDerive() {
+        Year.from(LocalTime.of(12, 30));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_factory_CalendricalObject_null() {
+        Year.from((TemporalAccessor) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // parse()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="goodParseData")
+    Object[][] provider_goodParseData() {
+        return new Object[][] {
+                {"0000", Year.of(0)},
+                {"9999", Year.of(9999)},
+                {"2000", Year.of(2000)},
+
+                {"+12345678", Year.of(12345678)},
+                {"+123456", Year.of(123456)},
+                {"-1234", Year.of(-1234)},
+                {"-12345678", Year.of(-12345678)},
+
+                {"+" + Year.MAX_VALUE, Year.of(Year.MAX_VALUE)},
+                {"" + Year.MIN_VALUE, Year.of(Year.MIN_VALUE)},
+        };
+    }
+
+    @Test(dataProvider="goodParseData", groups={"tck"})
+    public void factory_parse_success(String text, Year expected) {
+        Year year = Year.parse(text);
+        assertEquals(year, expected);
+    }
+
+    @DataProvider(name="badParseData")
+    Object[][] provider_badParseData() {
+        return new Object[][] {
+                {"", 0},
+                {"-00", 1},
+                {"--01-0", 1},
+                {"A01", 0},
+                {"200", 0},
+                {"2009/12", 4},
+
+                {"-0000-10", 0},
+                {"-12345678901-10", 11},
+                {"+1-10", 1},
+                {"+12-10", 1},
+                {"+123-10", 1},
+                {"+1234-10", 0},
+                {"12345-10", 0},
+                {"+12345678901-10", 11},
+        };
+    }
+
+    @Test(dataProvider="badParseData", expectedExceptions=DateTimeParseException.class, groups={"tck"})
+    public void factory_parse_fail(String text, int pos) {
+        try {
+            Year.parse(text);
+            fail(String.format("Parse should have failed for %s at position %d", text, pos));
+        } catch (DateTimeParseException ex) {
+            assertEquals(ex.getParsedString(), text);
+            assertEquals(ex.getErrorIndex(), pos);
+            throw ex;
+        }
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_parse_nullText() {
+        Year.parse(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // parse(DateTimeFormatter)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_parse_formatter() {
+        DateTimeFormatter f = DateTimeFormatters.pattern("y");
+        Year test = Year.parse("2010", f);
+        assertEquals(test, Year.of(2010));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_parse_formatter_nullText() {
+        DateTimeFormatter f = DateTimeFormatters.pattern("y");
+        Year.parse((String) null, f);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_parse_formatter_nullFormatter() {
+        Year.parse("ANY", null);
+    }
+
+    //-----------------------------------------------------------------------
+    // get(TemporalField)
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_get_TemporalField() {
+        assertEquals(TEST_2008.get(ChronoField.YEAR), 2008);
+        assertEquals(TEST_2008.get(ChronoField.YEAR_OF_ERA), 2008);
+        assertEquals(TEST_2008.get(ChronoField.ERA), 1);
+    }
+
+    @Test
+    public void test_getLong_TemporalField() {
+        assertEquals(TEST_2008.getLong(ChronoField.YEAR), 2008);
+        assertEquals(TEST_2008.getLong(ChronoField.YEAR_OF_ERA), 2008);
+        assertEquals(TEST_2008.getLong(ChronoField.ERA), 1);
+    }
+
+    //-----------------------------------------------------------------------
+    // isLeap()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_isLeap() {
+        assertEquals(Year.of(1999).isLeap(), false);
+        assertEquals(Year.of(2000).isLeap(), true);
+        assertEquals(Year.of(2001).isLeap(), false);
+
+        assertEquals(Year.of(2007).isLeap(), false);
+        assertEquals(Year.of(2008).isLeap(), true);
+        assertEquals(Year.of(2009).isLeap(), false);
+        assertEquals(Year.of(2010).isLeap(), false);
+        assertEquals(Year.of(2011).isLeap(), false);
+        assertEquals(Year.of(2012).isLeap(), true);
+
+        assertEquals(Year.of(2095).isLeap(), false);
+        assertEquals(Year.of(2096).isLeap(), true);
+        assertEquals(Year.of(2097).isLeap(), false);
+        assertEquals(Year.of(2098).isLeap(), false);
+        assertEquals(Year.of(2099).isLeap(), false);
+        assertEquals(Year.of(2100).isLeap(), false);
+        assertEquals(Year.of(2101).isLeap(), false);
+        assertEquals(Year.of(2102).isLeap(), false);
+        assertEquals(Year.of(2103).isLeap(), false);
+        assertEquals(Year.of(2104).isLeap(), true);
+        assertEquals(Year.of(2105).isLeap(), false);
+
+        assertEquals(Year.of(-500).isLeap(), false);
+        assertEquals(Year.of(-400).isLeap(), true);
+        assertEquals(Year.of(-300).isLeap(), false);
+        assertEquals(Year.of(-200).isLeap(), false);
+        assertEquals(Year.of(-100).isLeap(), false);
+        assertEquals(Year.of(0).isLeap(), true);
+        assertEquals(Year.of(100).isLeap(), false);
+        assertEquals(Year.of(200).isLeap(), false);
+        assertEquals(Year.of(300).isLeap(), false);
+        assertEquals(Year.of(400).isLeap(), true);
+        assertEquals(Year.of(500).isLeap(), false);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusYears()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusYears() {
+        assertEquals(Year.of(2007).plusYears(-1), Year.of(2006));
+        assertEquals(Year.of(2007).plusYears(0), Year.of(2007));
+        assertEquals(Year.of(2007).plusYears(1), Year.of(2008));
+        assertEquals(Year.of(2007).plusYears(2), Year.of(2009));
+
+        assertEquals(Year.of(Year.MAX_VALUE - 1).plusYears(1), Year.of(Year.MAX_VALUE));
+        assertEquals(Year.of(Year.MAX_VALUE).plusYears(0), Year.of(Year.MAX_VALUE));
+
+        assertEquals(Year.of(Year.MIN_VALUE + 1).plusYears(-1), Year.of(Year.MIN_VALUE));
+        assertEquals(Year.of(Year.MIN_VALUE).plusYears(0), Year.of(Year.MIN_VALUE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusYear_zero_equals() {
+        Year base = Year.of(2007);
+        assertEquals(base.plusYears(0), base);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusYears_big() {
+        long years = 20L + Year.MAX_VALUE;
+        assertEquals(Year.of(-40).plusYears(years), Year.of((int) (-40L + years)));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusYears_max() {
+        Year.of(Year.MAX_VALUE).plusYears(1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusYears_maxLots() {
+        Year.of(Year.MAX_VALUE).plusYears(1000);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusYears_min() {
+        Year.of(Year.MIN_VALUE).plusYears(-1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusYears_minLots() {
+        Year.of(Year.MIN_VALUE).plusYears(-1000);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusYears()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusYears() {
+        assertEquals(Year.of(2007).minusYears(-1), Year.of(2008));
+        assertEquals(Year.of(2007).minusYears(0), Year.of(2007));
+        assertEquals(Year.of(2007).minusYears(1), Year.of(2006));
+        assertEquals(Year.of(2007).minusYears(2), Year.of(2005));
+
+        assertEquals(Year.of(Year.MAX_VALUE - 1).minusYears(-1), Year.of(Year.MAX_VALUE));
+        assertEquals(Year.of(Year.MAX_VALUE).minusYears(0), Year.of(Year.MAX_VALUE));
+
+        assertEquals(Year.of(Year.MIN_VALUE + 1).minusYears(1), Year.of(Year.MIN_VALUE));
+        assertEquals(Year.of(Year.MIN_VALUE).minusYears(0), Year.of(Year.MIN_VALUE));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusYear_zero_equals() {
+        Year base = Year.of(2007);
+        assertEquals(base.minusYears(0), base);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusYears_big() {
+        long years = 20L + Year.MAX_VALUE;
+        assertEquals(Year.of(40).minusYears(years), Year.of((int) (40L - years)));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minusYears_max() {
+        Year.of(Year.MAX_VALUE).minusYears(-1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minusYears_maxLots() {
+        Year.of(Year.MAX_VALUE).minusYears(-1000);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minusYears_min() {
+        Year.of(Year.MIN_VALUE).minusYears(1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minusYears_minLots() {
+        Year.of(Year.MIN_VALUE).minusYears(1000);
+    }
+
+    //-----------------------------------------------------------------------
+    // adjustInto()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_adjustDate() {
+        LocalDate base = LocalDate.of(2007, 2, 12);
+        for (int i = -4; i <= 2104; i++) {
+            Temporal result = Year.of(i).adjustInto(base);
+            assertEquals(result, LocalDate.of(i, 2, 12));
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_adjustDate_resolve() {
+        Year test = Year.of(2011);
+        assertEquals(test.adjustInto(LocalDate.of(2012, 2, 29)), LocalDate.of(2011, 2, 28));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_adjustDate_nullLocalDate() {
+        Year test = Year.of(1);
+        test.adjustInto((LocalDate) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // length()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_length() {
+        assertEquals(Year.of(1999).length(), 365);
+        assertEquals(Year.of(2000).length(), 366);
+        assertEquals(Year.of(2001).length(), 365);
+
+        assertEquals(Year.of(2007).length(), 365);
+        assertEquals(Year.of(2008).length(), 366);
+        assertEquals(Year.of(2009).length(), 365);
+        assertEquals(Year.of(2010).length(), 365);
+        assertEquals(Year.of(2011).length(), 365);
+        assertEquals(Year.of(2012).length(), 366);
+
+        assertEquals(Year.of(2095).length(), 365);
+        assertEquals(Year.of(2096).length(), 366);
+        assertEquals(Year.of(2097).length(), 365);
+        assertEquals(Year.of(2098).length(), 365);
+        assertEquals(Year.of(2099).length(), 365);
+        assertEquals(Year.of(2100).length(), 365);
+        assertEquals(Year.of(2101).length(), 365);
+        assertEquals(Year.of(2102).length(), 365);
+        assertEquals(Year.of(2103).length(), 365);
+        assertEquals(Year.of(2104).length(), 366);
+        assertEquals(Year.of(2105).length(), 365);
+
+        assertEquals(Year.of(-500).length(), 365);
+        assertEquals(Year.of(-400).length(), 366);
+        assertEquals(Year.of(-300).length(), 365);
+        assertEquals(Year.of(-200).length(), 365);
+        assertEquals(Year.of(-100).length(), 365);
+        assertEquals(Year.of(0).length(), 366);
+        assertEquals(Year.of(100).length(), 365);
+        assertEquals(Year.of(200).length(), 365);
+        assertEquals(Year.of(300).length(), 365);
+        assertEquals(Year.of(400).length(), 366);
+        assertEquals(Year.of(500).length(), 365);
+    }
+
+    //-----------------------------------------------------------------------
+    // isValidMonthDay(Month)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_isValidMonthDay_june() {
+        Year test = Year.of(2007);
+        MonthDay monthDay = MonthDay.of(6, 30);
+        assertEquals(test.isValidMonthDay(monthDay), true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_isValidMonthDay_febNonLeap() {
+        Year test = Year.of(2007);
+        MonthDay monthDay = MonthDay.of(2, 29);
+        assertEquals(test.isValidMonthDay(monthDay), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_isValidMonthDay_febLeap() {
+        Year test = Year.of(2008);
+        MonthDay monthDay = MonthDay.of(2, 29);
+        assertEquals(test.isValidMonthDay(monthDay), true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_isValidMonthDay_null() {
+        Year test = Year.of(2008);
+        assertEquals(test.isValidMonthDay(null), false);
+    }
+
+    //-----------------------------------------------------------------------
+    // atMonth(Month)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_atMonth() {
+        Year test = Year.of(2008);
+        assertEquals(test.atMonth(Month.JUNE), YearMonth.of(2008, 6));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_atMonth_nullMonth() {
+        Year test = Year.of(2008);
+        test.atMonth((Month) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // atMonth(int)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_atMonth_int() {
+        Year test = Year.of(2008);
+        assertEquals(test.atMonth(6), YearMonth.of(2008, 6));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_atMonth_int_invalidMonth() {
+        Year test = Year.of(2008);
+        test.atMonth(13);
+    }
+
+    //-----------------------------------------------------------------------
+    // atMonthDay(Month)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_atMonthDay() {
+        Year test = Year.of(2008);
+        assertEquals(test.atMonthDay(MonthDay.of(6, 30)), LocalDate.of(2008, 6, 30));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_atMonthDay_nullMonthDay() {
+        Year test = Year.of(2008);
+        test.atMonthDay((MonthDay) null);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_atMonthDay_invalidMonthDay() {
+        Year test = Year.of(2008);
+        test.atMonthDay(MonthDay.of(6, 31));
+    }
+
+    //-----------------------------------------------------------------------
+    // atDay(int)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_atDay_notLeapYear() {
+        Year test = Year.of(2007);
+        LocalDate expected = LocalDate.of(2007, 1, 1);
+        for (int i = 1; i <= 365; i++) {
+            assertEquals(test.atDay(i), expected);
+            expected = expected.plusDays(1);
+        }
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_atDay_notLeapYear_day366() {
+        Year test = Year.of(2007);
+        test.atDay(366);
+    }
+
+    @Test(groups={"tck"})
+    public void test_atDay_leapYear() {
+        Year test = Year.of(2008);
+        LocalDate expected = LocalDate.of(2008, 1, 1);
+        for (int i = 1; i <= 366; i++) {
+            assertEquals(test.atDay(i), expected);
+            expected = expected.plusDays(1);
+        }
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_atDay_day0() {
+        Year test = Year.of(2007);
+        test.atDay(0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_atDay_day367() {
+        Year test = Year.of(2007);
+        test.atDay(367);
+    }
+
+    //-----------------------------------------------------------------------
+    // compareTo()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_compareTo() {
+        for (int i = -4; i <= 2104; i++) {
+            Year a = Year.of(i);
+            for (int j = -4; j <= 2104; j++) {
+                Year b = Year.of(j);
+                if (i < j) {
+                    assertEquals(a.compareTo(b) < 0, true);
+                    assertEquals(b.compareTo(a) > 0, true);
+                    assertEquals(a.isAfter(b), false);
+                    assertEquals(a.isBefore(b), true);
+                    assertEquals(b.isAfter(a), true);
+                    assertEquals(b.isBefore(a), false);
+                } else if (i > j) {
+                    assertEquals(a.compareTo(b) > 0, true);
+                    assertEquals(b.compareTo(a) < 0, true);
+                    assertEquals(a.isAfter(b), true);
+                    assertEquals(a.isBefore(b), false);
+                    assertEquals(b.isAfter(a), false);
+                    assertEquals(b.isBefore(a), true);
+                } else {
+                    assertEquals(a.compareTo(b), 0);
+                    assertEquals(b.compareTo(a), 0);
+                    assertEquals(a.isAfter(b), false);
+                    assertEquals(a.isBefore(b), false);
+                    assertEquals(b.isAfter(a), false);
+                    assertEquals(b.isBefore(a), false);
+                }
+            }
+        }
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_compareTo_nullYear() {
+        Year doy = null;
+        Year test = Year.of(1);
+        test.compareTo(doy);
+    }
+
+    //-----------------------------------------------------------------------
+    // equals() / hashCode()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_equals() {
+        for (int i = -4; i <= 2104; i++) {
+            Year a = Year.of(i);
+            for (int j = -4; j <= 2104; j++) {
+                Year b = Year.of(j);
+                assertEquals(a.equals(b), i == j);
+                assertEquals(a.hashCode() == b.hashCode(), i == j);
+            }
+        }
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_same() {
+        Year test = Year.of(2011);
+        assertEquals(test.equals(test), true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_nullYear() {
+        Year doy = null;
+        Year test = Year.of(1);
+        assertEquals(test.equals(doy), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_incorrectType() {
+        Year test = Year.of(1);
+        assertEquals(test.equals("Incorrect type"), false);
+    }
+
+    //-----------------------------------------------------------------------
+    // toString()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_toString() {
+        for (int i = -4; i <= 2104; i++) {
+            Year a = Year.of(i);
+            assertEquals(a.toString(), "" + i);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // toString(DateTimeFormatter)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_toString_formatter() {
+        DateTimeFormatter f = DateTimeFormatters.pattern("y");
+        String t = Year.of(2010).toString(f);
+        assertEquals(t, "2010");
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_toString_formatter_null() {
+        Year.of(2010).toString(null);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/temporal/TCKYearMonth.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,1046 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.temporal;
+
+import static java.time.temporal.ChronoField.EPOCH_MONTH;
+import static java.time.temporal.ChronoField.ERA;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.YEAR;
+import static java.time.temporal.ChronoField.YEAR_OF_ERA;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.Month;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatters;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.JulianFields;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalField;
+import java.time.temporal.Year;
+import java.time.temporal.YearMonth;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import tck.java.time.AbstractDateTimeTest;
+
+/**
+ * Test YearMonth.
+ */
+@Test
+public class TCKYearMonth extends AbstractDateTimeTest {
+
+    private YearMonth TEST_2008_06;
+
+    @BeforeMethod(groups={"tck", "implementation"})
+    public void setUp() {
+        TEST_2008_06 = YearMonth.of(2008, 6);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    protected List<TemporalAccessor> samples() {
+        TemporalAccessor[] array = {TEST_2008_06, };
+        return Arrays.asList(array);
+    }
+
+    @Override
+    protected List<TemporalField> validFields() {
+        TemporalField[] array = {
+            MONTH_OF_YEAR,
+            EPOCH_MONTH,
+            YEAR_OF_ERA,
+            YEAR,
+            ERA,
+        };
+        return Arrays.asList(array);
+    }
+
+    @Override
+    protected List<TemporalField> invalidFields() {
+        List<TemporalField> list = new ArrayList<>(Arrays.<TemporalField>asList(ChronoField.values()));
+        list.removeAll(validFields());
+        list.add(JulianFields.JULIAN_DAY);
+        list.add(JulianFields.MODIFIED_JULIAN_DAY);
+        list.add(JulianFields.RATA_DIE);
+        return list;
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_serialization() throws IOException, ClassNotFoundException {
+        assertSerializable(TEST_2008_06);
+    }
+
+    @Test
+    public void test_serialization_format() throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try (DataOutputStream dos = new DataOutputStream(baos) ) {
+            dos.writeByte(5);
+            dos.writeInt(2012);
+            dos.writeByte(9);
+        }
+        byte[] bytes = baos.toByteArray();
+        assertSerializedBySer(YearMonth.of(2012, 9), bytes);
+    }
+
+    //-----------------------------------------------------------------------
+    void check(YearMonth test, int y, int m) {
+        assertEquals(test.getYear(), y);
+        assertEquals(test.getMonth().getValue(), m);
+    }
+
+    //-----------------------------------------------------------------------
+    // now()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void now() {
+        YearMonth expected = YearMonth.now(Clock.systemDefaultZone());
+        YearMonth test = YearMonth.now();
+        for (int i = 0; i < 100; i++) {
+            if (expected.equals(test)) {
+                return;
+            }
+            expected = YearMonth.now(Clock.systemDefaultZone());
+            test = YearMonth.now();
+        }
+        assertEquals(test, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // now(ZoneId)
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void now_ZoneId_nullZoneId() {
+        YearMonth.now((ZoneId) null);
+    }
+
+    @Test(groups={"tck"})
+    public void now_ZoneId() {
+        ZoneId zone = ZoneId.of("UTC+01:02:03");
+        YearMonth expected = YearMonth.now(Clock.system(zone));
+        YearMonth test = YearMonth.now(zone);
+        for (int i = 0; i < 100; i++) {
+            if (expected.equals(test)) {
+                return;
+            }
+            expected = YearMonth.now(Clock.system(zone));
+            test = YearMonth.now(zone);
+        }
+        assertEquals(test, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // now(Clock)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void now_Clock() {
+        Instant instant = LocalDateTime.of(2010, 12, 31, 0, 0).toInstant(ZoneOffset.UTC);
+        Clock clock = Clock.fixed(instant, ZoneOffset.UTC);
+        YearMonth test = YearMonth.now(clock);
+        assertEquals(test.getYear(), 2010);
+        assertEquals(test.getMonth(), Month.DECEMBER);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void now_Clock_nullClock() {
+        YearMonth.now((Clock) null);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_intsMonth() {
+        YearMonth test = YearMonth.of(2008, Month.FEBRUARY);
+        check(test, 2008, 2);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_intsMonth_yearTooLow() {
+        YearMonth.of(Year.MIN_VALUE - 1, Month.JANUARY);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_intsMonth_dayTooHigh() {
+        YearMonth.of(Year.MAX_VALUE + 1, Month.JANUARY);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_intsMonth_nullMonth() {
+        YearMonth.of(2008, null);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_ints() {
+        YearMonth test = YearMonth.of(2008, 2);
+        check(test, 2008, 2);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_ints_yearTooLow() {
+        YearMonth.of(Year.MIN_VALUE - 1, 2);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_ints_dayTooHigh() {
+        YearMonth.of(Year.MAX_VALUE + 1, 2);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_ints_monthTooLow() {
+        YearMonth.of(2008, 0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_ints_monthTooHigh() {
+        YearMonth.of(2008, 13);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_factory_CalendricalObject() {
+        assertEquals(YearMonth.from(LocalDate.of(2007, 7, 15)), YearMonth.of(2007, 7));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_factory_CalendricalObject_invalid_noDerive() {
+        YearMonth.from(LocalTime.of(12, 30));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_factory_CalendricalObject_null() {
+        YearMonth.from((TemporalAccessor) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // parse()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="goodParseData")
+    Object[][] provider_goodParseData() {
+        return new Object[][] {
+                {"0000-01", YearMonth.of(0, 1)},
+                {"0000-12", YearMonth.of(0, 12)},
+                {"9999-12", YearMonth.of(9999, 12)},
+                {"2000-01", YearMonth.of(2000, 1)},
+                {"2000-02", YearMonth.of(2000, 2)},
+                {"2000-03", YearMonth.of(2000, 3)},
+                {"2000-04", YearMonth.of(2000, 4)},
+                {"2000-05", YearMonth.of(2000, 5)},
+                {"2000-06", YearMonth.of(2000, 6)},
+                {"2000-07", YearMonth.of(2000, 7)},
+                {"2000-08", YearMonth.of(2000, 8)},
+                {"2000-09", YearMonth.of(2000, 9)},
+                {"2000-10", YearMonth.of(2000, 10)},
+                {"2000-11", YearMonth.of(2000, 11)},
+                {"2000-12", YearMonth.of(2000, 12)},
+
+                {"+12345678-03", YearMonth.of(12345678, 3)},
+                {"+123456-03", YearMonth.of(123456, 3)},
+                {"0000-03", YearMonth.of(0, 3)},
+                {"-1234-03", YearMonth.of(-1234, 3)},
+                {"-12345678-03", YearMonth.of(-12345678, 3)},
+
+                {"+" + Year.MAX_VALUE + "-03", YearMonth.of(Year.MAX_VALUE, 3)},
+                {Year.MIN_VALUE + "-03", YearMonth.of(Year.MIN_VALUE, 3)},
+        };
+    }
+
+    @Test(dataProvider="goodParseData", groups={"tck"})
+    public void factory_parse_success(String text, YearMonth expected) {
+        YearMonth yearMonth = YearMonth.parse(text);
+        assertEquals(yearMonth, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="badParseData")
+    Object[][] provider_badParseData() {
+        return new Object[][] {
+                {"", 0},
+                {"-00", 1},
+                {"--01-0", 1},
+                {"A01-3", 0},
+                {"200-01", 0},
+                {"2009/12", 4},
+
+                {"-0000-10", 0},
+                {"-12345678901-10", 11},
+                {"+1-10", 1},
+                {"+12-10", 1},
+                {"+123-10", 1},
+                {"+1234-10", 0},
+                {"12345-10", 0},
+                {"+12345678901-10", 11},
+        };
+    }
+
+    @Test(dataProvider="badParseData", expectedExceptions=DateTimeParseException.class, groups={"tck"})
+    public void factory_parse_fail(String text, int pos) {
+        try {
+            YearMonth.parse(text);
+            fail(String.format("Parse should have failed for %s at position %d", text, pos));
+        } catch (DateTimeParseException ex) {
+            assertEquals(ex.getParsedString(), text);
+            assertEquals(ex.getErrorIndex(), pos);
+            throw ex;
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"})
+    public void factory_parse_illegalValue_Month() {
+        YearMonth.parse("2008-13");
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_parse_nullText() {
+        YearMonth.parse(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // parse(DateTimeFormatter)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void factory_parse_formatter() {
+        DateTimeFormatter f = DateTimeFormatters.pattern("y M");
+        YearMonth test = YearMonth.parse("2010 12", f);
+        assertEquals(test, YearMonth.of(2010, 12));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_parse_formatter_nullText() {
+        DateTimeFormatter f = DateTimeFormatters.pattern("y M");
+        YearMonth.parse((String) null, f);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void factory_parse_formatter_nullFormatter() {
+        YearMonth.parse("ANY", null);
+    }
+
+    //-----------------------------------------------------------------------
+    // get(TemporalField)
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_get_TemporalField() {
+        assertEquals(TEST_2008_06.get(ChronoField.YEAR), 2008);
+        assertEquals(TEST_2008_06.get(ChronoField.MONTH_OF_YEAR), 6);
+        assertEquals(TEST_2008_06.get(ChronoField.YEAR_OF_ERA), 2008);
+        assertEquals(TEST_2008_06.get(ChronoField.ERA), 1);
+    }
+
+    @Test
+    public void test_getLong_TemporalField() {
+        assertEquals(TEST_2008_06.getLong(ChronoField.YEAR), 2008);
+        assertEquals(TEST_2008_06.getLong(ChronoField.MONTH_OF_YEAR), 6);
+        assertEquals(TEST_2008_06.getLong(ChronoField.YEAR_OF_ERA), 2008);
+        assertEquals(TEST_2008_06.getLong(ChronoField.ERA), 1);
+        assertEquals(TEST_2008_06.getLong(ChronoField.EPOCH_MONTH), (2008 - 1970) * 12 + 6 - 1);
+    }
+
+    //-----------------------------------------------------------------------
+    // get*()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sampleDates")
+    Object[][] provider_sampleDates() {
+        return new Object[][] {
+            {2008, 1},
+            {2008, 2},
+            {-1, 3},
+            {0, 12},
+        };
+    }
+
+    //-----------------------------------------------------------------------
+    // with(Year)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_with_Year() {
+        YearMonth test = YearMonth.of(2008, 6);
+        assertEquals(test.with(Year.of(2000)), YearMonth.of(2000, 6));
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_Year_noChange_equal() {
+        YearMonth test = YearMonth.of(2008, 6);
+        assertEquals(test.with(Year.of(2008)), test);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_with_Year_null() {
+        YearMonth test = YearMonth.of(2008, 6);
+        test.with((Year) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // with(Month)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_with_Month() {
+        YearMonth test = YearMonth.of(2008, 6);
+        assertEquals(test.with(Month.JANUARY), YearMonth.of(2008, 1));
+    }
+
+    @Test(groups={"tck"})
+    public void test_with_Month_noChange_equal() {
+        YearMonth test = YearMonth.of(2008, 6);
+        assertEquals(test.with(Month.JUNE), test);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_with_Month_null() {
+        YearMonth test = YearMonth.of(2008, 6);
+        test.with((Month) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // withYear()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withYear() {
+        YearMonth test = YearMonth.of(2008, 6);
+        assertEquals(test.withYear(1999), YearMonth.of(1999, 6));
+    }
+
+    @Test(groups={"tck"})
+    public void test_withYear_int_noChange_equal() {
+        YearMonth test = YearMonth.of(2008, 6);
+        assertEquals(test.withYear(2008), test);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withYear_tooLow() {
+        YearMonth test = YearMonth.of(2008, 6);
+        test.withYear(Year.MIN_VALUE - 1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withYear_tooHigh() {
+        YearMonth test = YearMonth.of(2008, 6);
+        test.withYear(Year.MAX_VALUE + 1);
+    }
+
+    //-----------------------------------------------------------------------
+    // withMonth()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_withMonth() {
+        YearMonth test = YearMonth.of(2008, 6);
+        assertEquals(test.withMonth(1), YearMonth.of(2008, 1));
+    }
+
+    @Test(groups={"tck"})
+    public void test_withMonth_int_noChange_equal() {
+        YearMonth test = YearMonth.of(2008, 6);
+        assertEquals(test.withMonth(6), test);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withMonth_tooLow() {
+        YearMonth test = YearMonth.of(2008, 6);
+        test.withMonth(0);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_withMonth_tooHigh() {
+        YearMonth test = YearMonth.of(2008, 6);
+        test.withMonth(13);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusYears()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusYears_long() {
+        YearMonth test = YearMonth.of(2008, 6);
+        assertEquals(test.plusYears(1), YearMonth.of(2009, 6));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusYears_long_noChange_equal() {
+        YearMonth test = YearMonth.of(2008, 6);
+        assertEquals(test.plusYears(0), test);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusYears_long_negative() {
+        YearMonth test = YearMonth.of(2008, 6);
+        assertEquals(test.plusYears(-1), YearMonth.of(2007, 6));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusYears_long_big() {
+        YearMonth test = YearMonth.of(-40, 6);
+        assertEquals(test.plusYears(20L + Year.MAX_VALUE), YearMonth.of((int) (-40L + 20L + Year.MAX_VALUE), 6));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusYears_long_invalidTooLarge() {
+        YearMonth test = YearMonth.of(Year.MAX_VALUE, 6);
+        test.plusYears(1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusYears_long_invalidTooLargeMaxAddMax() {
+        YearMonth test = YearMonth.of(Year.MAX_VALUE, 12);
+        test.plusYears(Long.MAX_VALUE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusYears_long_invalidTooLargeMaxAddMin() {
+        YearMonth test = YearMonth.of(Year.MAX_VALUE, 12);
+        test.plusYears(Long.MIN_VALUE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusYears_long_invalidTooSmall() {
+        YearMonth test = YearMonth.of(Year.MIN_VALUE, 6);
+        test.plusYears(-1);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusMonths()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_plusMonths_long() {
+        YearMonth test = YearMonth.of(2008, 6);
+        assertEquals(test.plusMonths(1), YearMonth.of(2008, 7));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMonths_long_noChange_equal() {
+        YearMonth test = YearMonth.of(2008, 6);
+        assertEquals(test.plusMonths(0), test);
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMonths_long_overYears() {
+        YearMonth test = YearMonth.of(2008, 6);
+        assertEquals(test.plusMonths(7), YearMonth.of(2009, 1));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMonths_long_negative() {
+        YearMonth test = YearMonth.of(2008, 6);
+        assertEquals(test.plusMonths(-1), YearMonth.of(2008, 5));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMonths_long_negativeOverYear() {
+        YearMonth test = YearMonth.of(2008, 6);
+        assertEquals(test.plusMonths(-6), YearMonth.of(2007, 12));
+    }
+
+    @Test(groups={"tck"})
+    public void test_plusMonths_long_big() {
+        YearMonth test = YearMonth.of(-40, 6);
+        long months = 20L + Integer.MAX_VALUE;
+        assertEquals(test.plusMonths(months), YearMonth.of((int) (-40L + months / 12), 6 + (int) (months % 12)));
+    }
+
+    @Test(expectedExceptions={DateTimeException.class}, groups={"tck"})
+    public void test_plusMonths_long_invalidTooLarge() {
+        YearMonth test = YearMonth.of(Year.MAX_VALUE, 12);
+        test.plusMonths(1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusMonths_long_invalidTooLargeMaxAddMax() {
+        YearMonth test = YearMonth.of(Year.MAX_VALUE, 12);
+        test.plusMonths(Long.MAX_VALUE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_plusMonths_long_invalidTooLargeMaxAddMin() {
+        YearMonth test = YearMonth.of(Year.MAX_VALUE, 12);
+        test.plusMonths(Long.MIN_VALUE);
+    }
+
+    @Test(expectedExceptions={DateTimeException.class}, groups={"tck"})
+    public void test_plusMonths_long_invalidTooSmall() {
+        YearMonth test = YearMonth.of(Year.MIN_VALUE, 1);
+        test.plusMonths(-1);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusYears()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusYears_long() {
+        YearMonth test = YearMonth.of(2008, 6);
+        assertEquals(test.minusYears(1), YearMonth.of(2007, 6));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusYears_long_noChange_equal() {
+        YearMonth test = YearMonth.of(2008, 6);
+        assertEquals(test.minusYears(0), test);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusYears_long_negative() {
+        YearMonth test = YearMonth.of(2008, 6);
+        assertEquals(test.minusYears(-1), YearMonth.of(2009, 6));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusYears_long_big() {
+        YearMonth test = YearMonth.of(40, 6);
+        assertEquals(test.minusYears(20L + Year.MAX_VALUE), YearMonth.of((int) (40L - 20L - Year.MAX_VALUE), 6));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minusYears_long_invalidTooLarge() {
+        YearMonth test = YearMonth.of(Year.MAX_VALUE, 6);
+        test.minusYears(-1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minusYears_long_invalidTooLargeMaxSubtractMax() {
+        YearMonth test = YearMonth.of(Year.MIN_VALUE, 12);
+        test.minusYears(Long.MAX_VALUE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minusYears_long_invalidTooLargeMaxSubtractMin() {
+        YearMonth test = YearMonth.of(Year.MIN_VALUE, 12);
+        test.minusYears(Long.MIN_VALUE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minusYears_long_invalidTooSmall() {
+        YearMonth test = YearMonth.of(Year.MIN_VALUE, 6);
+        test.minusYears(1);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusMonths()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_minusMonths_long() {
+        YearMonth test = YearMonth.of(2008, 6);
+        assertEquals(test.minusMonths(1), YearMonth.of(2008, 5));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMonths_long_noChange_equal() {
+        YearMonth test = YearMonth.of(2008, 6);
+        assertEquals(test.minusMonths(0), test);
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMonths_long_overYears() {
+        YearMonth test = YearMonth.of(2008, 6);
+        assertEquals(test.minusMonths(6), YearMonth.of(2007, 12));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMonths_long_negative() {
+        YearMonth test = YearMonth.of(2008, 6);
+        assertEquals(test.minusMonths(-1), YearMonth.of(2008, 7));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMonths_long_negativeOverYear() {
+        YearMonth test = YearMonth.of(2008, 6);
+        assertEquals(test.minusMonths(-7), YearMonth.of(2009, 1));
+    }
+
+    @Test(groups={"tck"})
+    public void test_minusMonths_long_big() {
+        YearMonth test = YearMonth.of(40, 6);
+        long months = 20L + Integer.MAX_VALUE;
+        assertEquals(test.minusMonths(months), YearMonth.of((int) (40L - months / 12), 6 - (int) (months % 12)));
+    }
+
+    @Test(expectedExceptions={DateTimeException.class}, groups={"tck"})
+    public void test_minusMonths_long_invalidTooLarge() {
+        YearMonth test = YearMonth.of(Year.MAX_VALUE, 12);
+        test.minusMonths(-1);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minusMonths_long_invalidTooLargeMaxSubtractMax() {
+        YearMonth test = YearMonth.of(Year.MAX_VALUE, 12);
+        test.minusMonths(Long.MAX_VALUE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_minusMonths_long_invalidTooLargeMaxSubtractMin() {
+        YearMonth test = YearMonth.of(Year.MAX_VALUE, 12);
+        test.minusMonths(Long.MIN_VALUE);
+    }
+
+    @Test(expectedExceptions={DateTimeException.class}, groups={"tck"})
+    public void test_minusMonths_long_invalidTooSmall() {
+        YearMonth test = YearMonth.of(Year.MIN_VALUE, 1);
+        test.minusMonths(1);
+    }
+
+    //-----------------------------------------------------------------------
+    // adjustInto()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_adjustDate() {
+        YearMonth test = YearMonth.of(2008, 6);
+        LocalDate date = LocalDate.of(2007, 1, 1);
+        assertEquals(test.adjustInto(date), LocalDate.of(2008, 6, 1));
+    }
+
+    @Test(groups={"tck"})
+    public void test_adjustDate_preserveDoM() {
+        YearMonth test = YearMonth.of(2011, 3);
+        LocalDate date = LocalDate.of(2008, 2, 29);
+        assertEquals(test.adjustInto(date), LocalDate.of(2011, 3, 29));
+    }
+
+    @Test(groups={"tck"})
+    public void test_adjustDate_resolve() {
+        YearMonth test = YearMonth.of(2007, 2);
+        LocalDate date = LocalDate.of(2008, 3, 31);
+        assertEquals(test.adjustInto(date), LocalDate.of(2007, 2, 28));
+    }
+
+    @Test(groups={"tck"})
+    public void test_adjustDate_equal() {
+        YearMonth test = YearMonth.of(2008, 6);
+        LocalDate date = LocalDate.of(2008, 6, 30);
+        assertEquals(test.adjustInto(date), date);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_adjustDate_null() {
+        TEST_2008_06.adjustInto((LocalDate) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // isLeapYear()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_isLeapYear() {
+        assertEquals(YearMonth.of(2007, 6).isLeapYear(), false);
+        assertEquals(YearMonth.of(2008, 6).isLeapYear(), true);
+    }
+
+    //-----------------------------------------------------------------------
+    // lengthOfMonth()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_lengthOfMonth_june() {
+        YearMonth test = YearMonth.of(2007, 6);
+        assertEquals(test.lengthOfMonth(), 30);
+    }
+
+    @Test(groups={"tck"})
+    public void test_lengthOfMonth_febNonLeap() {
+        YearMonth test = YearMonth.of(2007, 2);
+        assertEquals(test.lengthOfMonth(), 28);
+    }
+
+    @Test(groups={"tck"})
+    public void test_lengthOfMonth_febLeap() {
+        YearMonth test = YearMonth.of(2008, 2);
+        assertEquals(test.lengthOfMonth(), 29);
+    }
+
+    //-----------------------------------------------------------------------
+    // lengthOfYear()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_lengthOfYear() {
+        assertEquals(YearMonth.of(2007, 6).lengthOfYear(), 365);
+        assertEquals(YearMonth.of(2008, 6).lengthOfYear(), 366);
+    }
+
+    //-----------------------------------------------------------------------
+    // isValidDay(int)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_isValidDay_int_june() {
+        YearMonth test = YearMonth.of(2007, 6);
+        assertEquals(test.isValidDay(1), true);
+        assertEquals(test.isValidDay(30), true);
+
+        assertEquals(test.isValidDay(-1), false);
+        assertEquals(test.isValidDay(0), false);
+        assertEquals(test.isValidDay(31), false);
+        assertEquals(test.isValidDay(32), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_isValidDay_int_febNonLeap() {
+        YearMonth test = YearMonth.of(2007, 2);
+        assertEquals(test.isValidDay(1), true);
+        assertEquals(test.isValidDay(28), true);
+
+        assertEquals(test.isValidDay(-1), false);
+        assertEquals(test.isValidDay(0), false);
+        assertEquals(test.isValidDay(29), false);
+        assertEquals(test.isValidDay(32), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_isValidDay_int_febLeap() {
+        YearMonth test = YearMonth.of(2008, 2);
+        assertEquals(test.isValidDay(1), true);
+        assertEquals(test.isValidDay(29), true);
+
+        assertEquals(test.isValidDay(-1), false);
+        assertEquals(test.isValidDay(0), false);
+        assertEquals(test.isValidDay(30), false);
+        assertEquals(test.isValidDay(32), false);
+    }
+
+    //-----------------------------------------------------------------------
+    // atDay(int)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_atDay_int() {
+        YearMonth test = YearMonth.of(2008, 6);
+        assertEquals(test.atDay(30), LocalDate.of(2008, 6, 30));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
+    public void test_atDay_int_invalidDay() {
+        YearMonth test = YearMonth.of(2008, 6);
+        test.atDay(31);
+    }
+
+    //-----------------------------------------------------------------------
+    // compareTo()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_comparisons() {
+        doTest_comparisons_YearMonth(
+            YearMonth.of(-1, 1),
+            YearMonth.of(0, 1),
+            YearMonth.of(0, 12),
+            YearMonth.of(1, 1),
+            YearMonth.of(1, 2),
+            YearMonth.of(1, 12),
+            YearMonth.of(2008, 1),
+            YearMonth.of(2008, 6),
+            YearMonth.of(2008, 12)
+        );
+    }
+
+    void doTest_comparisons_YearMonth(YearMonth... localDates) {
+        for (int i = 0; i < localDates.length; i++) {
+            YearMonth a = localDates[i];
+            for (int j = 0; j < localDates.length; j++) {
+                YearMonth b = localDates[j];
+                if (i < j) {
+                    assertTrue(a.compareTo(b) < 0, a + " <=> " + b);
+                    assertEquals(a.isBefore(b), true, a + " <=> " + b);
+                    assertEquals(a.isAfter(b), false, a + " <=> " + b);
+                    assertEquals(a.equals(b), false, a + " <=> " + b);
+                } else if (i > j) {
+                    assertTrue(a.compareTo(b) > 0, a + " <=> " + b);
+                    assertEquals(a.isBefore(b), false, a + " <=> " + b);
+                    assertEquals(a.isAfter(b), true, a + " <=> " + b);
+                    assertEquals(a.equals(b), false, a + " <=> " + b);
+                } else {
+                    assertEquals(a.compareTo(b), 0, a + " <=> " + b);
+                    assertEquals(a.isBefore(b), false, a + " <=> " + b);
+                    assertEquals(a.isAfter(b), false, a + " <=> " + b);
+                    assertEquals(a.equals(b), true, a + " <=> " + b);
+                }
+            }
+        }
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_compareTo_ObjectNull() {
+        TEST_2008_06.compareTo(null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_isBefore_ObjectNull() {
+        TEST_2008_06.isBefore(null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_isAfter_ObjectNull() {
+        TEST_2008_06.isAfter(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // equals()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_equals() {
+        YearMonth a = YearMonth.of(2008, 6);
+        YearMonth b = YearMonth.of(2008, 6);
+        YearMonth c = YearMonth.of(2007, 6);
+        YearMonth d = YearMonth.of(2008, 5);
+
+        assertEquals(a.equals(a), true);
+        assertEquals(a.equals(b), true);
+        assertEquals(a.equals(c), false);
+        assertEquals(a.equals(d), false);
+
+        assertEquals(b.equals(a), true);
+        assertEquals(b.equals(b), true);
+        assertEquals(b.equals(c), false);
+        assertEquals(b.equals(d), false);
+
+        assertEquals(c.equals(a), false);
+        assertEquals(c.equals(b), false);
+        assertEquals(c.equals(c), true);
+        assertEquals(c.equals(d), false);
+
+        assertEquals(d.equals(a), false);
+        assertEquals(d.equals(b), false);
+        assertEquals(d.equals(c), false);
+        assertEquals(d.equals(d), true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_itself_true() {
+        assertEquals(TEST_2008_06.equals(TEST_2008_06), true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_string_false() {
+        assertEquals(TEST_2008_06.equals("2007-07-15"), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_null_false() {
+        assertEquals(TEST_2008_06.equals(null), false);
+    }
+
+    //-----------------------------------------------------------------------
+    // hashCode()
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="sampleDates", groups={"tck"})
+    public void test_hashCode(int y, int m) {
+        YearMonth a = YearMonth.of(y, m);
+        assertEquals(a.hashCode(), a.hashCode());
+        YearMonth b = YearMonth.of(y, m);
+        assertEquals(a.hashCode(), b.hashCode());
+    }
+
+    @Test(groups={"tck"})
+    public void test_hashCode_unique() {
+        Set<Integer> uniques = new HashSet<Integer>(201 * 12);
+        for (int i = 1900; i <= 2100; i++) {
+            for (int j = 1; j <= 12; j++) {
+                assertTrue(uniques.add(YearMonth.of(i, j).hashCode()));
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // toString()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sampleToString")
+    Object[][] provider_sampleToString() {
+        return new Object[][] {
+            {2008, 1, "2008-01"},
+            {2008, 12, "2008-12"},
+            {7, 5, "0007-05"},
+            {0, 5, "0000-05"},
+            {-1, 1, "-0001-01"},
+        };
+    }
+
+    @Test(dataProvider="sampleToString", groups={"tck"})
+    public void test_toString(int y, int m, String expected) {
+        YearMonth test = YearMonth.of(y, m);
+        String str = test.toString();
+        assertEquals(str, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // toString(DateTimeFormatter)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_toString_formatter() {
+        DateTimeFormatter f = DateTimeFormatters.pattern("y M");
+        String t = YearMonth.of(2010, 12).toString(f);
+        assertEquals(t, "2010 12");
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_toString_formatter_null() {
+        YearMonth.of(2010, 12).toString(null);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/temporal/TestChrono.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.temporal;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Locale;
+import java.util.Set;
+
+import java.time.temporal.Chrono;
+import java.time.temporal.ChronoField;
+import java.time.calendar.HijrahChrono;
+import java.time.calendar.JapaneseChrono;
+import java.time.calendar.MinguoChrono;
+import java.time.calendar.ThaiBuddhistChrono;
+import java.time.temporal.ChronoLocalDate;
+import java.time.temporal.ISOChrono;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test Chrono class.
+ */
+@Test
+public class TestChrono {
+
+    @BeforeMethod(groups="tck")
+    public void setUp() {
+        // Ensure each of the classes are initialized (until initialization is fixed)
+        Chrono<?> c;
+        c = HijrahChrono.INSTANCE;
+        c = ISOChrono.INSTANCE;
+        c = JapaneseChrono.INSTANCE;
+        c = MinguoChrono.INSTANCE;
+        c = ThaiBuddhistChrono.INSTANCE;
+        c.toString();  // avoids variable being marked as unused
+    }
+
+    //-----------------------------------------------------------------------
+    // regular data factory for names and descriptions of available calendars
+    //-----------------------------------------------------------------------
+    @DataProvider(name = "calendars")
+    Object[][] data_of_calendars() {
+        return new Object[][] {
+                    {"Hijrah", "islamicc", "Hijrah calendar"},
+                    {"ISO", "iso8601", "ISO calendar"},
+                    {"Japanese", "japanese", "Japanese calendar"},
+                    {"Minguo", "roc", "Minguo Calendar"},
+                    {"ThaiBuddhist", "buddhist", "ThaiBuddhist calendar"},
+                };
+    }
+
+    @Test(dataProvider = "calendars")
+    public void test_getters(String chronoId, String calendarSystemType, String description) {
+        Chrono<?> chrono = Chrono.of(chronoId);
+        assertNotNull(chrono, "Required calendar not found by ID: " + chronoId);
+        assertEquals(chrono.getId(), chronoId);
+        assertEquals(chrono.getCalendarType(), calendarSystemType);
+    }
+
+    @Test(dataProvider = "calendars")
+    public void test_required_calendars(String chronoId, String calendarSystemType, String description) {
+        Chrono<?> chrono = Chrono.of(chronoId);
+        assertNotNull(chrono, "Required calendar not found by ID: " + chronoId);
+        chrono = Chrono.of(calendarSystemType);
+        assertNotNull(chrono, "Required calendar not found by type: " + chronoId);
+        Set<Chrono<?>> cals = Chrono.getAvailableChronologies();
+        assertTrue(cals.contains(chrono), "Required calendar not found in set of available calendars");
+    }
+
+    @Test(groups="tck")
+    public void test_calendar_list() {
+        Set<Chrono<?>> chronos = Chrono.getAvailableChronologies();
+        assertNotNull(chronos, "Required list of calendars must be non-null");
+        for (Chrono<?> chrono : chronos) {
+            Chrono<?> lookup = Chrono.of(chrono.getId());
+            assertNotNull(lookup, "Required calendar not found: " + chrono);
+        }
+        assertEquals(chronos.size() >= data_of_calendars().length, true, "Chrono.getAvailableChronologies().size = " + chronos.size()
+                + ", expected >= " + data_of_calendars().length);
+    }
+
+    /**
+     * Compute the number of days from the Epoch and compute the date from the number of days.
+     */
+    @Test(dataProvider = "calendars", groups="tck")
+    public void test_epoch(String name, String alias, String description) {
+        Chrono<?> chrono = Chrono.of(name); // a chronology. In practice this is rarely hardcoded
+        ChronoLocalDate<?> date1 = chrono.dateNow();
+        long epoch1 = date1.getLong(ChronoField.EPOCH_DAY);
+        ChronoLocalDate<?> date2 = date1.with(ChronoField.EPOCH_DAY, epoch1);
+        assertEquals(date1, date2, "Date from epoch day is not same date: " + date1 + " != " + date2);
+        long epoch2 = date1.getLong(ChronoField.EPOCH_DAY);
+        assertEquals(epoch1, epoch2, "Epoch day not the same: " + epoch1 + " != " + epoch2);
+    }
+
+    //-----------------------------------------------------------------------
+    // locale based lookup
+    //-----------------------------------------------------------------------
+    @DataProvider(name = "calendarsystemtype")
+    Object[][] data_CalendarType() {
+        return new Object[][] {
+            {HijrahChrono.INSTANCE, "islamicc"},
+            {ISOChrono.INSTANCE, "iso8601"},
+            {JapaneseChrono.INSTANCE, "japanese"},
+            {MinguoChrono.INSTANCE, "roc"},
+            {ThaiBuddhistChrono.INSTANCE, "buddhist"},
+        };
+    }
+
+    @Test(dataProvider = "calendarsystemtype", groups="tck")
+    public void test_getCalendarType(Chrono<?> chrono, String calendarType) {
+        assertEquals(chrono.getCalendarType(), calendarType);
+    }
+
+    @Test(dataProvider = "calendarsystemtype", groups="tck")
+    public void test_lookupLocale(Chrono<?> chrono, String calendarType) {
+        Locale locale = new Locale.Builder().setLanguage("en").setRegion("CA").setUnicodeLocaleKeyword("ca", calendarType).build();
+        assertEquals(Chrono.ofLocale(locale), chrono);
+    }
+
+
+    //-----------------------------------------------------------------------
+    // serialization; serialize and check each calendar system
+    //-----------------------------------------------------------------------
+    @Test(groups={"implementation"}, dataProvider = "calendarsystemtype")
+    public <C extends Chrono<C>> void test_chronoSerializationSingleton(C chrono, String calendarType) throws Exception {
+        C orginal = chrono;
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream(baos);
+        out.writeObject(orginal);
+        out.close();
+        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+        ObjectInputStream in = new ObjectInputStream(bais);
+        @SuppressWarnings("unchecked")
+        C ser = (C) in.readObject();
+        assertSame(ser, chrono, "Deserialized Chrono is not the singleton serialized");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/temporal/TestChronoLocalDate.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,503 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.temporal;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import java.time.Duration;
+import java.time.LocalDate;
+import java.time.temporal.Chrono;
+import java.time.temporal.ChronoLocalDate;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.SimplePeriod;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.format.DateTimeBuilder;
+import java.time.temporal.TemporalAdder;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalSubtractor;
+import java.time.temporal.ValueRange;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.ISOChrono;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test assertions that must be true for the built-in ISO chronology.
+ */
+@Test
+public class TestChronoLocalDate {
+
+    //-----------------------------------------------------------------------
+    // regular data factory for names and descriptions of ISO calendar
+    //-----------------------------------------------------------------------
+    @DataProvider(name = "calendars")
+    Chrono<?>[][] data_of_calendars() {
+        return new Chrono[][]{
+            {ISOChrono.INSTANCE},
+        };
+    }
+
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_badWithAdjusterChrono(Chrono<?> chrono) {
+        LocalDate refDate = LocalDate.of(1900, 1, 1);
+        ChronoLocalDate<?> date = chrono.date(refDate);
+        for (Chrono<?>[] clist : data_of_calendars()) {
+            Chrono<?> chrono2 = clist[0];
+            ChronoLocalDate<?> date2 = chrono2.date(refDate);
+            TemporalAdjuster adjuster = new FixedAdjuster(date2);
+            if (chrono != chrono2) {
+                try {
+                    date.with(adjuster);
+                    Assert.fail("WithAdjuster should have thrown a ClassCastException");
+                } catch (ClassCastException cce) {
+                    // Expected exception; not an error
+                }
+            } else {
+                // Same chronology,
+                ChronoLocalDate<?> result = date.with(adjuster);
+                assertEquals(result, date2, "WithAdjuster failed to replace date");
+            }
+        }
+    }
+
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_badPlusAdjusterChrono(Chrono<?> chrono) {
+        LocalDate refDate = LocalDate.of(1900, 1, 1);
+        ChronoLocalDate<?> date = chrono.date(refDate);
+        for (Chrono<?>[] clist : data_of_calendars()) {
+            Chrono<?> chrono2 = clist[0];
+            ChronoLocalDate<?> date2 = chrono2.date(refDate);
+            TemporalAdder adjuster = new FixedAdjuster(date2);
+            if (chrono != chrono2) {
+                try {
+                    date.plus(adjuster);
+                    Assert.fail("WithAdjuster should have thrown a ClassCastException");
+                } catch (ClassCastException cce) {
+                    // Expected exception; not an error
+                }
+            } else {
+                // Same chronology,
+                ChronoLocalDate<?> result = date.plus(adjuster);
+                assertEquals(result, date2, "WithAdjuster failed to replace date");
+            }
+        }
+    }
+
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_badMinusAdjusterChrono(Chrono<?> chrono) {
+        LocalDate refDate = LocalDate.of(1900, 1, 1);
+        ChronoLocalDate<?> date = chrono.date(refDate);
+        for (Chrono<?>[] clist : data_of_calendars()) {
+            Chrono<?> chrono2 = clist[0];
+            ChronoLocalDate<?> date2 = chrono2.date(refDate);
+            TemporalSubtractor adjuster = new FixedAdjuster(date2);
+            if (chrono != chrono2) {
+                try {
+                    date.minus(adjuster);
+                    Assert.fail("WithAdjuster should have thrown a ClassCastException");
+                } catch (ClassCastException cce) {
+                    // Expected exception; not an error
+                }
+            } else {
+                // Same chronology,
+                ChronoLocalDate<?> result = date.minus(adjuster);
+                assertEquals(result, date2, "WithAdjuster failed to replace date");
+            }
+        }
+    }
+
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_badPlusTemporalUnitChrono(Chrono<?> chrono) {
+        LocalDate refDate = LocalDate.of(1900, 1, 1);
+        ChronoLocalDate<?> date = chrono.date(refDate);
+        for (Chrono<?>[] clist : data_of_calendars()) {
+            Chrono<?> chrono2 = clist[0];
+            ChronoLocalDate<?> date2 = chrono2.date(refDate);
+            TemporalUnit adjuster = new FixedTemporalUnit(date2);
+            if (chrono != chrono2) {
+                try {
+                    date.plus(1, adjuster);
+                    Assert.fail("TemporalUnit.doPlus plus should have thrown a ClassCastException" + date.getClass()
+                            + ", can not be cast to " + date2.getClass());
+                } catch (ClassCastException cce) {
+                    // Expected exception; not an error
+                }
+            } else {
+                // Same chronology,
+                ChronoLocalDate<?> result = date.plus(1, adjuster);
+                assertEquals(result, date2, "WithAdjuster failed to replace date");
+            }
+        }
+    }
+
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_badMinusTemporalUnitChrono(Chrono<?> chrono) {
+        LocalDate refDate = LocalDate.of(1900, 1, 1);
+        ChronoLocalDate<?> date = chrono.date(refDate);
+        for (Chrono<?>[] clist : data_of_calendars()) {
+            Chrono<?> chrono2 = clist[0];
+            ChronoLocalDate<?> date2 = chrono2.date(refDate);
+            TemporalUnit adjuster = new FixedTemporalUnit(date2);
+            if (chrono != chrono2) {
+                try {
+                    date.minus(1, adjuster);
+                    Assert.fail("TemporalUnit.doPlus minus should have thrown a ClassCastException" + date.getClass()
+                            + ", can not be cast to " + date2.getClass());
+                } catch (ClassCastException cce) {
+                    // Expected exception; not an error
+                }
+            } else {
+                // Same chronology,
+                ChronoLocalDate<?> result = date.minus(1, adjuster);
+                assertEquals(result, date2, "WithAdjuster failed to replace date");
+            }
+        }
+    }
+
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_badTemporalFieldChrono(Chrono<?> chrono) {
+        LocalDate refDate = LocalDate.of(1900, 1, 1);
+        ChronoLocalDate<?> date = chrono.date(refDate);
+        for (Chrono<?>[] clist : data_of_calendars()) {
+            Chrono<?> chrono2 = clist[0];
+            ChronoLocalDate<?> date2 = chrono2.date(refDate);
+            TemporalField adjuster = new FixedTemporalField(date2);
+            if (chrono != chrono2) {
+                try {
+                    date.with(adjuster, 1);
+                    Assert.fail("TemporalField doWith() should have thrown a ClassCastException" + date.getClass()
+                            + ", can not be cast to " + date2.getClass());
+                } catch (ClassCastException cce) {
+                    // Expected exception; not an error
+                }
+            } else {
+                // Same chronology,
+                ChronoLocalDate<?> result = date.with(adjuster, 1);
+                assertEquals(result, date2, "TemporalField doWith() failed to replace date");
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // isBefore, isAfter, isEqual, DATE_COMPARATOR
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_date_comparisons(Chrono<?> chrono) {
+        List<ChronoLocalDate<?>> dates = new ArrayList<>();
+
+        ChronoLocalDate<?> date = chrono.date(LocalDate.of(1900, 1, 1));
+
+        // Insert dates in order, no duplicates
+        dates.add(date.minus(1000, ChronoUnit.YEARS));
+        dates.add(date.minus(100, ChronoUnit.YEARS));
+        dates.add(date.minus(10, ChronoUnit.YEARS));
+        dates.add(date.minus(1, ChronoUnit.YEARS));
+        dates.add(date.minus(1, ChronoUnit.MONTHS));
+        dates.add(date.minus(1, ChronoUnit.WEEKS));
+        dates.add(date.minus(1, ChronoUnit.DAYS));
+        dates.add(date);
+        dates.add(date.plus(1, ChronoUnit.DAYS));
+        dates.add(date.plus(1, ChronoUnit.WEEKS));
+        dates.add(date.plus(1, ChronoUnit.MONTHS));
+        dates.add(date.plus(1, ChronoUnit.YEARS));
+        dates.add(date.plus(10, ChronoUnit.YEARS));
+        dates.add(date.plus(100, ChronoUnit.YEARS));
+        dates.add(date.plus(1000, ChronoUnit.YEARS));
+
+        // Check these dates against the corresponding dates for every calendar
+        for (Chrono<?>[] clist : data_of_calendars()) {
+            List<ChronoLocalDate<?>> otherDates = new ArrayList<>();
+            Chrono<?> chrono2 = clist[0];
+            for (ChronoLocalDate<?> d : dates) {
+                otherDates.add(chrono2.date(d));
+            }
+
+            // Now compare  the sequence of original dates with the sequence of converted dates
+            for (int i = 0; i < dates.size(); i++) {
+                ChronoLocalDate<?> a = dates.get(i);
+                for (int j = 0; j < otherDates.size(); j++) {
+                    ChronoLocalDate<?> b = otherDates.get(j);
+                    int cmp = ChronoLocalDate.DATE_COMPARATOR.compare(a, b);
+                    if (i < j) {
+                        assertTrue(cmp < 0, a + " compare " + b);
+                        assertEquals(a.isBefore(b), true, a + " isBefore " + b);
+                        assertEquals(a.isAfter(b), false, a + " isAfter " + b);
+                        assertEquals(a.isEqual(b), false, a + " isEqual " + b);
+                    } else if (i > j) {
+                        assertTrue(cmp > 0, a + " compare " + b);
+                        assertEquals(a.isBefore(b), false, a + " isBefore " + b);
+                        assertEquals(a.isAfter(b), true, a + " isAfter " + b);
+                        assertEquals(a.isEqual(b), false, a + " isEqual " + b);
+                    } else {
+                        assertTrue(cmp == 0, a + " compare " + b);
+                        assertEquals(a.isBefore(b), false, a + " isBefore " + b);
+                        assertEquals(a.isAfter(b), false, a + " isAfter " + b);
+                        assertEquals(a.isEqual(b), true, a + " isEqual " + b);
+                    }
+                }
+            }
+        }
+    }
+
+    public void test_date_comparator_checkGenerics_ISO() {
+        List<ChronoLocalDate<ISOChrono>> dates = new ArrayList<>();
+        ChronoLocalDate<ISOChrono> date = LocalDate.of(1900, 1, 1);
+
+        // Insert dates in order, no duplicates
+        dates.add(date.minus(10, ChronoUnit.YEARS));
+        dates.add(date.minus(1, ChronoUnit.YEARS));
+        dates.add(date.minus(1, ChronoUnit.MONTHS));
+        dates.add(date.minus(1, ChronoUnit.WEEKS));
+        dates.add(date.minus(1, ChronoUnit.DAYS));
+        dates.add(date);
+        dates.add(date.plus(1, ChronoUnit.DAYS));
+        dates.add(date.plus(1, ChronoUnit.WEEKS));
+        dates.add(date.plus(1, ChronoUnit.MONTHS));
+        dates.add(date.plus(1, ChronoUnit.YEARS));
+        dates.add(date.plus(10, ChronoUnit.YEARS));
+
+        List<ChronoLocalDate<ISOChrono>> copy = new ArrayList<>(dates);
+        Collections.shuffle(copy);
+        Collections.sort(copy, ChronoLocalDate.DATE_COMPARATOR);
+        assertEquals(copy, dates);
+        assertTrue(ChronoLocalDate.DATE_COMPARATOR.compare(copy.get(0), copy.get(1)) < 0);
+    }
+
+    public void test_date_comparator_checkGenerics_LocalDate() {
+        List<LocalDate> dates = new ArrayList<>();
+        LocalDate date = LocalDate.of(1900, 1, 1);
+
+        // Insert dates in order, no duplicates
+        dates.add(date.minus(10, ChronoUnit.YEARS));
+        dates.add(date.minus(1, ChronoUnit.YEARS));
+        dates.add(date.minus(1, ChronoUnit.MONTHS));
+        dates.add(date.minus(1, ChronoUnit.WEEKS));
+        dates.add(date.minus(1, ChronoUnit.DAYS));
+        dates.add(date);
+        dates.add(date.plus(1, ChronoUnit.DAYS));
+        dates.add(date.plus(1, ChronoUnit.WEEKS));
+        dates.add(date.plus(1, ChronoUnit.MONTHS));
+        dates.add(date.plus(1, ChronoUnit.YEARS));
+        dates.add(date.plus(10, ChronoUnit.YEARS));
+
+        List<LocalDate> copy = new ArrayList<>(dates);
+        Collections.shuffle(copy);
+        Collections.sort(copy, ChronoLocalDate.DATE_COMPARATOR);
+        assertEquals(copy, dates);
+        assertTrue(ChronoLocalDate.DATE_COMPARATOR.compare(copy.get(0), copy.get(1)) < 0);
+    }
+
+    //-----------------------------------------------------------------------
+    // Test Serialization of ISO via chrono API
+    //-----------------------------------------------------------------------
+    @Test( groups={"tck"}, dataProvider="calendars")
+    public <C extends Chrono<C>> void test_ChronoSerialization(C chrono) throws Exception {
+        LocalDate ref = LocalDate.of(2000, 1, 5);
+        ChronoLocalDate<C> orginal = chrono.date(ref);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream(baos);
+        out.writeObject(orginal);
+        out.close();
+        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+        ObjectInputStream in = new ObjectInputStream(bais);
+        @SuppressWarnings("unchecked")
+        ChronoLocalDate<C> ser = (ChronoLocalDate<C>) in.readObject();
+        assertEquals(ser, orginal, "deserialized date is wrong");
+    }
+
+    /**
+     * FixedAdjusted returns a fixed Temporal in all adjustments.
+     * Construct an adjuster with the Temporal that should be returned from adjust.
+     */
+    static class FixedAdjuster implements TemporalAdjuster, TemporalAdder, TemporalSubtractor {
+        private Temporal datetime;
+
+        FixedAdjuster(Temporal datetime) {
+            this.datetime = datetime;
+        }
+
+        @Override
+        public Temporal adjustInto(Temporal ignore) {
+            return datetime;
+        }
+
+        @Override
+        public Temporal addTo(Temporal ignore) {
+            return datetime;
+        }
+
+        @Override
+        public Temporal subtractFrom(Temporal ignore) {
+            return datetime;
+        }
+
+    }
+
+    /**
+     * FixedTemporalUnit returns a fixed Temporal in all adjustments.
+     * Construct an FixedTemporalUnit with the Temporal that should be returned from doPlus.
+     */
+    static class FixedTemporalUnit implements TemporalUnit {
+        private Temporal temporal;
+
+        FixedTemporalUnit(Temporal temporal) {
+            this.temporal = temporal;
+        }
+
+        @Override
+        public String getName() {
+            return "FixedTemporalUnit";
+        }
+
+        @Override
+        public Duration getDuration() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public boolean isDurationEstimated() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public boolean isSupported(Temporal temporal) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public <R extends Temporal> R doPlus(R dateTime, long periodToAdd) {
+            return (R) this.temporal;
+        }
+
+        @Override
+        public <R extends Temporal> SimplePeriod between(R dateTime1, R dateTime2) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+    }
+
+    /**
+     * FixedTemporalField returns a fixed Temporal in all adjustments.
+     * Construct an FixedTemporalField with the Temporal that should be returned from doWith.
+     */
+    static class FixedTemporalField implements TemporalField {
+        private Temporal temporal;
+        FixedTemporalField(Temporal temporal) {
+            this.temporal = temporal;
+        }
+
+        @Override
+        public String getName() {
+            return "FixedTemporalField";
+        }
+
+        @Override
+        public TemporalUnit getBaseUnit() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public TemporalUnit getRangeUnit() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public ValueRange range() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public boolean doIsSupported(TemporalAccessor temporal) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public ValueRange doRange(TemporalAccessor temporal) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public long doGet(TemporalAccessor temporal) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public <R extends Temporal> R doWith(R temporal, long newValue) {
+            return (R) this.temporal;
+        }
+
+        @Override
+        public boolean resolve(DateTimeBuilder builder, long value) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/temporal/TestChronoLocalDateTime.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,470 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.temporal;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import java.time.Duration;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.temporal.Chrono;
+import java.time.temporal.ChronoLocalDateTime;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.SimplePeriod;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.format.DateTimeBuilder;
+import java.time.temporal.TemporalAdder;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalSubtractor;
+import java.time.temporal.ValueRange;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.ISOChrono;
+import java.time.calendar.HijrahChrono;
+import java.time.calendar.JapaneseChrono;
+import java.time.calendar.MinguoChrono;
+import java.time.calendar.ThaiBuddhistChrono;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test assertions that must be true for all built-in chronologies.
+ */
+@Test
+public class TestChronoLocalDateTime {
+
+    //-----------------------------------------------------------------------
+    // regular data factory for names and descriptions of available calendars
+    //-----------------------------------------------------------------------
+    @DataProvider(name = "calendars")
+    Chrono<?>[][] data_of_calendars() {
+        return new Chrono<?>[][]{
+                    {HijrahChrono.INSTANCE},
+                    {ISOChrono.INSTANCE},
+                    {JapaneseChrono.INSTANCE},
+                    {MinguoChrono.INSTANCE},
+                    {ThaiBuddhistChrono.INSTANCE}};
+    }
+
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_badWithAdjusterChrono(Chrono<?> chrono) {
+        LocalDate refDate = LocalDate.of(1900, 1, 1);
+        ChronoLocalDateTime<?> cdt = chrono.date(refDate).atTime(LocalTime.NOON);
+        for (Chrono<?>[] clist : data_of_calendars()) {
+            Chrono<?> chrono2 = clist[0];
+            ChronoLocalDateTime<?> cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON);
+            TemporalAdjuster adjuster = new FixedAdjuster(cdt2);
+            if (chrono != chrono2) {
+                try {
+                    cdt.with(adjuster);
+                    Assert.fail("WithAdjuster should have thrown a ClassCastException, "
+                            + "required: " + cdt + ", supplied: " + cdt2);
+                } catch (ClassCastException cce) {
+                    // Expected exception; not an error
+                }
+            } else {
+                // Same chronology,
+                ChronoLocalDateTime<?> result = cdt.with(adjuster);
+                assertEquals(result, cdt2, "WithAdjuster failed to replace date");
+            }
+        }
+    }
+
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_badPlusAdjusterChrono(Chrono<?> chrono) {
+        LocalDate refDate = LocalDate.of(1900, 1, 1);
+        ChronoLocalDateTime<?> cdt = chrono.date(refDate).atTime(LocalTime.NOON);
+        for (Chrono<?>[] clist : data_of_calendars()) {
+            Chrono<?> chrono2 = clist[0];
+            ChronoLocalDateTime<?> cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON);
+            TemporalAdder adjuster = new FixedAdjuster(cdt2);
+            if (chrono != chrono2) {
+                try {
+                    cdt.plus(adjuster);
+                    Assert.fail("WithAdjuster should have thrown a ClassCastException, "
+                            + "required: " + cdt + ", supplied: " + cdt2);
+                } catch (ClassCastException cce) {
+                    // Expected exception; not an error
+                }
+            } else {
+                // Same chronology,
+                ChronoLocalDateTime<?> result = cdt.plus(adjuster);
+                assertEquals(result, cdt2, "WithAdjuster failed to replace date time");
+            }
+        }
+    }
+
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_badMinusAdjusterChrono(Chrono<?> chrono) {
+        LocalDate refDate = LocalDate.of(1900, 1, 1);
+        ChronoLocalDateTime<?> cdt = chrono.date(refDate).atTime(LocalTime.NOON);
+        for (Chrono<?>[] clist : data_of_calendars()) {
+            Chrono<?> chrono2 = clist[0];
+            ChronoLocalDateTime<?> cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON);
+            TemporalSubtractor adjuster = new FixedAdjuster(cdt2);
+            if (chrono != chrono2) {
+                try {
+                    cdt.minus(adjuster);
+                    Assert.fail("WithAdjuster should have thrown a ClassCastException, "
+                            + "required: " + cdt + ", supplied: " + cdt2);
+                } catch (ClassCastException cce) {
+                    // Expected exception; not an error
+                }
+            } else {
+                // Same chronology,
+                ChronoLocalDateTime<?> result = cdt.minus(adjuster);
+                assertEquals(result, cdt2, "WithAdjuster failed to replace date");
+            }
+        }
+    }
+
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_badPlusTemporalUnitChrono(Chrono<?> chrono) {
+        LocalDate refDate = LocalDate.of(1900, 1, 1);
+        ChronoLocalDateTime<?> cdt = chrono.date(refDate).atTime(LocalTime.NOON);
+        for (Chrono<?>[] clist : data_of_calendars()) {
+            Chrono<?> chrono2 = clist[0];
+            ChronoLocalDateTime<?> cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON);
+            TemporalUnit adjuster = new FixedTemporalUnit(cdt2);
+            if (chrono != chrono2) {
+                try {
+                    cdt.plus(1, adjuster);
+                    Assert.fail("TemporalUnit.doPlus plus should have thrown a ClassCastException" + cdt
+                            + ", can not be cast to " + cdt2);
+                } catch (ClassCastException cce) {
+                    // Expected exception; not an error
+                }
+            } else {
+                // Same chronology,
+                ChronoLocalDateTime<?> result = cdt.plus(1, adjuster);
+                assertEquals(result, cdt2, "WithAdjuster failed to replace date");
+            }
+        }
+    }
+
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_badMinusTemporalUnitChrono(Chrono<?> chrono) {
+        LocalDate refDate = LocalDate.of(1900, 1, 1);
+        ChronoLocalDateTime<?> cdt = chrono.date(refDate).atTime(LocalTime.NOON);
+        for (Chrono<?>[] clist : data_of_calendars()) {
+            Chrono<?> chrono2 = clist[0];
+            ChronoLocalDateTime<?> cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON);
+            TemporalUnit adjuster = new FixedTemporalUnit(cdt2);
+            if (chrono != chrono2) {
+                try {
+                    cdt.minus(1, adjuster);
+                    Assert.fail("TemporalUnit.doPlus minus should have thrown a ClassCastException" + cdt.getClass()
+                            + ", can not be cast to " + cdt2.getClass());
+                } catch (ClassCastException cce) {
+                    // Expected exception; not an error
+                }
+            } else {
+                // Same chronology,
+                ChronoLocalDateTime<?> result = cdt.minus(1, adjuster);
+                assertEquals(result, cdt2, "WithAdjuster failed to replace date");
+            }
+        }
+    }
+
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_badTemporalFieldChrono(Chrono<?> chrono) {
+        LocalDate refDate = LocalDate.of(1900, 1, 1);
+        ChronoLocalDateTime<?> cdt = chrono.date(refDate).atTime(LocalTime.NOON);
+        for (Chrono<?>[] clist : data_of_calendars()) {
+            Chrono<?> chrono2 = clist[0];
+            ChronoLocalDateTime<?> cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON);
+            TemporalField adjuster = new FixedTemporalField(cdt2);
+            if (chrono != chrono2) {
+                try {
+                    cdt.with(adjuster, 1);
+                    Assert.fail("TemporalField doWith() should have thrown a ClassCastException" + cdt.getClass()
+                            + ", can not be cast to " + cdt2.getClass());
+                } catch (ClassCastException cce) {
+                    // Expected exception; not an error
+                }
+            } else {
+                // Same chronology,
+                ChronoLocalDateTime<?> result = cdt.with(adjuster, 1);
+                assertEquals(result, cdt2, "TemporalField doWith() failed to replace date");
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // isBefore, isAfter, isEqual
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_datetime_comparisons(Chrono<?> chrono) {
+        List<ChronoLocalDateTime<?>> dates = new ArrayList<>();
+
+        ChronoLocalDateTime<?> date = chrono.date(LocalDate.of(1900, 1, 1)).atTime(LocalTime.MIN);
+
+        // Insert dates in order, no duplicates
+        dates.add(date.minus(100, ChronoUnit.YEARS));
+        dates.add(date.minus(1, ChronoUnit.YEARS));
+        dates.add(date.minus(1, ChronoUnit.MONTHS));
+        dates.add(date.minus(1, ChronoUnit.WEEKS));
+        dates.add(date.minus(1, ChronoUnit.DAYS));
+        dates.add(date.minus(1, ChronoUnit.HOURS));
+        dates.add(date.minus(1, ChronoUnit.MINUTES));
+        dates.add(date.minus(1, ChronoUnit.SECONDS));
+        dates.add(date.minus(1, ChronoUnit.NANOS));
+        dates.add(date);
+        dates.add(date.plus(1, ChronoUnit.NANOS));
+        dates.add(date.plus(1, ChronoUnit.SECONDS));
+        dates.add(date.plus(1, ChronoUnit.MINUTES));
+        dates.add(date.plus(1, ChronoUnit.HOURS));
+        dates.add(date.plus(1, ChronoUnit.DAYS));
+        dates.add(date.plus(1, ChronoUnit.WEEKS));
+        dates.add(date.plus(1, ChronoUnit.MONTHS));
+        dates.add(date.plus(1, ChronoUnit.YEARS));
+        dates.add(date.plus(100, ChronoUnit.YEARS));
+
+        // Check these dates against the corresponding dates for every calendar
+        for (Chrono<?>[] clist : data_of_calendars()) {
+            List<ChronoLocalDateTime<?>> otherDates = new ArrayList<>();
+            Chrono<?> chrono2 = clist[0];
+            for (ChronoLocalDateTime<?> d : dates) {
+                otherDates.add(chrono2.date(d).atTime(d.getTime()));
+            }
+
+            // Now compare  the sequence of original dates with the sequence of converted dates
+            for (int i = 0; i < dates.size(); i++) {
+                ChronoLocalDateTime<?> a = dates.get(i);
+                for (int j = 0; j < otherDates.size(); j++) {
+                    ChronoLocalDateTime<?> b = otherDates.get(j);
+                    int cmp = ChronoLocalDateTime.DATE_TIME_COMPARATOR.compare(a, b);
+                    if (i < j) {
+                        assertTrue(cmp < 0, a + " compare " + b);
+                        assertEquals(a.isBefore(b), true, a + " isBefore " + b);
+                        assertEquals(a.isAfter(b), false, a + " isAfter " + b);
+                        assertEquals(a.isEqual(b), false, a + " isEqual " + b);
+                    } else if (i > j) {
+                        assertTrue(cmp > 0, a + " compare " + b);
+                        assertEquals(a.isBefore(b), false, a + " isBefore " + b);
+                        assertEquals(a.isAfter(b), true, a + " isAfter " + b);
+                        assertEquals(a.isEqual(b), false, a + " isEqual " + b);
+                    } else {
+                        assertTrue(cmp == 0, a + " compare " + b);
+                        assertEquals(a.isBefore(b), false, a + " isBefore " + b);
+                        assertEquals(a.isAfter(b), false, a + " isAfter " + b);
+                        assertEquals(a.isEqual(b), true, a + " isEqual " + b);
+                    }
+                }
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // Test Serialization of ISO via chrono API
+    //-----------------------------------------------------------------------
+    @Test( groups={"tck"}, dataProvider="calendars")
+    public <C extends Chrono<C>> void test_ChronoLocalDateTimeSerialization(C chrono) throws Exception {
+        LocalDateTime ref = LocalDate.of(2000, 1, 5).atTime(12, 1, 2, 3);
+        ChronoLocalDateTime<C> orginal = chrono.date(ref).atTime(ref.getTime());
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream(baos);
+        out.writeObject(orginal);
+        out.close();
+        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+        ObjectInputStream in = new ObjectInputStream(bais);
+        @SuppressWarnings("unchecked")
+        ChronoLocalDateTime<C> ser = (ChronoLocalDateTime<C>) in.readObject();
+        assertEquals(ser, orginal, "deserialized date is wrong");
+    }
+
+    /**
+     * FixedAdjusted returns a fixed Temporal in all adjustments.
+     * Construct an adjuster with the Temporal that should be returned from adjust.
+     */
+    static class FixedAdjuster implements TemporalAdjuster, TemporalAdder, TemporalSubtractor {
+        private Temporal datetime;
+
+        FixedAdjuster(Temporal datetime) {
+            this.datetime = datetime;
+        }
+
+        @Override
+        public Temporal adjustInto(Temporal ignore) {
+            return datetime;
+        }
+
+        @Override
+        public Temporal addTo(Temporal ignore) {
+            return datetime;
+        }
+
+        @Override
+        public Temporal subtractFrom(Temporal ignore) {
+            return datetime;
+        }
+
+    }
+
+    /**
+     * FixedTemporalUnit returns a fixed Temporal in all adjustments.
+     * Construct an FixedTemporalUnit with the Temporal that should be returned from doPlus.
+     */
+    static class FixedTemporalUnit implements TemporalUnit {
+        private Temporal temporal;
+
+        FixedTemporalUnit(Temporal temporal) {
+            this.temporal = temporal;
+        }
+
+        @Override
+        public String getName() {
+            return "FixedTemporalUnit";
+        }
+
+        @Override
+        public Duration getDuration() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public boolean isDurationEstimated() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public boolean isSupported(Temporal temporal) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public <R extends Temporal> R doPlus(R dateTime, long periodToAdd) {
+            return (R) this.temporal;
+        }
+
+        @Override
+        public <R extends Temporal> SimplePeriod between(R dateTime1, R dateTime2) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+    }
+
+    /**
+     * FixedTemporalField returns a fixed Temporal in all adjustments.
+     * Construct an FixedTemporalField with the Temporal that should be returned from doWith.
+     */
+    static class FixedTemporalField implements TemporalField {
+        private Temporal temporal;
+        FixedTemporalField(Temporal temporal) {
+            this.temporal = temporal;
+        }
+
+        @Override
+        public String getName() {
+            return "FixedTemporalField";
+        }
+
+        @Override
+        public TemporalUnit getBaseUnit() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public TemporalUnit getRangeUnit() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public ValueRange range() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public boolean doIsSupported(TemporalAccessor temporal) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public ValueRange doRange(TemporalAccessor temporal) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public long doGet(TemporalAccessor temporal) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public <R extends Temporal> R doWith(R temporal, long newValue) {
+            return (R) this.temporal;
+        }
+
+        @Override
+        public boolean resolve(DateTimeBuilder builder, long value) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/temporal/TestChronoZonedDateTime.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,475 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.temporal;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import java.time.Duration;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.temporal.Chrono;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.ChronoZonedDateTime;
+import java.time.temporal.SimplePeriod;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.format.DateTimeBuilder;
+import java.time.temporal.TemporalAdder;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalSubtractor;
+import java.time.temporal.ValueRange;
+import java.time.temporal.ISOChrono;
+import java.time.temporal.TemporalUnit;
+import java.time.calendar.HijrahChrono;
+import java.time.calendar.JapaneseChrono;
+import java.time.calendar.MinguoChrono;
+import java.time.calendar.ThaiBuddhistChrono;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test assertions that must be true for all built-in chronologies.
+ */
+@Test
+public class TestChronoZonedDateTime {
+
+    //-----------------------------------------------------------------------
+    // regular data factory for names and descriptions of available calendars
+    //-----------------------------------------------------------------------
+    @DataProvider(name = "calendars")
+    Chrono<?>[][] data_of_calendars() {
+        return new Chrono<?>[][]{
+                    {HijrahChrono.INSTANCE},
+                    {ISOChrono.INSTANCE},
+                    {JapaneseChrono.INSTANCE},
+                    {MinguoChrono.INSTANCE},
+                    {ThaiBuddhistChrono.INSTANCE},
+        };
+    }
+
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_badWithAdjusterChrono(Chrono<?> chrono) {
+        LocalDate refDate = LocalDate.of(1900, 1, 1);
+        ChronoZonedDateTime<?> czdt = chrono.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC);
+        for (Chrono<?>[] clist : data_of_calendars()) {
+            Chrono<?> chrono2 = clist[0];
+            ChronoZonedDateTime<?> czdt2 = chrono2.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC);
+            TemporalAdjuster adjuster = new FixedAdjuster(czdt2);
+            if (chrono != chrono2) {
+                try {
+                    czdt.with(adjuster);
+                    Assert.fail("WithAdjuster should have thrown a ClassCastException, "
+                            + "required: " + czdt + ", supplied: " + czdt2);
+                } catch (ClassCastException cce) {
+                    // Expected exception; not an error
+                }
+            } else {
+                ChronoZonedDateTime<?> result = czdt.with(adjuster);
+                assertEquals(result, czdt2, "WithAdjuster failed to replace date");
+            }
+        }
+    }
+
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_badPlusAdjusterChrono(Chrono<?> chrono) {
+        LocalDate refDate = LocalDate.of(1900, 1, 1);
+        ChronoZonedDateTime<?> czdt = chrono.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC);
+        for (Chrono<?>[] clist : data_of_calendars()) {
+            Chrono<?> chrono2 = clist[0];
+            ChronoZonedDateTime<?> czdt2 = chrono2.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC);
+            TemporalAdder adjuster = new FixedAdjuster(czdt2);
+            if (chrono != chrono2) {
+                try {
+                    czdt.plus(adjuster);
+                    Assert.fail("WithAdjuster should have thrown a ClassCastException, "
+                            + "required: " + czdt + ", supplied: " + czdt2);
+                } catch (ClassCastException cce) {
+                    // Expected exception; not an error
+                }
+            } else {
+                // Same chronology,
+                ChronoZonedDateTime<?> result = czdt.plus(adjuster);
+                assertEquals(result, czdt2, "WithAdjuster failed to replace date time");
+            }
+        }
+    }
+
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_badMinusAdjusterChrono(Chrono<?> chrono) {
+        LocalDate refDate = LocalDate.of(1900, 1, 1);
+        ChronoZonedDateTime<?> czdt = chrono.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC);
+        for (Chrono<?>[] clist : data_of_calendars()) {
+            Chrono<?> chrono2 = clist[0];
+            ChronoZonedDateTime<?> czdt2 = chrono2.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC);
+            TemporalSubtractor adjuster = new FixedAdjuster(czdt2);
+            if (chrono != chrono2) {
+                try {
+                    czdt.minus(adjuster);
+                    Assert.fail("WithAdjuster should have thrown a ClassCastException, "
+                            + "required: " + czdt + ", supplied: " + czdt2);
+                } catch (ClassCastException cce) {
+                    // Expected exception; not an error
+                }
+            } else {
+                // Same chronology,
+                ChronoZonedDateTime<?> result = czdt.minus(adjuster);
+                assertEquals(result, czdt2, "WithAdjuster failed to replace date");
+            }
+        }
+    }
+
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_badPlusTemporalUnitChrono(Chrono<?> chrono) {
+        LocalDate refDate = LocalDate.of(1900, 1, 1);
+        ChronoZonedDateTime<?> czdt = chrono.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC);
+        for (Chrono<?>[] clist : data_of_calendars()) {
+            Chrono<?> chrono2 = clist[0];
+            ChronoZonedDateTime<?> czdt2 = chrono2.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC);
+            TemporalUnit adjuster = new FixedTemporalUnit(czdt2);
+            if (chrono != chrono2) {
+                try {
+                    czdt.plus(1, adjuster);
+                    Assert.fail("TemporalUnit.doPlus plus should have thrown a ClassCastException, " + czdt
+                            + " can not be cast to " + czdt2);
+                } catch (ClassCastException cce) {
+                    // Expected exception; not an error
+                }
+            } else {
+                // Same chronology,
+                ChronoZonedDateTime<?> result = czdt.plus(1, adjuster);
+                assertEquals(result, czdt2, "WithAdjuster failed to replace date");
+            }
+        }
+    }
+
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_badMinusTemporalUnitChrono(Chrono<?> chrono) {
+        LocalDate refDate = LocalDate.of(1900, 1, 1);
+        ChronoZonedDateTime<?> czdt = chrono.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC);
+        for (Chrono<?>[] clist : data_of_calendars()) {
+            Chrono<?> chrono2 = clist[0];
+            ChronoZonedDateTime<?> czdt2 = chrono2.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC);
+            TemporalUnit adjuster = new FixedTemporalUnit(czdt2);
+            if (chrono != chrono2) {
+                try {
+                    czdt.minus(1, adjuster);
+                    Assert.fail("TemporalUnit.doPlus minus should have thrown a ClassCastException, " + czdt.getClass()
+                            + " can not be cast to " + czdt2.getClass());
+                } catch (ClassCastException cce) {
+                    // Expected exception; not an error
+                }
+            } else {
+                // Same chronology,
+                ChronoZonedDateTime<?> result = czdt.minus(1, adjuster);
+                assertEquals(result, czdt2, "WithAdjuster failed to replace date");
+            }
+        }
+    }
+
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_badTemporalFieldChrono(Chrono<?> chrono) {
+        LocalDate refDate = LocalDate.of(1900, 1, 1);
+        ChronoZonedDateTime<?> czdt = chrono.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC);
+        for (Chrono<?>[] clist : data_of_calendars()) {
+            Chrono<?> chrono2 = clist[0];
+            ChronoZonedDateTime<?> czdt2 = chrono2.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC);
+            TemporalField adjuster = new FixedTemporalField(czdt2);
+            if (chrono != chrono2) {
+                try {
+                    czdt.with(adjuster, 1);
+                    Assert.fail("TemporalField doWith() should have thrown a ClassCastException, " + czdt.getClass()
+                            + " can not be cast to " + czdt2.getClass());
+                } catch (ClassCastException cce) {
+                    // Expected exception; not an error
+                }
+            } else {
+                // Same chronology,
+                ChronoZonedDateTime<?> result = czdt.with(adjuster, 1);
+                assertEquals(result, czdt2, "TemporalField doWith() failed to replace date");
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // isBefore, isAfter, isEqual, INSTANT_COMPARATOR  test a Chrono<?> against the other Chronos
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"}, dataProvider="calendars")
+    public void test_zonedDateTime_comparisons(Chrono<?> chrono) {
+        List<ChronoZonedDateTime<?>> dates = new ArrayList<>();
+
+        ChronoZonedDateTime<?> date = chrono.date(LocalDate.of(1900, 1, 1))
+                .atTime(LocalTime.MIN)
+                .atZone(ZoneOffset.UTC);
+
+        // Insert dates in order, no duplicates
+        dates.add(date.minus(100, ChronoUnit.YEARS));
+        dates.add(date.minus(1, ChronoUnit.YEARS));
+        dates.add(date.minus(1, ChronoUnit.MONTHS));
+        dates.add(date.minus(1, ChronoUnit.WEEKS));
+        dates.add(date.minus(1, ChronoUnit.DAYS));
+        dates.add(date.minus(1, ChronoUnit.HOURS));
+        dates.add(date.minus(1, ChronoUnit.MINUTES));
+        dates.add(date.minus(1, ChronoUnit.SECONDS));
+        dates.add(date.minus(1, ChronoUnit.NANOS));
+        dates.add(date);
+        dates.add(date.plus(1, ChronoUnit.NANOS));
+        dates.add(date.plus(1, ChronoUnit.SECONDS));
+        dates.add(date.plus(1, ChronoUnit.MINUTES));
+        dates.add(date.plus(1, ChronoUnit.HOURS));
+        dates.add(date.plus(1, ChronoUnit.DAYS));
+        dates.add(date.plus(1, ChronoUnit.WEEKS));
+        dates.add(date.plus(1, ChronoUnit.MONTHS));
+        dates.add(date.plus(1, ChronoUnit.YEARS));
+        dates.add(date.plus(100, ChronoUnit.YEARS));
+
+        // Check these dates against the corresponding dates for every calendar
+        for (Chrono<?>[] clist : data_of_calendars()) {
+            List<ChronoZonedDateTime<?>> otherDates = new ArrayList<>();
+            Chrono<?> chrono2 = ISOChrono.INSTANCE; //clist[0];
+            for (ChronoZonedDateTime<?> d : dates) {
+                otherDates.add(chrono2.date(d).atTime(d.getTime()).atZone(d.getZone()));
+            }
+
+            // Now compare  the sequence of original dates with the sequence of converted dates
+            for (int i = 0; i < dates.size(); i++) {
+                ChronoZonedDateTime<?> a = dates.get(i);
+                for (int j = 0; j < otherDates.size(); j++) {
+                    ChronoZonedDateTime<?> b = otherDates.get(j);
+                    int cmp = ChronoZonedDateTime.INSTANT_COMPARATOR.compare(a, b);
+                    if (i < j) {
+                        assertTrue(cmp < 0, a + " compare " + b);
+                        assertEquals(a.isBefore(b), true, a + " isBefore " + b);
+                        assertEquals(a.isAfter(b), false, a + " ifAfter " + b);
+                        assertEquals(a.isEqual(b), false, a + " isEqual " + b);
+                    } else if (i > j) {
+                        assertTrue(cmp > 0, a + " compare " + b);
+                        assertEquals(a.isBefore(b), false, a + " isBefore " + b);
+                        assertEquals(a.isAfter(b), true, a + " ifAfter " + b);
+                        assertEquals(a.isEqual(b), false, a + " isEqual " + b);
+                    } else {
+                        assertTrue(cmp == 0, a + " compare " + b);
+                        assertEquals(a.isBefore(b), false, a + " isBefore " + b);
+                        assertEquals(a.isAfter(b), false, a + " ifAfter " + b);
+                        assertEquals(a.isEqual(b), true, a + " isEqual " + b);
+                    }
+                }
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // Test Serialization of ISO via chrono API
+    //-----------------------------------------------------------------------
+    @Test( groups={"tck"}, dataProvider="calendars")
+    public <C extends Chrono<C>> void test_ChronoZonedDateTimeSerialization(C chrono) throws Exception {
+        ZonedDateTime ref = LocalDate.of(2000, 1, 5).atTime(12, 1, 2, 3).atZone(ZoneId.of("GMT+01:23"));
+        ChronoZonedDateTime<C> orginal = chrono.date(ref).atTime(ref.getTime()).atZone(ref.getZone());
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream(baos);
+        out.writeObject(orginal);
+        out.close();
+        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+        ObjectInputStream in = new ObjectInputStream(bais);
+        @SuppressWarnings("unchecked")
+        ChronoZonedDateTime<C> ser = (ChronoZonedDateTime<C>) in.readObject();
+        assertEquals(ser, orginal, "deserialized date is wrong");
+    }
+
+
+    /**
+     * FixedAdjusted returns a fixed Temporal in all adjustments.
+     * Construct an adjuster with the Temporal that should be returned from adjust.
+     */
+    static class FixedAdjuster implements TemporalAdjuster, TemporalAdder, TemporalSubtractor {
+        private Temporal datetime;
+
+        FixedAdjuster(Temporal datetime) {
+            this.datetime = datetime;
+        }
+
+        @Override
+        public Temporal adjustInto(Temporal ignore) {
+            return datetime;
+        }
+
+        @Override
+        public Temporal addTo(Temporal ignore) {
+            return datetime;
+        }
+
+        @Override
+        public Temporal subtractFrom(Temporal ignore) {
+            return datetime;
+        }
+
+    }
+
+    /**
+     * FixedTemporalUnit returns a fixed Temporal in all adjustments.
+     * Construct an FixedTemporalUnit with the Temporal that should be returned from doPlus.
+     */
+    static class FixedTemporalUnit implements TemporalUnit {
+        private Temporal temporal;
+
+        FixedTemporalUnit(Temporal temporal) {
+            this.temporal = temporal;
+        }
+
+        @Override
+        public String getName() {
+            return "FixedTemporalUnit";
+        }
+
+        @Override
+        public Duration getDuration() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public boolean isDurationEstimated() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public boolean isSupported(Temporal temporal) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public <R extends Temporal> R doPlus(R dateTime, long periodToAdd) {
+            return (R) this.temporal;
+        }
+
+        @Override
+        public <R extends Temporal> SimplePeriod between(R dateTime1, R dateTime2) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+    }
+
+    /**
+     * FixedTemporalField returns a fixed Temporal in all adjustments.
+     * Construct an FixedTemporalField with the Temporal that should be returned from doWith.
+     */
+    static class FixedTemporalField implements TemporalField {
+        private Temporal temporal;
+        FixedTemporalField(Temporal temporal) {
+            this.temporal = temporal;
+        }
+
+        @Override
+        public String getName() {
+            return "FixedTemporalField";
+        }
+
+        @Override
+        public TemporalUnit getBaseUnit() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public TemporalUnit getRangeUnit() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public ValueRange range() {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public boolean doIsSupported(TemporalAccessor temporal) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public ValueRange doRange(TemporalAccessor temporal) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @Override
+        public long doGet(TemporalAccessor temporal) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public <R extends Temporal> R doWith(R temporal, long newValue) {
+            return (R) this.temporal;
+        }
+
+        @Override
+        public boolean resolve(DateTimeBuilder builder, long value) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/temporal/TestISOChrono.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.temporal;
+
+import static java.time.temporal.ChronoField.ERA;
+import static java.time.temporal.ChronoField.YEAR;
+import static java.time.temporal.ChronoField.YEAR_OF_ERA;
+import static java.time.temporal.ISOChrono.ERA_BCE;
+import static java.time.temporal.ISOChrono.ERA_CE;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.Month;
+import java.time.temporal.Chrono;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoLocalDate;
+import java.time.temporal.Adjusters;
+import java.time.calendar.HijrahChrono;
+import java.time.temporal.Era;
+import java.time.temporal.ISOChrono;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test.
+ */
+@Test
+public class TestISOChrono {
+
+    //-----------------------------------------------------------------------
+    // Chrono.ofName("ISO")  Lookup by name
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_chrono_byName() {
+        Chrono<ISOChrono> c = ISOChrono.INSTANCE;
+        Chrono<?> test = Chrono.of("ISO");
+        Assert.assertNotNull(test, "The ISO calendar could not be found byName");
+        Assert.assertEquals(test.getId(), "ISO", "ID mismatch");
+        Assert.assertEquals(test.getCalendarType(), "iso8601", "Type mismatch");
+        Assert.assertEquals(test, c);
+    }
+
+    //-----------------------------------------------------------------------
+    // Lookup by Singleton
+    //-----------------------------------------------------------------------
+    @Test(groups="tck")
+    public void instanceNotNull() {
+        assertNotNull(ISOChrono.INSTANCE);
+    }
+
+    //-----------------------------------------------------------------------
+    // Era creation
+    //-----------------------------------------------------------------------
+    @Test(groups="tck")
+    public void test_eraOf() {
+        assertEquals(ISOChrono.INSTANCE.eraOf(0), ERA_BCE);
+        assertEquals(ISOChrono.INSTANCE.eraOf(1), ERA_CE);
+    }
+
+    //-----------------------------------------------------------------------
+    // creation, toLocalDate()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="samples")
+    Object[][] data_samples() {
+        return new Object[][] {
+            {ISOChrono.INSTANCE.date(1, 7, 8), LocalDate.of(1, 7, 8)},
+            {ISOChrono.INSTANCE.date(1, 7, 20), LocalDate.of(1, 7, 20)},
+            {ISOChrono.INSTANCE.date(1, 7, 21), LocalDate.of(1, 7, 21)},
+
+            {ISOChrono.INSTANCE.date(2, 7, 8), LocalDate.of(2, 7, 8)},
+            {ISOChrono.INSTANCE.date(3, 6, 27), LocalDate.of(3, 6, 27)},
+            {ISOChrono.INSTANCE.date(3, 5, 23), LocalDate.of(3, 5, 23)},
+            {ISOChrono.INSTANCE.date(4, 6, 16), LocalDate.of(4, 6, 16)},
+            {ISOChrono.INSTANCE.date(4, 7, 3), LocalDate.of(4, 7, 3)},
+            {ISOChrono.INSTANCE.date(4, 7, 4), LocalDate.of(4, 7, 4)},
+            {ISOChrono.INSTANCE.date(5, 1, 1), LocalDate.of(5, 1, 1)},
+            {ISOChrono.INSTANCE.date(1727, 3, 3), LocalDate.of(1727, 3, 3)},
+            {ISOChrono.INSTANCE.date(1728, 10, 28), LocalDate.of(1728, 10, 28)},
+            {ISOChrono.INSTANCE.date(2012, 10, 29), LocalDate.of(2012, 10, 29)},
+        };
+    }
+
+    @Test(dataProvider="samples", groups={"tck"})
+    public void test_toLocalDate(ChronoLocalDate<ISOChrono> isoDate, LocalDate iso) {
+        assertEquals(LocalDate.from(isoDate), iso);
+    }
+
+    @Test(dataProvider="samples", groups={"tck"})
+    public void test_fromCalendrical(ChronoLocalDate<ISOChrono> isoDate, LocalDate iso) {
+        assertEquals(ISOChrono.INSTANCE.date(iso), isoDate);
+    }
+
+    @DataProvider(name="badDates")
+    Object[][] data_badDates() {
+        return new Object[][] {
+            {2012, 0, 0},
+
+            {2012, -1, 1},
+            {2012, 0, 1},
+            {2012, 14, 1},
+            {2012, 15, 1},
+
+            {2012, 1, -1},
+            {2012, 1, 0},
+            {2012, 1, 32},
+
+            {2012, 12, -1},
+            {2012, 12, 0},
+            {2012, 12, 32},
+        };
+    }
+
+    @Test(dataProvider="badDates", groups={"tck"}, expectedExceptions=DateTimeException.class)
+    public void test_badDates(int year, int month, int dom) {
+        ISOChrono.INSTANCE.date(year, month, dom);
+    }
+
+    @Test(groups="tck")
+    public void test_date_withEra() {
+        int year = 5;
+        int month = 5;
+        int dayOfMonth = 5;
+        ChronoLocalDate<ISOChrono> test = ISOChrono.INSTANCE.date(ERA_BCE, year, month, dayOfMonth);
+        assertEquals(test.getEra(), ERA_BCE);
+        assertEquals(test.get(ChronoField.YEAR_OF_ERA), year);
+        assertEquals(test.get(ChronoField.MONTH_OF_YEAR), month);
+        assertEquals(test.get(ChronoField.DAY_OF_MONTH), dayOfMonth);
+
+        assertEquals(test.get(YEAR), 1 + (-1 * year));
+        assertEquals(test.get(ERA), 0);
+        assertEquals(test.get(YEAR_OF_ERA), year);
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Test(expectedExceptions=DateTimeException.class, groups="tck")
+    public void test_date_withEra_withWrongEra() {
+        ISOChrono.INSTANCE.date((Era) HijrahChrono.ERA_AH, 1, 1, 1);
+    }
+
+    //-----------------------------------------------------------------------
+    // with(DateTimeAdjuster)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_adjust1() {
+        ChronoLocalDate<ISOChrono> base = ISOChrono.INSTANCE.date(1728, 10, 28);
+        ChronoLocalDate<ISOChrono> test = base.with(Adjusters.lastDayOfMonth());
+        assertEquals(test, ISOChrono.INSTANCE.date(1728, 10, 31));
+    }
+
+    @Test(groups={"tck"})
+    public void test_adjust2() {
+        ChronoLocalDate<ISOChrono> base = ISOChrono.INSTANCE.date(1728, 12, 2);
+        ChronoLocalDate<ISOChrono> test = base.with(Adjusters.lastDayOfMonth());
+        assertEquals(test, ISOChrono.INSTANCE.date(1728, 12, 31));
+    }
+
+    //-----------------------------------------------------------------------
+    // ISODate.with(Local*)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_adjust_toLocalDate() {
+        ChronoLocalDate<ISOChrono> isoDate = ISOChrono.INSTANCE.date(1726, 1, 4);
+        ChronoLocalDate<ISOChrono> test = isoDate.with(LocalDate.of(2012, 7, 6));
+        assertEquals(test, ISOChrono.INSTANCE.date(2012, 7, 6));
+    }
+
+    @Test(groups={"tck"})
+    public void test_adjust_toMonth() {
+        ChronoLocalDate<ISOChrono> isoDate = ISOChrono.INSTANCE.date(1726, 1, 4);
+        assertEquals(ISOChrono.INSTANCE.date(1726, 4, 4), isoDate.with(Month.APRIL));
+    }
+
+    //-----------------------------------------------------------------------
+    // LocalDate.with(ISODate)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_LocalDate_adjustToISODate() {
+        ChronoLocalDate<ISOChrono> isoDate = ISOChrono.INSTANCE.date(1728, 10, 29);
+        LocalDate test = LocalDate.MIN.with(isoDate);
+        assertEquals(test, LocalDate.of(1728, 10, 29));
+    }
+
+    @Test(groups={"tck"})
+    public void test_LocalDateTime_adjustToISODate() {
+        ChronoLocalDate<ISOChrono> isoDate = ISOChrono.INSTANCE.date(1728, 10, 29);
+        LocalDateTime test = LocalDateTime.MIN.with(isoDate);
+        assertEquals(test, LocalDateTime.of(1728, 10, 29, 0, 0));
+    }
+
+    //-----------------------------------------------------------------------
+    // isLeapYear()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="leapYears")
+    Object[][] leapYearInformation() {
+        return new Object[][] {
+                {2000, true},
+                {1996, true},
+                {1600, true},
+
+                {1900, false},
+                {2100, false},
+        };
+    }
+
+    @Test(dataProvider="leapYears", groups="tck")
+    public void test_isLeapYear(int year, boolean isLeapYear) {
+        assertEquals(ISOChrono.INSTANCE.isLeapYear(year), isLeapYear);
+    }
+
+    //-----------------------------------------------------------------------
+    // toString()
+    //-----------------------------------------------------------------------
+    @Test(groups="tck")
+    public void test_now() {
+        assertEquals(LocalDate.from(ISOChrono.INSTANCE.dateNow()), LocalDate.now());
+    }
+
+    //-----------------------------------------------------------------------
+    // toString()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="toString")
+    Object[][] data_toString() {
+        return new Object[][] {
+            {ISOChrono.INSTANCE.date(1, 1, 1), "0001-01-01"},
+            {ISOChrono.INSTANCE.date(1728, 10, 28), "1728-10-28"},
+            {ISOChrono.INSTANCE.date(1728, 10, 29), "1728-10-29"},
+            {ISOChrono.INSTANCE.date(1727, 12, 5), "1727-12-05"},
+            {ISOChrono.INSTANCE.date(1727, 12, 6), "1727-12-06"},
+        };
+    }
+
+    @Test(dataProvider="toString", groups={"tck"})
+    public void test_toString(ChronoLocalDate<ISOChrono> isoDate, String expected) {
+        assertEquals(isoDate.toString(), expected);
+    }
+
+    //-----------------------------------------------------------------------
+    // equals()
+    //-----------------------------------------------------------------------
+    @Test(groups="tck")
+    public void test_equals_true() {
+        assertTrue(ISOChrono.INSTANCE.equals(ISOChrono.INSTANCE));
+    }
+
+    @Test(groups="tck")
+    public void test_equals_false() {
+        assertFalse(ISOChrono.INSTANCE.equals(HijrahChrono.INSTANCE));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/zone/TCKFixedZoneRules.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2010-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.zone;
+
+import java.time.zone.*;
+import test.java.time.zone.*;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.Month;
+import java.time.ZoneOffset;
+import java.time.zone.ZoneOffsetTransitionRule.TimeDefinition;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test ZoneRules for fixed offset time-zones.
+ */
+@Test
+public class TCKFixedZoneRules {
+
+    private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1);
+    private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2);
+    private static final ZoneOffset OFFSET_M18 = ZoneOffset.ofHours(-18);
+    private static final LocalDateTime LDT = LocalDateTime.of(2010, 12, 3, 11, 30);
+    private static final Instant INSTANT = LDT.toInstant(OFFSET_PONE);
+
+    private ZoneRules make(ZoneOffset offset) {
+        return offset.getRules();
+    }
+
+    @DataProvider(name="rules")
+    Object[][] data_rules() {
+        return new Object[][] {
+            {make(OFFSET_PONE), OFFSET_PONE},
+            {make(OFFSET_PTWO), OFFSET_PTWO},
+            {make(OFFSET_M18), OFFSET_M18},
+        };
+    }
+
+    //-----------------------------------------------------------------------
+    // Basics
+    //-----------------------------------------------------------------------
+    @Test(groups="tck", dataProvider="rules")
+    public void test_serialization(ZoneRules test, ZoneOffset expectedOffset) throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream(baos);
+        out.writeObject(test);
+        baos.close();
+        byte[] bytes = baos.toByteArray();
+
+        ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+        ObjectInputStream in = new ObjectInputStream(bais);
+        ZoneRules result = (ZoneRules) in.readObject();
+
+        assertEquals(result, test);
+        assertEquals(result.getClass(), test.getClass());
+    }
+
+    //-----------------------------------------------------------------------
+    // basics
+    //-----------------------------------------------------------------------
+    @Test(groups="tck", dataProvider="rules")
+    public void test_getOffset_Instant(ZoneRules test, ZoneOffset expectedOffset) {
+        assertEquals(test.getOffset(INSTANT), expectedOffset);
+        assertEquals(test.getOffset((Instant) null), expectedOffset);
+    }
+
+    @Test(groups="tck", dataProvider="rules")
+    public void test_getOffset_LocalDateTime(ZoneRules test, ZoneOffset expectedOffset) {
+        assertEquals(test.getOffset(LDT), expectedOffset);
+        assertEquals(test.getOffset((LocalDateTime) null), expectedOffset);
+    }
+
+    @Test(groups="tck", dataProvider="rules")
+    public void test_getValidOffsets_LDT(ZoneRules test, ZoneOffset expectedOffset) {
+        assertEquals(test.getValidOffsets(LDT).size(), 1);
+        assertEquals(test.getValidOffsets(LDT).get(0), expectedOffset);
+        assertEquals(test.getValidOffsets(null).size(), 1);
+        assertEquals(test.getValidOffsets(null).get(0), expectedOffset);
+    }
+
+    @Test(groups="tck", dataProvider="rules")
+    public void test_getTransition_LDT(ZoneRules test, ZoneOffset expectedOffset) {
+        assertEquals(test.getTransition(LDT), null);
+        assertEquals(test.getTransition(null), null);
+    }
+
+    @Test(groups="tck", dataProvider="rules")
+    public void test_isValidOffset_LDT_ZO(ZoneRules test, ZoneOffset expectedOffset) {
+        assertEquals(test.isValidOffset(LDT, expectedOffset), true);
+        assertEquals(test.isValidOffset(LDT, ZoneOffset.UTC), false);
+        assertEquals(test.isValidOffset(LDT, null), false);
+
+        assertEquals(test.isValidOffset(null, expectedOffset), true);
+        assertEquals(test.isValidOffset(null, ZoneOffset.UTC), false);
+        assertEquals(test.isValidOffset(null, null), false);
+    }
+
+    @Test(groups="tck", dataProvider="rules")
+    public void test_getStandardOffset_Instant(ZoneRules test, ZoneOffset expectedOffset) {
+        assertEquals(test.getStandardOffset(INSTANT), expectedOffset);
+        assertEquals(test.getStandardOffset(null), expectedOffset);
+    }
+
+    @Test(groups="tck", dataProvider="rules")
+    public void test_getDaylightSavings_Instant(ZoneRules test, ZoneOffset expectedOffset) {
+        assertEquals(test.getDaylightSavings(INSTANT), Duration.ZERO);
+        assertEquals(test.getDaylightSavings(null), Duration.ZERO);
+    }
+
+    @Test(groups="tck", dataProvider="rules")
+    public void test_isDaylightSavings_Instant(ZoneRules test, ZoneOffset expectedOffset) {
+        assertEquals(test.isDaylightSavings(INSTANT), false);
+        assertEquals(test.isDaylightSavings(null), false);
+    }
+
+    //-------------------------------------------------------------------------
+    @Test(groups="tck", dataProvider="rules")
+    public void test_nextTransition_Instant(ZoneRules test, ZoneOffset expectedOffset) {
+        assertEquals(test.nextTransition(INSTANT), null);
+        assertEquals(test.nextTransition(null), null);
+    }
+
+    @Test(groups="tck", dataProvider="rules")
+    public void test_previousTransition_Instant(ZoneRules test, ZoneOffset expectedOffset) {
+        assertEquals(test.previousTransition(INSTANT), null);
+        assertEquals(test.previousTransition(null), null);
+    }
+
+    //-------------------------------------------------------------------------
+    @Test(groups="tck", dataProvider="rules")
+    public void test_getTransitions(ZoneRules test, ZoneOffset expectedOffset) {
+        assertEquals(test.getTransitions().size(), 0);
+    }
+
+    @Test(expectedExceptions=UnsupportedOperationException.class, groups="tck")
+    public void test_getTransitions_immutable() {
+        ZoneRules test = make(OFFSET_PTWO);
+        test.getTransitions().add(ZoneOffsetTransition.of(LDT, OFFSET_PONE, OFFSET_PTWO));
+    }
+
+    @Test(groups="tck", dataProvider="rules")
+    public void test_getTransitionRules(ZoneRules test, ZoneOffset expectedOffset) {
+        assertEquals(test.getTransitionRules().size(), 0);
+    }
+
+    @Test(expectedExceptions=UnsupportedOperationException.class, groups="tck")
+    public void test_getTransitionRules_immutable() {
+        ZoneRules test = make(OFFSET_PTWO);
+        test.getTransitionRules().add(ZoneOffsetTransitionRule.of(Month.JULY, 2, null, LocalTime.of(12, 30), false, TimeDefinition.STANDARD, OFFSET_PONE, OFFSET_PTWO, OFFSET_PONE));
+    }
+
+    //-----------------------------------------------------------------------
+    // equals() / hashCode()
+    //-----------------------------------------------------------------------
+    @Test(groups="tck")
+    public void test_equalsHashCode() {
+        ZoneRules a = make(OFFSET_PONE);
+        ZoneRules b = make(OFFSET_PTWO);
+
+        assertEquals(a.equals(a), true);
+        assertEquals(a.equals(b), false);
+        assertEquals(b.equals(a), false);
+        assertEquals(b.equals(b), true);
+
+        assertEquals(a.equals("Rubbish"), false);
+        assertEquals(a.equals(null), false);
+
+        assertEquals(a.hashCode() == a.hashCode(), true);
+        assertEquals(b.hashCode() == b.hashCode(), true);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/zone/TCKZoneOffsetTransition.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2010-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.zone;
+
+import java.time.temporal.Year;
+import java.time.zone.*;
+
+import static java.time.temporal.ChronoUnit.HOURS;
+import static org.testng.Assert.assertEquals;
+
+import java.io.IOException;
+
+import tck.java.time.AbstractTCKTest;
+import java.time.Duration;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test ZoneOffsetTransition.
+ */
+@Test
+public class TCKZoneOffsetTransition extends AbstractTCKTest {
+
+    private static final ZoneOffset OFFSET_0100 = ZoneOffset.ofHours(1);
+    private static final ZoneOffset OFFSET_0200 = ZoneOffset.ofHours(2);
+    private static final ZoneOffset OFFSET_0230 = ZoneOffset.ofHoursMinutes(2, 30);
+    private static final ZoneOffset OFFSET_0300 = ZoneOffset.ofHours(3);
+    private static final ZoneOffset OFFSET_0400 = ZoneOffset.ofHours(4);
+
+    //-----------------------------------------------------------------------
+    // factory
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_factory_nullTransition() {
+        ZoneOffsetTransition.of(null, OFFSET_0100, OFFSET_0200);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_factory_nullOffsetBefore() {
+        ZoneOffsetTransition.of(LocalDateTime.of(2010, 12, 3, 11, 30), null, OFFSET_0200);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_factory_nullOffsetAfter() {
+        ZoneOffsetTransition.of(LocalDateTime.of(2010, 12, 3, 11, 30), OFFSET_0200, null);
+    }
+
+    @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"})
+    public void test_factory_sameOffset() {
+        ZoneOffsetTransition.of(LocalDateTime.of(2010, 12, 3, 11, 30), OFFSET_0200, OFFSET_0200);
+    }
+
+    @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"})
+    public void test_factory_noNanos() {
+        ZoneOffsetTransition.of(LocalDateTime.of(2010, 12, 3, 11, 30, 0, 500), OFFSET_0200, OFFSET_0300);
+    }
+
+    //-----------------------------------------------------------------------
+    // getters
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_getters_gap() throws Exception {
+        LocalDateTime before = LocalDateTime.of(2010, 3, 31, 1, 0);
+        LocalDateTime after = LocalDateTime.of(2010, 3, 31, 2, 0);
+        ZoneOffsetTransition test = ZoneOffsetTransition.of(before, OFFSET_0200, OFFSET_0300);
+        assertEquals(test.isGap(), true);
+        assertEquals(test.isOverlap(), false);
+        assertEquals(test.getDateTimeBefore(), before);
+        assertEquals(test.getDateTimeAfter(), after);
+        assertEquals(test.getInstant(), before.toInstant(OFFSET_0200));
+        assertEquals(test.getOffsetBefore(), OFFSET_0200);
+        assertEquals(test.getOffsetAfter(), OFFSET_0300);
+        assertEquals(test.getDuration(), Duration.of(1, HOURS));
+        assertSerializable(test);
+    }
+
+    @Test(groups={"tck"})
+    public void test_getters_overlap() throws Exception {
+        LocalDateTime before = LocalDateTime.of(2010, 10, 31, 1, 0);
+        LocalDateTime after = LocalDateTime.of(2010, 10, 31, 0, 0);
+        ZoneOffsetTransition test = ZoneOffsetTransition.of(before, OFFSET_0300, OFFSET_0200);
+        assertEquals(test.isGap(), false);
+        assertEquals(test.isOverlap(), true);
+        assertEquals(test.getDateTimeBefore(), before);
+        assertEquals(test.getDateTimeAfter(), after);
+        assertEquals(test.getInstant(), before.toInstant(OFFSET_0300));
+        assertEquals(test.getOffsetBefore(), OFFSET_0300);
+        assertEquals(test.getOffsetAfter(), OFFSET_0200);
+        assertEquals(test.getDuration(), Duration.of(-1, HOURS));
+        assertSerializable(test);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_serialization_unusual1() throws Exception {
+        LocalDateTime ldt = LocalDateTime.of(Year.MAX_VALUE, 12, 31, 1, 31, 53);
+        ZoneOffsetTransition test = ZoneOffsetTransition.of(ldt, ZoneOffset.of("+02:04:56"), ZoneOffset.of("-10:02:34"));
+        assertSerializable(test);
+    }
+
+    @Test
+    public void test_serialization_unusual2() throws Exception {
+        LocalDateTime ldt = LocalDateTime.of(Year.MIN_VALUE, 1, 1, 12, 1, 3);
+        ZoneOffsetTransition test = ZoneOffsetTransition.of(ldt, ZoneOffset.of("+02:04:56"), ZoneOffset.of("+10:02:34"));
+        assertSerializable(test);
+    }
+
+    //-----------------------------------------------------------------------
+    // isValidOffset()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_isValidOffset_gap() {
+        LocalDateTime ldt = LocalDateTime.of(2010, 3, 31, 1, 0);
+        ZoneOffsetTransition test = ZoneOffsetTransition.of(ldt, OFFSET_0200, OFFSET_0300);
+        assertEquals(test.isValidOffset(OFFSET_0100), false);
+        assertEquals(test.isValidOffset(OFFSET_0200), false);
+        assertEquals(test.isValidOffset(OFFSET_0230), false);
+        assertEquals(test.isValidOffset(OFFSET_0300), false);
+        assertEquals(test.isValidOffset(OFFSET_0400), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_isValidOffset_overlap() {
+        LocalDateTime ldt = LocalDateTime.of(2010, 10, 31, 1, 0);
+        ZoneOffsetTransition test = ZoneOffsetTransition.of(ldt, OFFSET_0300, OFFSET_0200);
+        assertEquals(test.isValidOffset(OFFSET_0100), false);
+        assertEquals(test.isValidOffset(OFFSET_0200), true);
+        assertEquals(test.isValidOffset(OFFSET_0230), false);
+        assertEquals(test.isValidOffset(OFFSET_0300), true);
+        assertEquals(test.isValidOffset(OFFSET_0400), false);
+    }
+
+    //-----------------------------------------------------------------------
+    // compareTo()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_compareTo() {
+        ZoneOffsetTransition a = ZoneOffsetTransition.of(
+            LocalDateTime.ofEpochSecond(23875287L - 1, 0, OFFSET_0200), OFFSET_0200, OFFSET_0300);
+        ZoneOffsetTransition b = ZoneOffsetTransition.of(
+            LocalDateTime.ofEpochSecond(23875287L, 0, OFFSET_0300), OFFSET_0300, OFFSET_0200);
+        ZoneOffsetTransition c = ZoneOffsetTransition.of(
+            LocalDateTime.ofEpochSecond(23875287L + 1, 0, OFFSET_0100), OFFSET_0100,OFFSET_0400);
+
+        assertEquals(a.compareTo(a) == 0, true);
+        assertEquals(a.compareTo(b) < 0, true);
+        assertEquals(a.compareTo(c) < 0, true);
+
+        assertEquals(b.compareTo(a) > 0, true);
+        assertEquals(b.compareTo(b) == 0, true);
+        assertEquals(b.compareTo(c) < 0, true);
+
+        assertEquals(c.compareTo(a) > 0, true);
+        assertEquals(c.compareTo(b) > 0, true);
+        assertEquals(c.compareTo(c) == 0, true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_compareTo_sameInstant() {
+        ZoneOffsetTransition a = ZoneOffsetTransition.of(
+            LocalDateTime.ofEpochSecond(23875287L, 0, OFFSET_0200), OFFSET_0200, OFFSET_0300);
+        ZoneOffsetTransition b = ZoneOffsetTransition.of(
+            LocalDateTime.ofEpochSecond(23875287L, 0, OFFSET_0300), OFFSET_0300, OFFSET_0200);
+        ZoneOffsetTransition c = ZoneOffsetTransition.of(
+            LocalDateTime.ofEpochSecond(23875287L, 0, OFFSET_0100), OFFSET_0100, OFFSET_0400);
+
+        assertEquals(a.compareTo(a) == 0, true);
+        assertEquals(a.compareTo(b) == 0, true);
+        assertEquals(a.compareTo(c) == 0, true);
+
+        assertEquals(b.compareTo(a) == 0, true);
+        assertEquals(b.compareTo(b) == 0, true);
+        assertEquals(b.compareTo(c) == 0, true);
+
+        assertEquals(c.compareTo(a) == 0, true);
+        assertEquals(c.compareTo(b) == 0, true);
+        assertEquals(c.compareTo(c) == 0, true);
+    }
+
+    //-----------------------------------------------------------------------
+    // equals()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_equals() {
+        LocalDateTime ldtA = LocalDateTime.of(2010, 3, 31, 1, 0);
+        ZoneOffsetTransition a1 = ZoneOffsetTransition.of(ldtA, OFFSET_0200, OFFSET_0300);
+        ZoneOffsetTransition a2 = ZoneOffsetTransition.of(ldtA, OFFSET_0200, OFFSET_0300);
+        LocalDateTime ldtB = LocalDateTime.of(2010, 10, 31, 1, 0);
+        ZoneOffsetTransition b = ZoneOffsetTransition.of(ldtB, OFFSET_0300, OFFSET_0200);
+
+        assertEquals(a1.equals(a1), true);
+        assertEquals(a1.equals(a2), true);
+        assertEquals(a1.equals(b), false);
+        assertEquals(a2.equals(a1), true);
+        assertEquals(a2.equals(a2), true);
+        assertEquals(a2.equals(b), false);
+        assertEquals(b.equals(a1), false);
+        assertEquals(b.equals(a2), false);
+        assertEquals(b.equals(b), true);
+
+        assertEquals(a1.equals(""), false);
+        assertEquals(a1.equals(null), false);
+    }
+
+    //-----------------------------------------------------------------------
+    // hashCode()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_hashCode_floatingWeek_gap_notEndOfDay() {
+        LocalDateTime ldtA = LocalDateTime.of(2010, 3, 31, 1, 0);
+        ZoneOffsetTransition a1 = ZoneOffsetTransition.of(ldtA, OFFSET_0200, OFFSET_0300);
+        ZoneOffsetTransition a2 = ZoneOffsetTransition.of(ldtA, OFFSET_0200, OFFSET_0300);
+        LocalDateTime ldtB = LocalDateTime.of(2010, 10, 31, 1, 0);
+        ZoneOffsetTransition b = ZoneOffsetTransition.of(ldtB, OFFSET_0300, OFFSET_0200);
+
+        assertEquals(a1.hashCode(), a1.hashCode());
+        assertEquals(a1.hashCode(), a2.hashCode());
+        assertEquals(b.hashCode(), b.hashCode());
+    }
+
+    //-----------------------------------------------------------------------
+    // toString()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_toString_gap() {
+        LocalDateTime ldt = LocalDateTime.of(2010, 3, 31, 1, 0);
+        ZoneOffsetTransition test = ZoneOffsetTransition.of(ldt, OFFSET_0200, OFFSET_0300);
+        assertEquals(test.toString(), "Transition[Gap at 2010-03-31T01:00+02:00 to +03:00]");
+    }
+
+    @Test(groups={"tck"})
+    public void test_toString_overlap() {
+        LocalDateTime ldt = LocalDateTime.of(2010, 10, 31, 1, 0);
+        ZoneOffsetTransition test = ZoneOffsetTransition.of(ldt, OFFSET_0300, OFFSET_0200);
+        assertEquals(test.toString(), "Transition[Overlap at 2010-10-31T01:00+03:00 to +02:00]");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/zone/TCKZoneOffsetTransitionRule.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,557 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2010-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.zone;
+
+import java.time.ZoneId;
+import java.time.zone.*;
+import test.java.time.zone.*;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import tck.java.time.AbstractTCKTest;
+import java.time.DayOfWeek;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.Month;
+import java.time.ZoneOffset;
+import java.time.zone.ZoneOffsetTransitionRule.TimeDefinition;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test ZoneOffsetTransitionRule.
+ */
+@Test
+public class TCKZoneOffsetTransitionRule extends AbstractTCKTest {
+
+    private static final LocalTime TIME_0100 = LocalTime.of(1, 0);
+    private static final ZoneOffset OFFSET_0200 = ZoneOffset.ofHours(2);
+    private static final ZoneOffset OFFSET_0300 = ZoneOffset.ofHours(3);
+
+    //-----------------------------------------------------------------------
+    // factory
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_factory_nullMonth() {
+        ZoneOffsetTransitionRule.of(
+                null, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_factory_nullTime() {
+        ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SUNDAY, null, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_factory_nullTimeDefinition() {
+        ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, null,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_factory_nullStandardOffset() {
+        ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                null, OFFSET_0200, OFFSET_0300);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_factory_nullOffsetBefore() {
+        ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, null, OFFSET_0300);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
+    public void test_factory_nullOffsetAfter() {
+        ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, null);
+    }
+
+    @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"})
+    public void test_factory_invalidDayOfMonthIndicator_tooSmall() {
+        ZoneOffsetTransitionRule.of(
+                Month.MARCH, -29, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+    }
+
+    @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"})
+    public void test_factory_invalidDayOfMonthIndicator_zero() {
+        ZoneOffsetTransitionRule.of(
+                Month.MARCH, 0, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+    }
+
+    @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"})
+    public void test_factory_invalidDayOfMonthIndicator_tooLarge() {
+        ZoneOffsetTransitionRule.of(
+                Month.MARCH, 32, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+    }
+
+    @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"})
+    public void test_factory_invalidMidnightFlag() {
+        ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, true, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+    }
+
+    //-----------------------------------------------------------------------
+    // getters
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_getters_floatingWeek() throws Exception {
+        ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        assertEquals(test.getMonth(), Month.MARCH);
+        assertEquals(test.getDayOfMonthIndicator(), 20);
+        assertEquals(test.getDayOfWeek(), DayOfWeek.SUNDAY);
+        assertEquals(test.getLocalTime(), TIME_0100);
+        assertEquals(test.isMidnightEndOfDay(), false);
+        assertEquals(test.getTimeDefinition(), TimeDefinition.WALL);
+        assertEquals(test.getStandardOffset(), OFFSET_0200);
+        assertEquals(test.getOffsetBefore(), OFFSET_0200);
+        assertEquals(test.getOffsetAfter(), OFFSET_0300);
+        assertSerializable(test);
+    }
+
+    @Test
+    public void test_getters_floatingWeekBackwards() throws Exception {
+        ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of(
+                Month.MARCH, -1, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        assertEquals(test.getMonth(), Month.MARCH);
+        assertEquals(test.getDayOfMonthIndicator(), -1);
+        assertEquals(test.getDayOfWeek(), DayOfWeek.SUNDAY);
+        assertEquals(test.getLocalTime(), TIME_0100);
+        assertEquals(test.isMidnightEndOfDay(), false);
+        assertEquals(test.getTimeDefinition(), TimeDefinition.WALL);
+        assertEquals(test.getStandardOffset(), OFFSET_0200);
+        assertEquals(test.getOffsetBefore(), OFFSET_0200);
+        assertEquals(test.getOffsetAfter(), OFFSET_0300);
+        assertSerializable(test);
+    }
+
+    @Test
+    public void test_getters_fixedDate() throws Exception {
+        ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, null, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        assertEquals(test.getMonth(), Month.MARCH);
+        assertEquals(test.getDayOfMonthIndicator(), 20);
+        assertEquals(test.getDayOfWeek(), null);
+        assertEquals(test.getLocalTime(), TIME_0100);
+        assertEquals(test.isMidnightEndOfDay(), false);
+        assertEquals(test.getTimeDefinition(), TimeDefinition.WALL);
+        assertEquals(test.getStandardOffset(), OFFSET_0200);
+        assertEquals(test.getOffsetBefore(), OFFSET_0200);
+        assertEquals(test.getOffsetAfter(), OFFSET_0300);
+        assertSerializable(test);
+    }
+
+    @Test
+    public void test_serialization_unusualOffsets() throws Exception {
+        ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, null, TIME_0100, false, TimeDefinition.STANDARD,
+                ZoneOffset.ofHoursMinutesSeconds(-12, -20, -50),
+                ZoneOffset.ofHoursMinutesSeconds(-4, -10, -34),
+                ZoneOffset.ofHours(-18));
+        assertSerializable(test);
+    }
+
+    @Test
+    public void test_serialization_endOfDay() throws Exception {
+        ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.FRIDAY, LocalTime.MIDNIGHT, true, TimeDefinition.UTC,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        assertSerializable(test);
+    }
+
+    @Test
+    public void test_serialization_unusualTime() throws Exception {
+        ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.WEDNESDAY, LocalTime.of(13, 34, 56), false, TimeDefinition.STANDARD,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        assertSerializable(test);
+    }
+
+    //-----------------------------------------------------------------------
+    // createTransition()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_createTransition_floatingWeek_gap_notEndOfDay() {
+        ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        ZoneOffsetTransition trans = ZoneOffsetTransition.of(
+                LocalDateTime.of(2000, Month.MARCH, 26, 1, 0), OFFSET_0200, OFFSET_0300);
+        assertEquals(test.createTransition(2000), trans);
+    }
+
+    @Test(groups={"tck"})
+    public void test_createTransition_floatingWeek_overlap_endOfDay() {
+        ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SUNDAY, LocalTime.MIDNIGHT, true, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0300, OFFSET_0200);
+        ZoneOffsetTransition trans = ZoneOffsetTransition.of(
+                LocalDateTime.of(2000, Month.MARCH, 27, 0, 0), OFFSET_0300, OFFSET_0200);
+        assertEquals(test.createTransition(2000), trans);
+    }
+
+    @Test(groups={"tck"})
+    public void test_createTransition_floatingWeekBackwards_last() {
+        ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of(
+                Month.MARCH, -1, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        ZoneOffsetTransition trans = ZoneOffsetTransition.of(
+                LocalDateTime.of(2000, Month.MARCH, 26, 1, 0), OFFSET_0200, OFFSET_0300);
+        assertEquals(test.createTransition(2000), trans);
+    }
+
+    @Test(groups={"tck"})
+    public void test_createTransition_floatingWeekBackwards_seventhLast() {
+        ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of(
+                Month.MARCH, -7, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        ZoneOffsetTransition trans = ZoneOffsetTransition.of(
+                LocalDateTime.of(2000, Month.MARCH, 19, 1, 0), OFFSET_0200, OFFSET_0300);
+        assertEquals(test.createTransition(2000), trans);
+    }
+
+    @Test(groups={"tck"})
+    public void test_createTransition_floatingWeekBackwards_secondLast() {
+        ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of(
+                Month.MARCH, -2, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        ZoneOffsetTransition trans = ZoneOffsetTransition.of(
+                LocalDateTime.of(2000, Month.MARCH, 26, 1, 0), OFFSET_0200, OFFSET_0300);
+        assertEquals(test.createTransition(2000), trans);
+    }
+
+    @Test(groups={"tck"})
+    public void test_createTransition_fixedDate() {
+        ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, null, TIME_0100, false, TimeDefinition.STANDARD,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        ZoneOffsetTransition trans = ZoneOffsetTransition.of(
+                LocalDateTime.of(2000, Month.MARCH, 20, 1, 0), OFFSET_0200, OFFSET_0300);
+        assertEquals(test.createTransition(2000), trans);
+    }
+
+    //-----------------------------------------------------------------------
+    // equals()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_equals_monthDifferent() {
+        ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        ZoneOffsetTransitionRule b = ZoneOffsetTransitionRule.of(
+                Month.APRIL, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        assertEquals(a.equals(a), true);
+        assertEquals(a.equals(b), false);
+        assertEquals(b.equals(a), false);
+        assertEquals(b.equals(b), true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_dayOfMonthDifferent() {
+        ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        ZoneOffsetTransitionRule b = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 21, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        assertEquals(a.equals(a), true);
+        assertEquals(a.equals(b), false);
+        assertEquals(b.equals(a), false);
+        assertEquals(b.equals(b), true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_dayOfWeekDifferent() {
+        ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        ZoneOffsetTransitionRule b = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SATURDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        assertEquals(a.equals(a), true);
+        assertEquals(a.equals(b), false);
+        assertEquals(b.equals(a), false);
+        assertEquals(b.equals(b), true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_dayOfWeekDifferentNull() {
+        ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        ZoneOffsetTransitionRule b = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, null, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        assertEquals(a.equals(a), true);
+        assertEquals(a.equals(b), false);
+        assertEquals(b.equals(a), false);
+        assertEquals(b.equals(b), true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_localTimeDifferent() {
+        ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        ZoneOffsetTransitionRule b = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SUNDAY, LocalTime.MIDNIGHT, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        assertEquals(a.equals(a), true);
+        assertEquals(a.equals(b), false);
+        assertEquals(b.equals(a), false);
+        assertEquals(b.equals(b), true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_endOfDayDifferent() {
+        ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SUNDAY, LocalTime.MIDNIGHT, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        ZoneOffsetTransitionRule b = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SUNDAY, LocalTime.MIDNIGHT, true, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        assertEquals(a.equals(a), true);
+        assertEquals(a.equals(b), false);
+        assertEquals(b.equals(a), false);
+        assertEquals(b.equals(b), true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_timeDefinitionDifferent() {
+        ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        ZoneOffsetTransitionRule b = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.STANDARD,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        assertEquals(a.equals(a), true);
+        assertEquals(a.equals(b), false);
+        assertEquals(b.equals(a), false);
+        assertEquals(b.equals(b), true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_standardOffsetDifferent() {
+        ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        ZoneOffsetTransitionRule b = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0300, OFFSET_0200, OFFSET_0300);
+        assertEquals(a.equals(a), true);
+        assertEquals(a.equals(b), false);
+        assertEquals(b.equals(a), false);
+        assertEquals(b.equals(b), true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_offsetBeforeDifferent() {
+        ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        ZoneOffsetTransitionRule b = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0300, OFFSET_0300);
+        assertEquals(a.equals(a), true);
+        assertEquals(a.equals(b), false);
+        assertEquals(b.equals(a), false);
+        assertEquals(b.equals(b), true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_offsetAfterDifferent() {
+        ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        ZoneOffsetTransitionRule b = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0200);
+        assertEquals(a.equals(a), true);
+        assertEquals(a.equals(b), false);
+        assertEquals(b.equals(a), false);
+        assertEquals(b.equals(b), true);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_string_false() {
+        ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        assertEquals(a.equals("TZDB"), false);
+    }
+
+    @Test(groups={"tck"})
+    public void test_equals_null_false() {
+        ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        assertEquals(a.equals(null), false);
+    }
+
+    //-----------------------------------------------------------------------
+    // hashCode()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_hashCode_floatingWeek_gap_notEndOfDay() {
+        ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        ZoneOffsetTransitionRule b = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        assertEquals(a.hashCode(), b.hashCode());
+    }
+
+    @Test(groups={"tck"})
+    public void test_hashCode_floatingWeek_overlap_endOfDay_nullDayOfWeek() {
+        ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of(
+                Month.OCTOBER, 20, null, LocalTime.MIDNIGHT, true, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0300, OFFSET_0200);
+        ZoneOffsetTransitionRule b = ZoneOffsetTransitionRule.of(
+                Month.OCTOBER, 20, null, LocalTime.MIDNIGHT, true, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0300, OFFSET_0200);
+        assertEquals(a.hashCode(), b.hashCode());
+    }
+
+    @Test(groups={"tck"})
+    public void test_hashCode_floatingWeekBackwards() {
+        ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of(
+                Month.MARCH, -1, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        ZoneOffsetTransitionRule b = ZoneOffsetTransitionRule.of(
+                Month.MARCH, -1, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        assertEquals(a.hashCode(), b.hashCode());
+    }
+
+    @Test(groups={"tck"})
+    public void test_hashCode_fixedDate() {
+        ZoneOffsetTransitionRule a = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, null, TIME_0100, false, TimeDefinition.STANDARD,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        ZoneOffsetTransitionRule b = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, null, TIME_0100, false, TimeDefinition.STANDARD,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        assertEquals(a.hashCode(), b.hashCode());
+    }
+
+    //-----------------------------------------------------------------------
+    // toString()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_toString_floatingWeek_gap_notEndOfDay() {
+        ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        assertEquals(test.toString(), "TransitionRule[Gap +02:00 to +03:00, SUNDAY on or after MARCH 20 at 01:00 WALL, standard offset +02:00]");
+    }
+
+    @Test(groups={"tck"})
+    public void test_toString_floatingWeek_overlap_endOfDay() {
+        ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of(
+                Month.OCTOBER, 20, DayOfWeek.SUNDAY, LocalTime.MIDNIGHT, true, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0300, OFFSET_0200);
+        assertEquals(test.toString(), "TransitionRule[Overlap +03:00 to +02:00, SUNDAY on or after OCTOBER 20 at 24:00 WALL, standard offset +02:00]");
+    }
+
+    @Test(groups={"tck"})
+    public void test_toString_floatingWeekBackwards_last() {
+        ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of(
+                Month.MARCH, -1, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        assertEquals(test.toString(), "TransitionRule[Gap +02:00 to +03:00, SUNDAY on or before last day of MARCH at 01:00 WALL, standard offset +02:00]");
+    }
+
+    @Test(groups={"tck"})
+    public void test_toString_floatingWeekBackwards_secondLast() {
+        ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of(
+                Month.MARCH, -2, DayOfWeek.SUNDAY, TIME_0100, false, TimeDefinition.WALL,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        assertEquals(test.toString(), "TransitionRule[Gap +02:00 to +03:00, SUNDAY on or before last day minus 1 of MARCH at 01:00 WALL, standard offset +02:00]");
+    }
+
+    @Test(groups={"tck"})
+    public void test_toString_fixedDate() {
+        ZoneOffsetTransitionRule test = ZoneOffsetTransitionRule.of(
+                Month.MARCH, 20, null, TIME_0100, false, TimeDefinition.STANDARD,
+                OFFSET_0200, OFFSET_0200, OFFSET_0300);
+        assertEquals(test.toString(), "TransitionRule[Gap +02:00 to +03:00, MARCH 20 at 01:00 STANDARD, standard offset +02:00]");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/zone/TCKZoneRules.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,1005 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.zone;
+
+import java.time.temporal.Year;
+import java.time.zone.*;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Iterator;
+import java.util.List;
+
+import java.time.DayOfWeek;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.Month;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.zone.ZoneOffsetTransitionRule.TimeDefinition;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test ZoneRules.
+ */
+@Test
+public class TCKZoneRules {
+
+    private static final ZoneOffset OFFSET_ZERO = ZoneOffset.ofHours(0);
+    private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1);
+    private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2);
+    public static final String LATEST_TZDB = "2009b";
+    private static final int OVERLAP = 2;
+    private static final int GAP = 0;
+
+    //-----------------------------------------------------------------------
+    // Basics
+    //-----------------------------------------------------------------------
+    public void test_serialization_loaded() throws Exception {
+        assertSerialization(europeLondon());
+        assertSerialization(europeParis());
+        assertSerialization(americaNewYork());
+    }
+
+    private void assertSerialization(ZoneRules test) throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream(baos);
+        out.writeObject(test);
+        baos.close();
+        byte[] bytes = baos.toByteArray();
+
+        ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+        ObjectInputStream in = new ObjectInputStream(bais);
+        ZoneRules result = (ZoneRules) in.readObject();
+
+        assertEquals(result, test);
+    }
+
+    //-----------------------------------------------------------------------
+    // Europe/London
+    //-----------------------------------------------------------------------
+    private ZoneRules europeLondon() {
+        return ZoneId.of("Europe/London").getRules();
+    }
+
+    public void test_London() {
+        ZoneRules test = europeLondon();
+        assertEquals(test.isFixedOffset(), false);
+    }
+
+    public void test_London_preTimeZones() {
+        ZoneRules test = europeLondon();
+        ZonedDateTime old = createZDT(1800, 1, 1, ZoneOffset.UTC);
+        Instant instant = old.toInstant();
+        ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(0, -1, -15);
+        assertEquals(test.getOffset(instant), offset);
+        checkOffset(test, old.getDateTime(), offset, 1);
+        assertEquals(test.getStandardOffset(instant), offset);
+        assertEquals(test.getDaylightSavings(instant), Duration.ZERO);
+        assertEquals(test.isDaylightSavings(instant), false);
+    }
+
+    public void test_London_getOffset() {
+        ZoneRules test = europeLondon();
+        assertEquals(test.getOffset(createInstant(2008, 1, 1, ZoneOffset.UTC)), OFFSET_ZERO);
+        assertEquals(test.getOffset(createInstant(2008, 2, 1, ZoneOffset.UTC)), OFFSET_ZERO);
+        assertEquals(test.getOffset(createInstant(2008, 3, 1, ZoneOffset.UTC)), OFFSET_ZERO);
+        assertEquals(test.getOffset(createInstant(2008, 4, 1, ZoneOffset.UTC)), OFFSET_PONE);
+        assertEquals(test.getOffset(createInstant(2008, 5, 1, ZoneOffset.UTC)), OFFSET_PONE);
+        assertEquals(test.getOffset(createInstant(2008, 6, 1, ZoneOffset.UTC)), OFFSET_PONE);
+        assertEquals(test.getOffset(createInstant(2008, 7, 1, ZoneOffset.UTC)), OFFSET_PONE);
+        assertEquals(test.getOffset(createInstant(2008, 8, 1, ZoneOffset.UTC)), OFFSET_PONE);
+        assertEquals(test.getOffset(createInstant(2008, 9, 1, ZoneOffset.UTC)), OFFSET_PONE);
+        assertEquals(test.getOffset(createInstant(2008, 10, 1, ZoneOffset.UTC)), OFFSET_PONE);
+        assertEquals(test.getOffset(createInstant(2008, 11, 1, ZoneOffset.UTC)), OFFSET_ZERO);
+        assertEquals(test.getOffset(createInstant(2008, 12, 1, ZoneOffset.UTC)), OFFSET_ZERO);
+    }
+
+    public void test_London_getOffset_toDST() {
+        ZoneRules test = europeLondon();
+        assertEquals(test.getOffset(createInstant(2008, 3, 24, ZoneOffset.UTC)), OFFSET_ZERO);
+        assertEquals(test.getOffset(createInstant(2008, 3, 25, ZoneOffset.UTC)), OFFSET_ZERO);
+        assertEquals(test.getOffset(createInstant(2008, 3, 26, ZoneOffset.UTC)), OFFSET_ZERO);
+        assertEquals(test.getOffset(createInstant(2008, 3, 27, ZoneOffset.UTC)), OFFSET_ZERO);
+        assertEquals(test.getOffset(createInstant(2008, 3, 28, ZoneOffset.UTC)), OFFSET_ZERO);
+        assertEquals(test.getOffset(createInstant(2008, 3, 29, ZoneOffset.UTC)), OFFSET_ZERO);
+        assertEquals(test.getOffset(createInstant(2008, 3, 30, ZoneOffset.UTC)), OFFSET_ZERO);
+        assertEquals(test.getOffset(createInstant(2008, 3, 31, ZoneOffset.UTC)), OFFSET_PONE);
+        // cutover at 01:00Z
+        assertEquals(test.getOffset(createInstant(2008, 3, 30, 0, 59, 59, 999999999, ZoneOffset.UTC)), OFFSET_ZERO);
+        assertEquals(test.getOffset(createInstant(2008, 3, 30, 1, 0, 0, 0, ZoneOffset.UTC)), OFFSET_PONE);
+    }
+
+    public void test_London_getOffset_fromDST() {
+        ZoneRules test = europeLondon();
+        assertEquals(test.getOffset(createInstant(2008, 10, 24, ZoneOffset.UTC)), OFFSET_PONE);
+        assertEquals(test.getOffset(createInstant(2008, 10, 25, ZoneOffset.UTC)), OFFSET_PONE);
+        assertEquals(test.getOffset(createInstant(2008, 10, 26, ZoneOffset.UTC)), OFFSET_PONE);
+        assertEquals(test.getOffset(createInstant(2008, 10, 27, ZoneOffset.UTC)), OFFSET_ZERO);
+        assertEquals(test.getOffset(createInstant(2008, 10, 28, ZoneOffset.UTC)), OFFSET_ZERO);
+        assertEquals(test.getOffset(createInstant(2008, 10, 29, ZoneOffset.UTC)), OFFSET_ZERO);
+        assertEquals(test.getOffset(createInstant(2008, 10, 30, ZoneOffset.UTC)), OFFSET_ZERO);
+        assertEquals(test.getOffset(createInstant(2008, 10, 31, ZoneOffset.UTC)), OFFSET_ZERO);
+        // cutover at 01:00Z
+        assertEquals(test.getOffset(createInstant(2008, 10, 26, 0, 59, 59, 999999999, ZoneOffset.UTC)), OFFSET_PONE);
+        assertEquals(test.getOffset(createInstant(2008, 10, 26, 1, 0, 0, 0, ZoneOffset.UTC)), OFFSET_ZERO);
+    }
+
+    public void test_London_getOffsetInfo() {
+        ZoneRules test = europeLondon();
+        checkOffset(test, createLDT(2008, 1, 1), OFFSET_ZERO, 1);
+        checkOffset(test, createLDT(2008, 2, 1), OFFSET_ZERO, 1);
+        checkOffset(test, createLDT(2008, 3, 1), OFFSET_ZERO, 1);
+        checkOffset(test, createLDT(2008, 4, 1), OFFSET_PONE, 1);
+        checkOffset(test, createLDT(2008, 5, 1), OFFSET_PONE, 1);
+        checkOffset(test, createLDT(2008, 6, 1), OFFSET_PONE, 1);
+        checkOffset(test, createLDT(2008, 7, 1), OFFSET_PONE, 1);
+        checkOffset(test, createLDT(2008, 8, 1), OFFSET_PONE, 1);
+        checkOffset(test, createLDT(2008, 9, 1), OFFSET_PONE, 1);
+        checkOffset(test, createLDT(2008, 10, 1), OFFSET_PONE, 1);
+        checkOffset(test, createLDT(2008, 11, 1), OFFSET_ZERO, 1);
+        checkOffset(test, createLDT(2008, 12, 1), OFFSET_ZERO, 1);
+    }
+
+    public void test_London_getOffsetInfo_toDST() {
+        ZoneRules test = europeLondon();
+        checkOffset(test, createLDT(2008, 3, 24), OFFSET_ZERO, 1);
+        checkOffset(test, createLDT(2008, 3, 25), OFFSET_ZERO, 1);
+        checkOffset(test, createLDT(2008, 3, 26), OFFSET_ZERO, 1);
+        checkOffset(test, createLDT(2008, 3, 27), OFFSET_ZERO, 1);
+        checkOffset(test, createLDT(2008, 3, 28), OFFSET_ZERO, 1);
+        checkOffset(test, createLDT(2008, 3, 29), OFFSET_ZERO, 1);
+        checkOffset(test, createLDT(2008, 3, 30), OFFSET_ZERO, 1);
+        checkOffset(test, createLDT(2008, 3, 31), OFFSET_PONE, 1);
+        // cutover at 01:00Z
+        checkOffset(test, LocalDateTime.of(2008, 3, 30, 0, 59, 59, 999999999), OFFSET_ZERO, 1);
+        checkOffset(test, LocalDateTime.of(2008, 3, 30, 2, 0, 0, 0), OFFSET_PONE, 1);
+    }
+
+    public void test_London_getOffsetInfo_fromDST() {
+        ZoneRules test = europeLondon();
+        checkOffset(test, createLDT(2008, 10, 24), OFFSET_PONE, 1);
+        checkOffset(test, createLDT(2008, 10, 25), OFFSET_PONE, 1);
+        checkOffset(test, createLDT(2008, 10, 26), OFFSET_PONE, 1);
+        checkOffset(test, createLDT(2008, 10, 27), OFFSET_ZERO, 1);
+        checkOffset(test, createLDT(2008, 10, 28), OFFSET_ZERO, 1);
+        checkOffset(test, createLDT(2008, 10, 29), OFFSET_ZERO, 1);
+        checkOffset(test, createLDT(2008, 10, 30), OFFSET_ZERO, 1);
+        checkOffset(test, createLDT(2008, 10, 31), OFFSET_ZERO, 1);
+        // cutover at 01:00Z
+        checkOffset(test, LocalDateTime.of(2008, 10, 26, 0, 59, 59, 999999999), OFFSET_PONE, 1);
+        checkOffset(test, LocalDateTime.of(2008, 10, 26, 2, 0, 0, 0), OFFSET_ZERO, 1);
+    }
+
+    public void test_London_getOffsetInfo_gap() {
+        ZoneRules test = europeLondon();
+        final LocalDateTime dateTime = LocalDateTime.of(2008, 3, 30, 1, 0, 0, 0);
+        ZoneOffsetTransition trans = checkOffset(test, dateTime, OFFSET_ZERO, GAP);
+        assertEquals(trans.isGap(), true);
+        assertEquals(trans.isOverlap(), false);
+        assertEquals(trans.getOffsetBefore(), OFFSET_ZERO);
+        assertEquals(trans.getOffsetAfter(), OFFSET_PONE);
+        assertEquals(trans.getInstant(), createInstant(2008, 3, 30, 1, 0, ZoneOffset.UTC));
+        assertEquals(trans.getDateTimeBefore(), LocalDateTime.of(2008, 3, 30, 1, 0));
+        assertEquals(trans.getDateTimeAfter(), LocalDateTime.of(2008, 3, 30, 2, 0));
+        assertEquals(trans.isValidOffset(OFFSET_ZERO), false);
+        assertEquals(trans.isValidOffset(OFFSET_PONE), false);
+        assertEquals(trans.isValidOffset(OFFSET_PTWO), false);
+        assertEquals(trans.toString(), "Transition[Gap at 2008-03-30T01:00Z to +01:00]");
+
+        assertFalse(trans.equals(null));
+        assertFalse(trans.equals(OFFSET_ZERO));
+        assertTrue(trans.equals(trans));
+
+        final ZoneOffsetTransition otherTrans = test.getTransition(dateTime);
+        assertTrue(trans.equals(otherTrans));
+        assertEquals(trans.hashCode(), otherTrans.hashCode());
+    }
+
+    public void test_London_getOffsetInfo_overlap() {
+        ZoneRules test = europeLondon();
+        final LocalDateTime dateTime = LocalDateTime.of(2008, 10, 26, 1, 0, 0, 0);
+        ZoneOffsetTransition trans = checkOffset(test, dateTime, OFFSET_PONE, OVERLAP);
+        assertEquals(trans.isGap(), false);
+        assertEquals(trans.isOverlap(), true);
+        assertEquals(trans.getOffsetBefore(), OFFSET_PONE);
+        assertEquals(trans.getOffsetAfter(), OFFSET_ZERO);
+        assertEquals(trans.getInstant(), createInstant(2008, 10, 26, 1, 0, ZoneOffset.UTC));
+        assertEquals(trans.getDateTimeBefore(), LocalDateTime.of(2008, 10, 26, 2, 0));
+        assertEquals(trans.getDateTimeAfter(), LocalDateTime.of(2008, 10, 26, 1, 0));
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-1)), false);
+        assertEquals(trans.isValidOffset(OFFSET_ZERO), true);
+        assertEquals(trans.isValidOffset(OFFSET_PONE), true);
+        assertEquals(trans.isValidOffset(OFFSET_PTWO), false);
+        assertEquals(trans.toString(), "Transition[Overlap at 2008-10-26T02:00+01:00 to Z]");
+
+        assertFalse(trans.equals(null));
+        assertFalse(trans.equals(OFFSET_PONE));
+        assertTrue(trans.equals(trans));
+
+        final ZoneOffsetTransition otherTrans = test.getTransition(dateTime);
+        assertTrue(trans.equals(otherTrans));
+        assertEquals(trans.hashCode(), otherTrans.hashCode());
+    }
+
+    public void test_London_getStandardOffset() {
+        ZoneRules test = europeLondon();
+        ZonedDateTime zdt = createZDT(1840, 1, 1, ZoneOffset.UTC);
+        while (zdt.getYear() < 2010) {
+            Instant instant = zdt.toInstant();
+            if (zdt.getYear() < 1848) {
+                assertEquals(test.getStandardOffset(instant), ZoneOffset.ofHoursMinutesSeconds(0, -1, -15));
+            } else if (zdt.getYear() >= 1969 && zdt.getYear() < 1972) {
+                assertEquals(test.getStandardOffset(instant), OFFSET_PONE);
+            } else {
+                assertEquals(test.getStandardOffset(instant), OFFSET_ZERO);
+            }
+            zdt = zdt.plusMonths(6);
+        }
+    }
+
+    public void test_London_getTransitions() {
+        ZoneRules test = europeLondon();
+        List<ZoneOffsetTransition> trans = test.getTransitions();
+
+        ZoneOffsetTransition first = trans.get(0);
+        assertEquals(first.getDateTimeBefore(), LocalDateTime.of(1847, 12, 1, 0, 0));
+        assertEquals(first.getOffsetBefore(), ZoneOffset.ofHoursMinutesSeconds(0, -1, -15));
+        assertEquals(first.getOffsetAfter(), OFFSET_ZERO);
+
+        ZoneOffsetTransition spring1916 = trans.get(1);
+        assertEquals(spring1916.getDateTimeBefore(), LocalDateTime.of(1916, 5, 21, 2, 0));
+        assertEquals(spring1916.getOffsetBefore(), OFFSET_ZERO);
+        assertEquals(spring1916.getOffsetAfter(), OFFSET_PONE);
+
+        ZoneOffsetTransition autumn1916 = trans.get(2);
+        assertEquals(autumn1916.getDateTimeBefore(), LocalDateTime.of(1916, 10, 1, 3, 0));
+        assertEquals(autumn1916.getOffsetBefore(), OFFSET_PONE);
+        assertEquals(autumn1916.getOffsetAfter(), OFFSET_ZERO);
+
+        ZoneOffsetTransition zot = null;
+        Iterator<ZoneOffsetTransition> it = trans.iterator();
+        while (it.hasNext()) {
+            zot = it.next();
+            if (zot.getDateTimeBefore().getYear() == 1990) {
+                break;
+            }
+        }
+        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1990, 3, 25, 1, 0));
+        assertEquals(zot.getOffsetBefore(), OFFSET_ZERO);
+        zot = it.next();
+        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1990, 10, 28, 2, 0));
+        assertEquals(zot.getOffsetBefore(), OFFSET_PONE);
+        zot = it.next();
+        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1991, 3, 31, 1, 0));
+        assertEquals(zot.getOffsetBefore(), OFFSET_ZERO);
+        zot = it.next();
+        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1991, 10, 27, 2, 0));
+        assertEquals(zot.getOffsetBefore(), OFFSET_PONE);
+        zot = it.next();
+        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1992, 3, 29, 1, 0));
+        assertEquals(zot.getOffsetBefore(), OFFSET_ZERO);
+        zot = it.next();
+        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1992, 10, 25, 2, 0));
+        assertEquals(zot.getOffsetBefore(), OFFSET_PONE);
+        zot = it.next();
+        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1993, 3, 28, 1, 0));
+        assertEquals(zot.getOffsetBefore(), OFFSET_ZERO);
+        zot = it.next();
+        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1993, 10, 24, 2, 0));
+        assertEquals(zot.getOffsetBefore(), OFFSET_PONE);
+        zot = it.next();
+        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1994, 3, 27, 1, 0));
+        assertEquals(zot.getOffsetBefore(), OFFSET_ZERO);
+        zot = it.next();
+        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1994, 10, 23, 2, 0));
+        assertEquals(zot.getOffsetBefore(), OFFSET_PONE);
+        zot = it.next();
+        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1995, 3, 26, 1, 0));
+        assertEquals(zot.getOffsetBefore(), OFFSET_ZERO);
+        zot = it.next();
+        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1995, 10, 22, 2, 0));
+        assertEquals(zot.getOffsetBefore(), OFFSET_PONE);
+        zot = it.next();
+        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1996, 3, 31, 1, 0));
+        assertEquals(zot.getOffsetBefore(), OFFSET_ZERO);
+        zot = it.next();
+        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1996, 10, 27, 2, 0));
+        assertEquals(zot.getOffsetBefore(), OFFSET_PONE);
+        zot = it.next();
+        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1997, 3, 30, 1, 0));
+        assertEquals(zot.getOffsetBefore(), OFFSET_ZERO);
+        zot = it.next();
+        assertEquals(zot.getDateTimeBefore(), LocalDateTime.of(1997, 10, 26, 2, 0));
+        assertEquals(zot.getOffsetBefore(), OFFSET_PONE);
+        assertEquals(it.hasNext(), false);
+    }
+
+    public void test_London_getTransitionRules() {
+        ZoneRules test = europeLondon();
+        List<ZoneOffsetTransitionRule> rules = test.getTransitionRules();
+        assertEquals(rules.size(), 2);
+
+        ZoneOffsetTransitionRule in = rules.get(0);
+        assertEquals(in.getMonth(), Month.MARCH);
+        assertEquals(in.getDayOfMonthIndicator(), 25);  // optimized from -1
+        assertEquals(in.getDayOfWeek(), DayOfWeek.SUNDAY);
+        assertEquals(in.getLocalTime(), LocalTime.of(1, 0));
+        assertEquals(in.getTimeDefinition(), TimeDefinition.UTC);
+        assertEquals(in.getStandardOffset(), OFFSET_ZERO);
+        assertEquals(in.getOffsetBefore(), OFFSET_ZERO);
+        assertEquals(in.getOffsetAfter(), OFFSET_PONE);
+
+        ZoneOffsetTransitionRule out = rules.get(1);
+        assertEquals(out.getMonth(), Month.OCTOBER);
+        assertEquals(out.getDayOfMonthIndicator(), 25);  // optimized from -1
+        assertEquals(out.getDayOfWeek(), DayOfWeek.SUNDAY);
+        assertEquals(out.getLocalTime(), LocalTime.of(1, 0));
+        assertEquals(out.getTimeDefinition(), TimeDefinition.UTC);
+        assertEquals(out.getStandardOffset(), OFFSET_ZERO);
+        assertEquals(out.getOffsetBefore(), OFFSET_PONE);
+        assertEquals(out.getOffsetAfter(), OFFSET_ZERO);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_London_nextTransition_historic() {
+        ZoneRules test = europeLondon();
+        List<ZoneOffsetTransition> trans = test.getTransitions();
+
+        ZoneOffsetTransition first = trans.get(0);
+        assertEquals(test.nextTransition(first.getInstant().minusNanos(1)), first);
+
+        for (int i = 0; i < trans.size() - 1; i++) {
+            ZoneOffsetTransition cur = trans.get(i);
+            ZoneOffsetTransition next = trans.get(i + 1);
+
+            assertEquals(test.nextTransition(cur.getInstant()), next);
+            assertEquals(test.nextTransition(next.getInstant().minusNanos(1)), next);
+        }
+    }
+
+    public void test_London_nextTransition_rulesBased() {
+        ZoneRules test = europeLondon();
+        List<ZoneOffsetTransitionRule> rules = test.getTransitionRules();
+        List<ZoneOffsetTransition> trans = test.getTransitions();
+
+        ZoneOffsetTransition last = trans.get(trans.size() - 1);
+        assertEquals(test.nextTransition(last.getInstant()), rules.get(0).createTransition(1998));
+
+        for (int year = 1998; year < 2010; year++) {
+            ZoneOffsetTransition a = rules.get(0).createTransition(year);
+            ZoneOffsetTransition b = rules.get(1).createTransition(year);
+            ZoneOffsetTransition c = rules.get(0).createTransition(year + 1);
+
+            assertEquals(test.nextTransition(a.getInstant()), b);
+            assertEquals(test.nextTransition(b.getInstant().minusNanos(1)), b);
+
+            assertEquals(test.nextTransition(b.getInstant()), c);
+            assertEquals(test.nextTransition(c.getInstant().minusNanos(1)), c);
+        }
+    }
+
+    public void test_London_nextTransition_lastYear() {
+        ZoneRules test = europeLondon();
+        List<ZoneOffsetTransitionRule> rules = test.getTransitionRules();
+        ZoneOffsetTransition zot = rules.get(1).createTransition(Year.MAX_VALUE);
+        assertEquals(test.nextTransition(zot.getInstant()), null);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_London_previousTransition_historic() {
+        ZoneRules test = europeLondon();
+        List<ZoneOffsetTransition> trans = test.getTransitions();
+
+        ZoneOffsetTransition first = trans.get(0);
+        assertEquals(test.previousTransition(first.getInstant()), null);
+        assertEquals(test.previousTransition(first.getInstant().minusNanos(1)), null);
+
+        for (int i = 0; i < trans.size() - 1; i++) {
+            ZoneOffsetTransition prev = trans.get(i);
+            ZoneOffsetTransition cur = trans.get(i + 1);
+
+            assertEquals(test.previousTransition(cur.getInstant()), prev);
+            assertEquals(test.previousTransition(prev.getInstant().plusSeconds(1)), prev);
+            assertEquals(test.previousTransition(prev.getInstant().plusNanos(1)), prev);
+        }
+    }
+
+    public void test_London_previousTransition_rulesBased() {
+        ZoneRules test = europeLondon();
+        List<ZoneOffsetTransitionRule> rules = test.getTransitionRules();
+        List<ZoneOffsetTransition> trans = test.getTransitions();
+
+        ZoneOffsetTransition last = trans.get(trans.size() - 1);
+        assertEquals(test.previousTransition(last.getInstant().plusSeconds(1)), last);
+        assertEquals(test.previousTransition(last.getInstant().plusNanos(1)), last);
+
+        // Jan 1st of year between transitions and rules
+        ZonedDateTime odt = ZonedDateTime.ofInstant(last.getInstant(), last.getOffsetAfter());
+        odt = odt.withDayOfYear(1).plusYears(1).with(LocalTime.MIDNIGHT);
+        assertEquals(test.previousTransition(odt.toInstant()), last);
+
+        // later years
+        for (int year = 1998; year < 2010; year++) {
+            ZoneOffsetTransition a = rules.get(0).createTransition(year);
+            ZoneOffsetTransition b = rules.get(1).createTransition(year);
+            ZoneOffsetTransition c = rules.get(0).createTransition(year + 1);
+
+            assertEquals(test.previousTransition(c.getInstant()), b);
+            assertEquals(test.previousTransition(b.getInstant().plusSeconds(1)), b);
+            assertEquals(test.previousTransition(b.getInstant().plusNanos(1)), b);
+
+            assertEquals(test.previousTransition(b.getInstant()), a);
+            assertEquals(test.previousTransition(a.getInstant().plusSeconds(1)), a);
+            assertEquals(test.previousTransition(a.getInstant().plusNanos(1)), a);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // Europe/Paris
+    //-----------------------------------------------------------------------
+    private ZoneRules europeParis() {
+        return ZoneId.of("Europe/Paris").getRules();
+    }
+
+    public void test_Paris() {
+        ZoneRules test = europeParis();
+        assertEquals(test.isFixedOffset(), false);
+    }
+
+    public void test_Paris_preTimeZones() {
+        ZoneRules test = europeParis();
+        ZonedDateTime old = createZDT(1800, 1, 1, ZoneOffset.UTC);
+        Instant instant = old.toInstant();
+        ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(0, 9, 21);
+        assertEquals(test.getOffset(instant), offset);
+        checkOffset(test, old.getDateTime(), offset, 1);
+        assertEquals(test.getStandardOffset(instant), offset);
+        assertEquals(test.getDaylightSavings(instant), Duration.ZERO);
+        assertEquals(test.isDaylightSavings(instant), false);
+    }
+
+    public void test_Paris_getOffset() {
+        ZoneRules test = europeParis();
+        assertEquals(test.getOffset(createInstant(2008, 1, 1, ZoneOffset.UTC)), OFFSET_PONE);
+        assertEquals(test.getOffset(createInstant(2008, 2, 1, ZoneOffset.UTC)), OFFSET_PONE);
+        assertEquals(test.getOffset(createInstant(2008, 3, 1, ZoneOffset.UTC)), OFFSET_PONE);
+        assertEquals(test.getOffset(createInstant(2008, 4, 1, ZoneOffset.UTC)), OFFSET_PTWO);
+        assertEquals(test.getOffset(createInstant(2008, 5, 1, ZoneOffset.UTC)), OFFSET_PTWO);
+        assertEquals(test.getOffset(createInstant(2008, 6, 1, ZoneOffset.UTC)), OFFSET_PTWO);
+        assertEquals(test.getOffset(createInstant(2008, 7, 1, ZoneOffset.UTC)), OFFSET_PTWO);
+        assertEquals(test.getOffset(createInstant(2008, 8, 1, ZoneOffset.UTC)), OFFSET_PTWO);
+        assertEquals(test.getOffset(createInstant(2008, 9, 1, ZoneOffset.UTC)), OFFSET_PTWO);
+        assertEquals(test.getOffset(createInstant(2008, 10, 1, ZoneOffset.UTC)), OFFSET_PTWO);
+        assertEquals(test.getOffset(createInstant(2008, 11, 1, ZoneOffset.UTC)), OFFSET_PONE);
+        assertEquals(test.getOffset(createInstant(2008, 12, 1, ZoneOffset.UTC)), OFFSET_PONE);
+    }
+
+    public void test_Paris_getOffset_toDST() {
+        ZoneRules test = europeParis();
+        assertEquals(test.getOffset(createInstant(2008, 3, 24, ZoneOffset.UTC)), OFFSET_PONE);
+        assertEquals(test.getOffset(createInstant(2008, 3, 25, ZoneOffset.UTC)), OFFSET_PONE);
+        assertEquals(test.getOffset(createInstant(2008, 3, 26, ZoneOffset.UTC)), OFFSET_PONE);
+        assertEquals(test.getOffset(createInstant(2008, 3, 27, ZoneOffset.UTC)), OFFSET_PONE);
+        assertEquals(test.getOffset(createInstant(2008, 3, 28, ZoneOffset.UTC)), OFFSET_PONE);
+        assertEquals(test.getOffset(createInstant(2008, 3, 29, ZoneOffset.UTC)), OFFSET_PONE);
+        assertEquals(test.getOffset(createInstant(2008, 3, 30, ZoneOffset.UTC)), OFFSET_PONE);
+        assertEquals(test.getOffset(createInstant(2008, 3, 31, ZoneOffset.UTC)), OFFSET_PTWO);
+        // cutover at 01:00Z
+        assertEquals(test.getOffset(createInstant(2008, 3, 30, 0, 59, 59, 999999999, ZoneOffset.UTC)), OFFSET_PONE);
+        assertEquals(test.getOffset(createInstant(2008, 3, 30, 1, 0, 0, 0, ZoneOffset.UTC)), OFFSET_PTWO);
+    }
+
+    public void test_Paris_getOffset_fromDST() {
+        ZoneRules test = europeParis();
+        assertEquals(test.getOffset(createInstant(2008, 10, 24, ZoneOffset.UTC)), OFFSET_PTWO);
+        assertEquals(test.getOffset(createInstant(2008, 10, 25, ZoneOffset.UTC)), OFFSET_PTWO);
+        assertEquals(test.getOffset(createInstant(2008, 10, 26, ZoneOffset.UTC)), OFFSET_PTWO);
+        assertEquals(test.getOffset(createInstant(2008, 10, 27, ZoneOffset.UTC)), OFFSET_PONE);
+        assertEquals(test.getOffset(createInstant(2008, 10, 28, ZoneOffset.UTC)), OFFSET_PONE);
+        assertEquals(test.getOffset(createInstant(2008, 10, 29, ZoneOffset.UTC)), OFFSET_PONE);
+        assertEquals(test.getOffset(createInstant(2008, 10, 30, ZoneOffset.UTC)), OFFSET_PONE);
+        assertEquals(test.getOffset(createInstant(2008, 10, 31, ZoneOffset.UTC)), OFFSET_PONE);
+        // cutover at 01:00Z
+        assertEquals(test.getOffset(createInstant(2008, 10, 26, 0, 59, 59, 999999999, ZoneOffset.UTC)), OFFSET_PTWO);
+        assertEquals(test.getOffset(createInstant(2008, 10, 26, 1, 0, 0, 0, ZoneOffset.UTC)), OFFSET_PONE);
+    }
+
+    public void test_Paris_getOffsetInfo() {
+        ZoneRules test = europeParis();
+        checkOffset(test, createLDT(2008, 1, 1), OFFSET_PONE, 1);
+        checkOffset(test, createLDT(2008, 2, 1), OFFSET_PONE, 1);
+        checkOffset(test, createLDT(2008, 3, 1), OFFSET_PONE, 1);
+        checkOffset(test, createLDT(2008, 4, 1), OFFSET_PTWO, 1);
+        checkOffset(test, createLDT(2008, 5, 1), OFFSET_PTWO, 1);
+        checkOffset(test, createLDT(2008, 6, 1), OFFSET_PTWO, 1);
+        checkOffset(test, createLDT(2008, 7, 1), OFFSET_PTWO, 1);
+        checkOffset(test, createLDT(2008, 8, 1), OFFSET_PTWO, 1);
+        checkOffset(test, createLDT(2008, 9, 1), OFFSET_PTWO, 1);
+        checkOffset(test, createLDT(2008, 10, 1), OFFSET_PTWO, 1);
+        checkOffset(test, createLDT(2008, 11, 1), OFFSET_PONE, 1);
+        checkOffset(test, createLDT(2008, 12, 1), OFFSET_PONE, 1);
+    }
+
+    public void test_Paris_getOffsetInfo_toDST() {
+        ZoneRules test = europeParis();
+        checkOffset(test, createLDT(2008, 3, 24), OFFSET_PONE, 1);
+        checkOffset(test, createLDT(2008, 3, 25), OFFSET_PONE, 1);
+        checkOffset(test, createLDT(2008, 3, 26), OFFSET_PONE, 1);
+        checkOffset(test, createLDT(2008, 3, 27), OFFSET_PONE, 1);
+        checkOffset(test, createLDT(2008, 3, 28), OFFSET_PONE, 1);
+        checkOffset(test, createLDT(2008, 3, 29), OFFSET_PONE, 1);
+        checkOffset(test, createLDT(2008, 3, 30), OFFSET_PONE, 1);
+        checkOffset(test, createLDT(2008, 3, 31), OFFSET_PTWO, 1);
+        // cutover at 01:00Z which is 02:00+01:00(local Paris time)
+        checkOffset(test, LocalDateTime.of(2008, 3, 30, 1, 59, 59, 999999999), OFFSET_PONE, 1);
+        checkOffset(test, LocalDateTime.of(2008, 3, 30, 3, 0, 0, 0), OFFSET_PTWO, 1);
+    }
+
+    public void test_Paris_getOffsetInfo_fromDST() {
+        ZoneRules test = europeParis();
+        checkOffset(test, createLDT(2008, 10, 24), OFFSET_PTWO, 1);
+        checkOffset(test, createLDT(2008, 10, 25), OFFSET_PTWO, 1);
+        checkOffset(test, createLDT(2008, 10, 26), OFFSET_PTWO, 1);
+        checkOffset(test, createLDT(2008, 10, 27), OFFSET_PONE, 1);
+        checkOffset(test, createLDT(2008, 10, 28), OFFSET_PONE, 1);
+        checkOffset(test, createLDT(2008, 10, 29), OFFSET_PONE, 1);
+        checkOffset(test, createLDT(2008, 10, 30), OFFSET_PONE, 1);
+        checkOffset(test, createLDT(2008, 10, 31), OFFSET_PONE, 1);
+        // cutover at 01:00Z which is 02:00+01:00(local Paris time)
+        checkOffset(test, LocalDateTime.of(2008, 10, 26, 1, 59, 59, 999999999), OFFSET_PTWO, 1);
+        checkOffset(test, LocalDateTime.of(2008, 10, 26, 3, 0, 0, 0), OFFSET_PONE, 1);
+    }
+
+    public void test_Paris_getOffsetInfo_gap() {
+        ZoneRules test = europeParis();
+        final LocalDateTime dateTime = LocalDateTime.of(2008, 3, 30, 2, 0, 0, 0);
+        ZoneOffsetTransition trans = checkOffset(test, dateTime, OFFSET_PONE, GAP);
+        assertEquals(trans.isGap(), true);
+        assertEquals(trans.isOverlap(), false);
+        assertEquals(trans.getOffsetBefore(), OFFSET_PONE);
+        assertEquals(trans.getOffsetAfter(), OFFSET_PTWO);
+        assertEquals(trans.getInstant(), createInstant(2008, 3, 30, 1, 0, ZoneOffset.UTC));
+        assertEquals(trans.isValidOffset(OFFSET_ZERO), false);
+        assertEquals(trans.isValidOffset(OFFSET_PONE), false);
+        assertEquals(trans.isValidOffset(OFFSET_PTWO), false);
+        assertEquals(trans.toString(), "Transition[Gap at 2008-03-30T02:00+01:00 to +02:00]");
+
+        assertFalse(trans.equals(null));
+        assertFalse(trans.equals(OFFSET_PONE));
+        assertTrue(trans.equals(trans));
+
+        final ZoneOffsetTransition otherTrans = test.getTransition(dateTime);
+        assertTrue(trans.equals(otherTrans));
+        assertEquals(trans.hashCode(), otherTrans.hashCode());
+    }
+
+    public void test_Paris_getOffsetInfo_overlap() {
+        ZoneRules test = europeParis();
+        final LocalDateTime dateTime = LocalDateTime.of(2008, 10, 26, 2, 0, 0, 0);
+        ZoneOffsetTransition trans = checkOffset(test, dateTime, OFFSET_PTWO, OVERLAP);
+        assertEquals(trans.isGap(), false);
+        assertEquals(trans.isOverlap(), true);
+        assertEquals(trans.getOffsetBefore(), OFFSET_PTWO);
+        assertEquals(trans.getOffsetAfter(), OFFSET_PONE);
+        assertEquals(trans.getInstant(), createInstant(2008, 10, 26, 1, 0, ZoneOffset.UTC));
+        assertEquals(trans.isValidOffset(OFFSET_ZERO), false);
+        assertEquals(trans.isValidOffset(OFFSET_PONE), true);
+        assertEquals(trans.isValidOffset(OFFSET_PTWO), true);
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(3)), false);
+        assertEquals(trans.toString(), "Transition[Overlap at 2008-10-26T03:00+02:00 to +01:00]");
+
+        assertFalse(trans.equals(null));
+        assertFalse(trans.equals(OFFSET_PTWO));
+        assertTrue(trans.equals(trans));
+
+        final ZoneOffsetTransition otherTrans = test.getTransition(dateTime);
+        assertTrue(trans.equals(otherTrans));
+        assertEquals(trans.hashCode(), otherTrans.hashCode());
+    }
+
+    public void test_Paris_getStandardOffset() {
+        ZoneRules test = europeParis();
+        ZonedDateTime zdt = createZDT(1840, 1, 1, ZoneOffset.UTC);
+        while (zdt.getYear() < 2010) {
+            Instant instant = zdt.toInstant();
+            if (zdt.getDate().isBefore(LocalDate.of(1911, 3, 11))) {
+                assertEquals(test.getStandardOffset(instant), ZoneOffset.ofHoursMinutesSeconds(0, 9, 21));
+            } else if (zdt.getDate().isBefore(LocalDate.of(1940, 6, 14))) {
+                assertEquals(test.getStandardOffset(instant), OFFSET_ZERO);
+            } else if (zdt.getDate().isBefore(LocalDate.of(1944, 8, 25))) {
+                assertEquals(test.getStandardOffset(instant), OFFSET_PONE);
+            } else if (zdt.getDate().isBefore(LocalDate.of(1945, 9, 16))) {
+                assertEquals(test.getStandardOffset(instant), OFFSET_ZERO);
+            } else {
+                assertEquals(test.getStandardOffset(instant), OFFSET_PONE);
+            }
+            zdt = zdt.plusMonths(6);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // America/New_York
+    //-----------------------------------------------------------------------
+    private ZoneRules americaNewYork() {
+        return ZoneId.of("America/New_York").getRules();
+    }
+
+    public void test_NewYork() {
+        ZoneRules test = americaNewYork();
+        assertEquals(test.isFixedOffset(), false);
+    }
+
+    public void test_NewYork_preTimeZones() {
+        ZoneRules test = americaNewYork();
+        ZonedDateTime old = createZDT(1800, 1, 1, ZoneOffset.UTC);
+        Instant instant = old.toInstant();
+        ZoneOffset offset = ZoneOffset.of("-04:56:02");
+        assertEquals(test.getOffset(instant), offset);
+        checkOffset(test, old.getDateTime(), offset, 1);
+        assertEquals(test.getStandardOffset(instant), offset);
+        assertEquals(test.getDaylightSavings(instant), Duration.ZERO);
+        assertEquals(test.isDaylightSavings(instant), false);
+    }
+
+    public void test_NewYork_getOffset() {
+        ZoneRules test = americaNewYork();
+        ZoneOffset offset = ZoneOffset.ofHours(-5);
+        assertEquals(test.getOffset(createInstant(2008, 1, 1, offset)), ZoneOffset.ofHours(-5));
+        assertEquals(test.getOffset(createInstant(2008, 2, 1, offset)), ZoneOffset.ofHours(-5));
+        assertEquals(test.getOffset(createInstant(2008, 3, 1, offset)), ZoneOffset.ofHours(-5));
+        assertEquals(test.getOffset(createInstant(2008, 4, 1, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getOffset(createInstant(2008, 5, 1, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getOffset(createInstant(2008, 6, 1, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getOffset(createInstant(2008, 7, 1, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getOffset(createInstant(2008, 8, 1, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getOffset(createInstant(2008, 9, 1, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getOffset(createInstant(2008, 10, 1, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getOffset(createInstant(2008, 11, 1, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getOffset(createInstant(2008, 12, 1, offset)), ZoneOffset.ofHours(-5));
+        assertEquals(test.getOffset(createInstant(2008, 1, 28, offset)), ZoneOffset.ofHours(-5));
+        assertEquals(test.getOffset(createInstant(2008, 2, 28, offset)), ZoneOffset.ofHours(-5));
+        assertEquals(test.getOffset(createInstant(2008, 3, 28, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getOffset(createInstant(2008, 4, 28, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getOffset(createInstant(2008, 5, 28, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getOffset(createInstant(2008, 6, 28, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getOffset(createInstant(2008, 7, 28, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getOffset(createInstant(2008, 8, 28, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getOffset(createInstant(2008, 9, 28, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getOffset(createInstant(2008, 10, 28, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getOffset(createInstant(2008, 11, 28, offset)), ZoneOffset.ofHours(-5));
+        assertEquals(test.getOffset(createInstant(2008, 12, 28, offset)), ZoneOffset.ofHours(-5));
+    }
+
+    public void test_NewYork_getOffset_toDST() {
+        ZoneRules test = americaNewYork();
+        ZoneOffset offset = ZoneOffset.ofHours(-5);
+        assertEquals(test.getOffset(createInstant(2008, 3, 8, offset)), ZoneOffset.ofHours(-5));
+        assertEquals(test.getOffset(createInstant(2008, 3, 9, offset)), ZoneOffset.ofHours(-5));
+        assertEquals(test.getOffset(createInstant(2008, 3, 10, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getOffset(createInstant(2008, 3, 11, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getOffset(createInstant(2008, 3, 12, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getOffset(createInstant(2008, 3, 13, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getOffset(createInstant(2008, 3, 14, offset)), ZoneOffset.ofHours(-4));
+        // cutover at 02:00 local
+        assertEquals(test.getOffset(createInstant(2008, 3, 9, 1, 59, 59, 999999999, offset)), ZoneOffset.ofHours(-5));
+        assertEquals(test.getOffset(createInstant(2008, 3, 9, 2, 0, 0, 0, offset)), ZoneOffset.ofHours(-4));
+    }
+
+    public void test_NewYork_getOffset_fromDST() {
+        ZoneRules test = americaNewYork();
+        ZoneOffset offset = ZoneOffset.ofHours(-4);
+        assertEquals(test.getOffset(createInstant(2008, 11, 1, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getOffset(createInstant(2008, 11, 2, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getOffset(createInstant(2008, 11, 3, offset)), ZoneOffset.ofHours(-5));
+        assertEquals(test.getOffset(createInstant(2008, 11, 4, offset)), ZoneOffset.ofHours(-5));
+        assertEquals(test.getOffset(createInstant(2008, 11, 5, offset)), ZoneOffset.ofHours(-5));
+        assertEquals(test.getOffset(createInstant(2008, 11, 6, offset)), ZoneOffset.ofHours(-5));
+        assertEquals(test.getOffset(createInstant(2008, 11, 7, offset)), ZoneOffset.ofHours(-5));
+        // cutover at 02:00 local
+        assertEquals(test.getOffset(createInstant(2008, 11, 2, 1, 59, 59, 999999999, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getOffset(createInstant(2008, 11, 2, 2, 0, 0, 0, offset)), ZoneOffset.ofHours(-5));
+    }
+
+    public void test_NewYork_getOffsetInfo() {
+        ZoneRules test = americaNewYork();
+        checkOffset(test, createLDT(2008, 1, 1), ZoneOffset.ofHours(-5), 1);
+        checkOffset(test, createLDT(2008, 2, 1), ZoneOffset.ofHours(-5), 1);
+        checkOffset(test, createLDT(2008, 3, 1), ZoneOffset.ofHours(-5), 1);
+        checkOffset(test, createLDT(2008, 4, 1), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test, createLDT(2008, 5, 1), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test, createLDT(2008, 6, 1), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test, createLDT(2008, 7, 1), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test, createLDT(2008, 8, 1), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test, createLDT(2008, 9, 1), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test, createLDT(2008, 10, 1), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test, createLDT(2008, 11, 1), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test, createLDT(2008, 12, 1), ZoneOffset.ofHours(-5), 1);
+        checkOffset(test, createLDT(2008, 1, 28), ZoneOffset.ofHours(-5), 1);
+        checkOffset(test, createLDT(2008, 2, 28), ZoneOffset.ofHours(-5), 1);
+        checkOffset(test, createLDT(2008, 3, 28), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test, createLDT(2008, 4, 28), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test, createLDT(2008, 5, 28), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test, createLDT(2008, 6, 28), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test, createLDT(2008, 7, 28), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test, createLDT(2008, 8, 28), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test, createLDT(2008, 9, 28), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test, createLDT(2008, 10, 28), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test, createLDT(2008, 11, 28), ZoneOffset.ofHours(-5), 1);
+        checkOffset(test, createLDT(2008, 12, 28), ZoneOffset.ofHours(-5), 1);
+    }
+
+    public void test_NewYork_getOffsetInfo_toDST() {
+        ZoneRules test = americaNewYork();
+        checkOffset(test, createLDT(2008, 3, 8), ZoneOffset.ofHours(-5), 1);
+        checkOffset(test, createLDT(2008, 3, 9), ZoneOffset.ofHours(-5), 1);
+        checkOffset(test, createLDT(2008, 3, 10), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test, createLDT(2008, 3, 11), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test, createLDT(2008, 3, 12), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test, createLDT(2008, 3, 13), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test, createLDT(2008, 3, 14), ZoneOffset.ofHours(-4), 1);
+        // cutover at 02:00 local
+        checkOffset(test, LocalDateTime.of(2008, 3, 9, 1, 59, 59, 999999999), ZoneOffset.ofHours(-5), 1);
+        checkOffset(test, LocalDateTime.of(2008, 3, 9, 3, 0, 0, 0), ZoneOffset.ofHours(-4), 1);
+    }
+
+    public void test_NewYork_getOffsetInfo_fromDST() {
+        ZoneRules test = americaNewYork();
+        checkOffset(test, createLDT(2008, 11, 1), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test, createLDT(2008, 11, 2), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test, createLDT(2008, 11, 3), ZoneOffset.ofHours(-5), 1);
+        checkOffset(test, createLDT(2008, 11, 4), ZoneOffset.ofHours(-5), 1);
+        checkOffset(test, createLDT(2008, 11, 5), ZoneOffset.ofHours(-5), 1);
+        checkOffset(test, createLDT(2008, 11, 6), ZoneOffset.ofHours(-5), 1);
+        checkOffset(test, createLDT(2008, 11, 7), ZoneOffset.ofHours(-5), 1);
+        // cutover at 02:00 local
+        checkOffset(test, LocalDateTime.of(2008, 11, 2, 0, 59, 59, 999999999), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test, LocalDateTime.of(2008, 11, 2, 2, 0, 0, 0), ZoneOffset.ofHours(-5), 1);
+    }
+
+    public void test_NewYork_getOffsetInfo_gap() {
+        ZoneRules test = americaNewYork();
+        final LocalDateTime dateTime = LocalDateTime.of(2008, 3, 9, 2, 0, 0, 0);
+        ZoneOffsetTransition trans = checkOffset(test, dateTime, ZoneOffset.ofHours(-5), GAP);
+        assertEquals(trans.isGap(), true);
+        assertEquals(trans.isOverlap(), false);
+        assertEquals(trans.getOffsetBefore(), ZoneOffset.ofHours(-5));
+        assertEquals(trans.getOffsetAfter(), ZoneOffset.ofHours(-4));
+        assertEquals(trans.getInstant(), createInstant(2008, 3, 9, 2, 0, ZoneOffset.ofHours(-5)));
+        assertEquals(trans.isValidOffset(OFFSET_PTWO), false);
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-5)), false);
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-4)), false);
+        assertEquals(trans.toString(), "Transition[Gap at 2008-03-09T02:00-05:00 to -04:00]");
+
+        assertFalse(trans.equals(null));
+        assertFalse(trans.equals(ZoneOffset.ofHours(-5)));
+        assertTrue(trans.equals(trans));
+
+        final ZoneOffsetTransition otherTrans = test.getTransition(dateTime);
+        assertTrue(trans.equals(otherTrans));
+        assertEquals(trans.hashCode(), otherTrans.hashCode());
+    }
+
+    public void test_NewYork_getOffsetInfo_overlap() {
+        ZoneRules test = americaNewYork();
+        final LocalDateTime dateTime = LocalDateTime.of(2008, 11, 2, 1, 0, 0, 0);
+        ZoneOffsetTransition trans = checkOffset(test, dateTime, ZoneOffset.ofHours(-4), OVERLAP);
+        assertEquals(trans.isGap(), false);
+        assertEquals(trans.isOverlap(), true);
+        assertEquals(trans.getOffsetBefore(), ZoneOffset.ofHours(-4));
+        assertEquals(trans.getOffsetAfter(), ZoneOffset.ofHours(-5));
+        assertEquals(trans.getInstant(), createInstant(2008, 11, 2, 2, 0, ZoneOffset.ofHours(-4)));
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-1)), false);
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-5)), true);
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-4)), true);
+        assertEquals(trans.isValidOffset(OFFSET_PTWO), false);
+        assertEquals(trans.toString(), "Transition[Overlap at 2008-11-02T02:00-04:00 to -05:00]");
+
+        assertFalse(trans.equals(null));
+        assertFalse(trans.equals(ZoneOffset.ofHours(-4)));
+        assertTrue(trans.equals(trans));
+
+        final ZoneOffsetTransition otherTrans = test.getTransition(dateTime);
+        assertTrue(trans.equals(otherTrans));
+        assertEquals(trans.hashCode(), otherTrans.hashCode());
+    }
+
+    public void test_NewYork_getStandardOffset() {
+        ZoneRules test = americaNewYork();
+        ZonedDateTime dateTime = createZDT(1860, 1, 1, ZoneOffset.UTC);
+        while (dateTime.getYear() < 2010) {
+            Instant instant = dateTime.toInstant();
+            if (dateTime.getDate().isBefore(LocalDate.of(1883, 11, 18))) {
+                assertEquals(test.getStandardOffset(instant), ZoneOffset.of("-04:56:02"));
+            } else {
+                assertEquals(test.getStandardOffset(instant), ZoneOffset.ofHours(-5));
+            }
+            dateTime = dateTime.plusMonths(6);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // Kathmandu
+    //-----------------------------------------------------------------------
+    private ZoneRules asiaKathmandu() {
+        return ZoneId.of("Asia/Kathmandu").getRules();
+    }
+
+    public void test_Kathmandu_nextTransition_historic() {
+        ZoneRules test = asiaKathmandu();
+        List<ZoneOffsetTransition> trans = test.getTransitions();
+
+        ZoneOffsetTransition first = trans.get(0);
+        assertEquals(test.nextTransition(first.getInstant().minusNanos(1)), first);
+
+        for (int i = 0; i < trans.size() - 1; i++) {
+            ZoneOffsetTransition cur = trans.get(i);
+            ZoneOffsetTransition next = trans.get(i + 1);
+
+            assertEquals(test.nextTransition(cur.getInstant()), next);
+            assertEquals(test.nextTransition(next.getInstant().minusNanos(1)), next);
+        }
+    }
+
+    public void test_Kathmandu_nextTransition_noRules() {
+        ZoneRules test = asiaKathmandu();
+        List<ZoneOffsetTransition> trans = test.getTransitions();
+
+        ZoneOffsetTransition last = trans.get(trans.size() - 1);
+        assertEquals(test.nextTransition(last.getInstant()), null);
+    }
+
+    //-------------------------------------------------------------------------
+    @Test(expectedExceptions=UnsupportedOperationException.class)
+    public void test_getTransitions_immutable() {
+        ZoneRules test = europeParis();
+        test.getTransitions().clear();
+    }
+
+    @Test(expectedExceptions=UnsupportedOperationException.class)
+    public void test_getTransitionRules_immutable() {
+        ZoneRules test = europeParis();
+        test.getTransitionRules().clear();
+    }
+
+    //-----------------------------------------------------------------------
+    // equals() / hashCode()
+    //-----------------------------------------------------------------------
+    public void test_equals() {
+        ZoneRules test1 = europeLondon();
+        ZoneRules test2 = europeParis();
+        ZoneRules test2b = europeParis();
+        assertEquals(test1.equals(test2), false);
+        assertEquals(test2.equals(test1), false);
+
+        assertEquals(test1.equals(test1), true);
+        assertEquals(test2.equals(test2), true);
+        assertEquals(test2.equals(test2b), true);
+
+        assertEquals(test1.hashCode() == test1.hashCode(), true);
+        assertEquals(test2.hashCode() == test2.hashCode(), true);
+        assertEquals(test2.hashCode() == test2b.hashCode(), true);
+    }
+
+    public void test_equals_null() {
+        assertEquals(europeLondon().equals(null), false);
+    }
+
+    public void test_equals_notZoneRules() {
+        assertEquals(europeLondon().equals("Europe/London"), false);
+    }
+
+    public void test_toString() {
+        assertEquals(europeLondon().toString().contains("ZoneRules"), true);
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    private Instant createInstant(int year, int month, int day, ZoneOffset offset) {
+        return LocalDateTime.of(year, month, day, 0, 0).toInstant(offset);
+    }
+
+    private Instant createInstant(int year, int month, int day, int hour, int min, ZoneOffset offset) {
+        return LocalDateTime.of(year, month, day, hour, min).toInstant(offset);
+    }
+
+    private Instant createInstant(int year, int month, int day, int hour, int min, int sec, int nano, ZoneOffset offset) {
+        return LocalDateTime.of(year, month, day, hour, min, sec, nano).toInstant(offset);
+    }
+
+    private ZonedDateTime createZDT(int year, int month, int day, ZoneId zone) {
+        return LocalDateTime.of(year, month, day, 0, 0).atZone(zone);
+    }
+
+    private LocalDateTime createLDT(int year, int month, int day) {
+        return LocalDateTime.of(year, month, day, 0, 0);
+    }
+
+    private ZoneOffsetTransition checkOffset(ZoneRules rules, LocalDateTime dateTime, ZoneOffset offset, int type) {
+        List<ZoneOffset> validOffsets = rules.getValidOffsets(dateTime);
+        assertEquals(validOffsets.size(), type);
+        assertEquals(rules.getOffset(dateTime), offset);
+        if (type == 1) {
+            assertEquals(validOffsets.get(0), offset);
+            return null;
+        } else {
+            ZoneOffsetTransition zot = rules.getTransition(dateTime);
+            assertNotNull(zot);
+            assertEquals(zot.isOverlap(), type == 2);
+            assertEquals(zot.isGap(), type == 0);
+            assertEquals(zot.isValidOffset(offset), type == 2);
+            return zot;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/tck/java/time/zone/TCKZoneRulesProvider.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package tck.java.time.zone;
+
+import java.time.zone.*;
+import test.java.time.zone.*;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.NavigableMap;
+import java.util.Set;
+import java.util.TreeMap;
+
+import java.time.ZoneOffset;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test ZoneRulesProvider.
+ */
+@Test
+public class TCKZoneRulesProvider {
+
+    private static String TZDB_VERSION = "2012i";
+
+    //-----------------------------------------------------------------------
+    // getAvailableZoneIds()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_getAvailableGroupIds() {
+        Set<String> zoneIds = ZoneRulesProvider.getAvailableZoneIds();
+        assertEquals(zoneIds.contains("Europe/London"), true);
+        zoneIds.clear();
+        assertEquals(zoneIds.size(), 0);
+        Set<String> zoneIds2 = ZoneRulesProvider.getAvailableZoneIds();
+        assertEquals(zoneIds2.contains("Europe/London"), true);
+    }
+
+    //-----------------------------------------------------------------------
+    // getRules(String)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_getRules_String() {
+        ZoneRules rules = ZoneRulesProvider.getRules("Europe/London");
+        assertNotNull(rules);
+        ZoneRules rules2 = ZoneRulesProvider.getRules("Europe/London");
+        assertEquals(rules2, rules);
+    }
+
+    @Test(groups={"tck"}, expectedExceptions=ZoneRulesException.class)
+    public void test_getRules_String_unknownId() {
+        ZoneRulesProvider.getRules("Europe/Lon");
+    }
+
+    @Test(groups={"tck"}, expectedExceptions=NullPointerException.class)
+    public void test_getRules_String_null() {
+        ZoneRulesProvider.getRules(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // getVersions(String)
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_getVersions_String() {
+        NavigableMap<String, ZoneRules> versions = ZoneRulesProvider.getVersions("Europe/London");
+        assertTrue(versions.size() >= 1);
+        ZoneRules rules = ZoneRulesProvider.getRules("Europe/London");
+        assertEquals(versions.lastEntry().getValue(), rules);
+
+        NavigableMap<String, ZoneRules> copy = new TreeMap<>(versions);
+        versions.clear();
+        assertEquals(versions.size(), 0);
+        NavigableMap<String, ZoneRules> versions2 = ZoneRulesProvider.getVersions("Europe/London");
+        assertEquals(versions2, copy);
+    }
+
+    @Test(groups={"tck"}, expectedExceptions=ZoneRulesException.class)
+    public void test_getVersions_String_unknownId() {
+        ZoneRulesProvider.getVersions("Europe/Lon");
+    }
+
+    @Test(groups={"tck"}, expectedExceptions=NullPointerException.class)
+    public void test_getVersions_String_null() {
+        ZoneRulesProvider.getVersions(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // refresh()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_refresh() {
+        assertEquals(ZoneRulesProvider.refresh(), false);
+    }
+
+    //-----------------------------------------------------------------------
+    // registerProvider()
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck"})
+    public void test_registerProvider() {
+        Set<String> pre = ZoneRulesProvider.getAvailableZoneIds();
+        assertEquals(pre.contains("FooLocation"), false);
+        ZoneRulesProvider.registerProvider(new MockTempProvider());
+        assertEquals(pre.contains("FooLocation"), false);
+        Set<String> post = ZoneRulesProvider.getAvailableZoneIds();
+        assertEquals(post.contains("FooLocation"), true);
+
+        assertEquals(ZoneRulesProvider.getRules("FooLocation"), ZoneOffset.of("+01:45").getRules());
+    }
+
+    static class MockTempProvider extends ZoneRulesProvider {
+        final ZoneRules rules = ZoneOffset.of("+01:45").getRules();
+        @Override
+        public Set<String> provideZoneIds() {
+            return new HashSet<String>(Collections.singleton("FooLocation"));
+        }
+        @Override
+        protected ZoneRulesProvider provideBind(String zoneId) {
+            return this;
+        }
+        @Override
+        protected NavigableMap<String, ZoneRules> provideVersions(String zoneId) {
+            NavigableMap<String, ZoneRules> result = new TreeMap<>();
+            result.put("BarVersion", rules);
+            return result;
+        }
+        @Override
+        protected ZoneRules provideRules(String zoneId) {
+            if (zoneId.equals("FooLocation")) {
+                return rules;
+            }
+            throw new ZoneRulesException("Invalid");
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/AbstractTest.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+/**
+ * Base test class.
+ */
+public abstract class AbstractTest {
+
+    protected static boolean isIsoLeap(long year) {
+        if (year % 4 != 0) {
+            return false;
+        }
+        if (year % 100 == 0 && year % 400 != 0) {
+            return false;
+        }
+        return true;
+    }
+
+    protected static void assertSerializable(Object o) throws IOException, ClassNotFoundException {
+        Object deserialisedObject = writeThenRead(o);
+        assertEquals(deserialisedObject, o);
+    }
+
+    protected static void assertSerializableAndSame(Object o) throws IOException, ClassNotFoundException {
+        Object deserialisedObject = writeThenRead(o);
+        assertSame(deserialisedObject, o);
+    }
+
+    private static Object writeThenRead(Object o) throws IOException, ClassNotFoundException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try (ObjectOutputStream oos = new ObjectOutputStream(baos) ) {
+            oos.writeObject(o);
+        }
+
+        try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) {
+            return ois.readObject();
+        }
+    }
+
+    protected static void assertImmutable(Class<?> cls) {
+        assertTrue(Modifier.isPublic(cls.getModifiers()));
+        assertTrue(Modifier.isFinal(cls.getModifiers()));
+        Field[] fields = cls.getDeclaredFields();
+        for (Field field : fields) {
+            if (field.getName().contains("$") == false) {
+                if (Modifier.isStatic(field.getModifiers())) {
+                    assertTrue(Modifier.isFinal(field.getModifiers()), "Field:" + field.getName());
+                } else {
+                    assertTrue(Modifier.isPrivate(field.getModifiers()), "Field:" + field.getName());
+                    assertTrue(Modifier.isFinal(field.getModifiers()), "Field:" + field.getName());
+                }
+            }
+        }
+        Constructor<?>[] cons = cls.getDeclaredConstructors();
+        for (Constructor<?> con : cons) {
+            assertTrue(Modifier.isPrivate(con.getModifiers()));
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/MockSimplePeriod.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time;
+
+import java.time.*;
+
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.FOREVER;
+import static java.time.temporal.ChronoUnit.SECONDS;
+
+import java.util.Objects;
+
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalSubtractor;
+import java.time.temporal.TemporalAdder;
+import java.time.temporal.TemporalUnit;
+
+/**
+ * Mock period of time measured using a single unit, such as {@code 3 Days}.
+ */
+public final class MockSimplePeriod
+        implements TemporalAdder, TemporalSubtractor, Comparable<MockSimplePeriod> {
+
+    /**
+     * A constant for a period of zero, measured in days.
+     */
+    public static final MockSimplePeriod ZERO_DAYS = new MockSimplePeriod(0, DAYS);
+    /**
+     * A constant for a period of zero, measured in seconds.
+     */
+    public static final MockSimplePeriod ZERO_SECONDS = new MockSimplePeriod(0, SECONDS);
+
+    /**
+     * The amount of the period.
+     */
+    private final long amount;
+    /**
+     * The unit the period is measured in.
+     */
+    private final TemporalUnit unit;
+
+    /**
+     * Obtains a {@code MockSimplePeriod} from an amount and unit.
+     * <p>
+     * The parameters represent the two parts of a phrase like '6 Days'.
+     *
+     * @param amount  the amount of the period, measured in terms of the unit, positive or negative
+     * @param unit  the unit that the period is measured in, must not be the 'Forever' unit, not null
+     * @return the {@code MockSimplePeriod} instance, not null
+     * @throws DateTimeException if the period unit is {@link java.time.temporal.ChronoUnit#FOREVER}.
+     */
+    public static MockSimplePeriod of(long amount, TemporalUnit unit) {
+        return new MockSimplePeriod(amount, unit);
+    }
+
+    private MockSimplePeriod(long amount, TemporalUnit unit) {
+        Objects.requireNonNull(unit, "unit");
+        if (unit == FOREVER) {
+            throw new DateTimeException("Cannot create a period of the Forever unit");
+        }
+        this.amount = amount;
+        this.unit = unit;
+    }
+
+    //-----------------------------------------------------------------------
+    public long getAmount() {
+        return amount;
+    }
+
+    public TemporalUnit getUnit() {
+        return unit;
+    }
+
+    //-------------------------------------------------------------------------
+    @Override
+    public Temporal addTo(Temporal temporal) {
+        return temporal.plus(amount, unit);
+    }
+
+    @Override
+    public Temporal subtractFrom(Temporal temporal) {
+        return temporal.minus(amount, unit);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public int compareTo(MockSimplePeriod otherPeriod) {
+        if (unit.equals(otherPeriod.getUnit()) == false) {
+            throw new IllegalArgumentException("Units cannot be compared: " + unit + " and " + otherPeriod.getUnit());
+        }
+        return Long.compare(amount, otherPeriod.amount);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+           return true;
+        }
+        if (obj instanceof MockSimplePeriod) {
+            MockSimplePeriod other = (MockSimplePeriod) obj;
+            return this.amount == other.amount &&
+                    this.unit.equals(other.unit);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return unit.hashCode() ^ (int) (amount ^ (amount >>> 32));
+    }
+
+    @Override
+    public String toString() {
+        return amount + " " + unit.getName();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/TestClock_Fixed.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012 Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertSame;
+
+import java.time.Clock;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test fixed clock.
+ */
+@Test
+public class TestClock_Fixed {
+
+    private static final ZoneId PARIS = ZoneId.of("Europe/Paris");
+    private static final Instant INSTANT = LocalDateTime.of(2008, 6, 30, 11, 30, 10, 500).atZone(ZoneOffset.ofHours(2)).toInstant();
+
+    //-------------------------------------------------------------------------
+    public void test_withZone_same() {
+        Clock test = Clock.fixed(INSTANT, PARIS);
+        Clock changed = test.withZone(PARIS);
+        assertSame(test, changed);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_toString() {
+        Clock test = Clock.fixed(INSTANT, PARIS);
+        assertEquals(test.toString(), "FixedClock[2008-06-30T09:30:10.000000500Z,Europe/Paris]");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/TestClock_Offset.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012 Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertSame;
+
+import java.time.Clock;
+import java.time.Duration;
+import java.time.ZoneId;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test offset clock.
+ */
+@Test
+public class TestClock_Offset {
+
+    private static final ZoneId PARIS = ZoneId.of("Europe/Paris");
+    private static final Duration OFFSET = Duration.ofSeconds(2);
+
+    //-------------------------------------------------------------------------
+    public void test_withZone_same() {
+        Clock test = Clock.offset(Clock.system(PARIS), OFFSET);
+        Clock changed = test.withZone(PARIS);
+        assertSame(test, changed);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_toString() {
+        Clock test = Clock.offset(Clock.systemUTC(), OFFSET);
+        assertEquals(test.toString(), "OffsetClock[SystemClock[Z],PT2S]");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/TestClock_System.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012 Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time;
+
+import java.time.*;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertSame;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test system clock.
+ */
+@Test
+public class TestClock_System {
+
+    private static final ZoneId PARIS = ZoneId.of("Europe/Paris");
+
+    public void test_withZone_same() {
+        Clock test = Clock.system(PARIS);
+        Clock changed = test.withZone(PARIS);
+        assertSame(test, changed);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_toString() {
+        Clock test = Clock.system(PARIS);
+        assertEquals(test.toString(), "SystemClock[Europe/Paris]");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/TestClock_Tick.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012 Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertSame;
+
+import java.time.Clock;
+import java.time.Duration;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test tick clock.
+ */
+@Test
+public class TestClock_Tick {
+
+    private static final ZoneId MOSCOW = ZoneId.of("Europe/Moscow");
+    private static final ZoneId PARIS = ZoneId.of("Europe/Paris");
+    private static final ZonedDateTime ZDT = LocalDateTime.of(2008, 6, 30, 11, 30, 10, 500).atZone(ZoneOffset.ofHours(2));
+
+    //-------------------------------------------------------------------------
+    public void test_withZone_same() {
+        Clock test = Clock.tick(Clock.system(PARIS), Duration.ofMillis(500));
+        Clock changed = test.withZone(PARIS);
+        assertSame(test, changed);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_toString() {
+        Clock test = Clock.tick(Clock.systemUTC(), Duration.ofMillis(500));
+        assertEquals(test.toString(), "TickClock[SystemClock[Z],PT0.5S]");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/TestDuration.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+
+import java.time.Duration;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test Duration.
+ */
+@Test
+public class TestDuration extends AbstractTest {
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_immutable() {
+        assertImmutable(Duration.class);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"implementation"})
+    public void test_interfaces() {
+        assertTrue(Serializable.class.isAssignableFrom(Duration.class));
+        assertTrue(Comparable.class.isAssignableFrom(Duration.class));
+    }
+
+    //-----------------------------------------------------------------------
+    // serialization
+    //-----------------------------------------------------------------------
+    @Test(groups={"implementation"})
+    public void test_deserializationSingleton() throws Exception {
+        Duration orginal = Duration.ZERO;
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream(baos);
+        out.writeObject(orginal);
+        out.close();
+        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+        ObjectInputStream in = new ObjectInputStream(bais);
+        Duration ser = (Duration) in.readObject();
+        assertSame(ser, Duration.ZERO);
+    }
+
+    @Test(groups={"implementation"})
+    public void plus_zeroReturnsThis() {
+        Duration t = Duration.ofSeconds(-1);
+        assertSame(t.plus(Duration.ZERO), t);
+    }
+
+    @Test(groups={"implementation"})
+    public void plus_zeroSingleton() {
+        Duration t = Duration.ofSeconds(-1);
+        assertSame(t.plus(Duration.ofSeconds(1)), Duration.ZERO);
+    }
+
+    @Test(groups={"implementation"})
+    public void plusSeconds_zeroReturnsThis() {
+        Duration t = Duration.ofSeconds(-1);
+        assertSame(t.plusSeconds(0), t);
+    }
+
+    @Test(groups={"implementation"})
+    public void plusSeconds_zeroSingleton() {
+        Duration t = Duration.ofSeconds(-1);
+        assertSame(t.plusSeconds(1), Duration.ZERO);
+    }
+
+    @Test(groups={"implementation"})
+    public void plusMillis_zeroReturnsThis() {
+        Duration t = Duration.ofSeconds(-1, 2000000);
+        assertSame(t.plusMillis(0), t);
+    }
+
+    @Test(groups={"implementation"})
+    public void plusMillis_zeroSingleton() {
+        Duration t = Duration.ofSeconds(-1, 2000000);
+        assertSame(t.plusMillis(998), Duration.ZERO);
+    }
+
+    @Test(groups={"implementation"})
+    public void plusNanos_zeroReturnsThis() {
+        Duration t = Duration.ofSeconds(-1, 2000000);
+        assertSame(t.plusNanos(0), t);
+    }
+
+    @Test(groups={"implementation"})
+    public void plusNanos_zeroSingleton() {
+        Duration t = Duration.ofSeconds(-1, 2000000);
+        assertSame(t.plusNanos(998000000), Duration.ZERO);
+    }
+
+    @Test(groups={"implementation"})
+    public void minus_zeroReturnsThis() {
+        Duration t = Duration.ofSeconds(1);
+        assertSame(t.minus(Duration.ZERO), t);
+    }
+
+    @Test(groups={"implementation"})
+    public void minus_zeroSingleton() {
+        Duration t = Duration.ofSeconds(1);
+        assertSame(t.minus(Duration.ofSeconds(1)), Duration.ZERO);
+    }
+
+    @Test(groups={"implementation"})
+    public void minusSeconds_zeroReturnsThis() {
+        Duration t = Duration.ofSeconds(1);
+        assertSame(t.minusSeconds(0), t);
+    }
+
+    @Test(groups={"implementation"})
+    public void minusSeconds_zeroSingleton() {
+        Duration t = Duration.ofSeconds(1);
+        assertSame(t.minusSeconds(1), Duration.ZERO);
+    }
+
+    @Test(groups={"implementation"})
+    public void minusMillis_zeroReturnsThis() {
+        Duration t = Duration.ofSeconds(1, 2000000);
+        assertSame(t.minusMillis(0), t);
+    }
+
+    @Test(groups={"implementation"})
+    public void minusMillis_zeroSingleton() {
+        Duration t = Duration.ofSeconds(1, 2000000);
+        assertSame(t.minusMillis(1002), Duration.ZERO);
+    }
+
+    @Test(groups={"implementation"})
+    public void minusNanos_zeroReturnsThis() {
+        Duration t = Duration.ofSeconds(1, 2000000);
+        assertSame(t.minusNanos(0), t);
+    }
+
+    @Test(groups={"implementation"})
+    public void minusNanos_zeroSingleton() {
+        Duration t = Duration.ofSeconds(1, 2000000);
+        assertSame(t.minusNanos(1002000000), Duration.ZERO);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_abs_same() {
+        Duration base = Duration.ofSeconds(12);
+        assertSame(base.abs(), base);
+    }
+
+    void doTest_comparisons_Duration(Duration... durations) {
+        for (int i = 0; i < durations.length; i++) {
+            Duration a = durations[i];
+            for (int j = 0; j < durations.length; j++) {
+                Duration b = durations[j];
+                if (i < j) {
+                    assertEquals(a.compareTo(b)< 0, true, a + " <=> " + b);
+                    assertEquals(a.isLessThan(b), true, a + " <=> " + b);
+                    assertEquals(a.isGreaterThan(b), false, a + " <=> " + b);
+                    assertEquals(a.equals(b), false, a + " <=> " + b);
+                } else if (i > j) {
+                    assertEquals(a.compareTo(b) > 0, true, a + " <=> " + b);
+                    assertEquals(a.isLessThan(b), false, a + " <=> " + b);
+                    assertEquals(a.isGreaterThan(b), true, a + " <=> " + b);
+                    assertEquals(a.equals(b), false, a + " <=> " + b);
+                } else {
+                    assertEquals(a.compareTo(b), 0, a + " <=> " + b);
+                    assertEquals(a.isLessThan(b), false, a + " <=> " + b);
+                    assertEquals(a.isGreaterThan(b), false, a + " <=> " + b);
+                    assertEquals(a.equals(b), true, a + " <=> " + b);
+                }
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/TestInstant.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time;
+
+import java.time.Instant;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test Instant.
+ */
+@Test
+public class TestInstant extends AbstractTest {
+
+    @Test
+    public void test_immutable() {
+        assertImmutable(Instant.class);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/TestLocalDate.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,447 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time;
+
+import static java.time.temporal.ChronoField.YEAR;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
+
+import java.time.LocalDate;
+import java.time.Month;
+import java.time.temporal.ChronoUnit;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test LocalDate.
+ */
+@Test
+public class TestLocalDate extends AbstractTest {
+
+    private LocalDate TEST_2007_07_15;
+
+    @BeforeMethod(groups={"tck", "implementation"})
+    public void setUp() {
+        TEST_2007_07_15 = LocalDate.of(2007, 7, 15);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_immutable() {
+        assertImmutable(LocalDate.class);
+    }
+
+    //-----------------------------------------------------------------------
+    // Since plusDays/minusDays actually depends on MJDays, it cannot be used for testing
+    private LocalDate next(LocalDate date) {
+        int newDayOfMonth = date.getDayOfMonth() + 1;
+        if (newDayOfMonth <= date.getMonth().length(isIsoLeap(date.getYear()))) {
+            return date.withDayOfMonth(newDayOfMonth);
+        }
+        date = date.withDayOfMonth(1);
+        if (date.getMonth() == Month.DECEMBER) {
+            date = date.withYear(date.getYear() + 1);
+        }
+        return date.with(date.getMonth().plus(1));
+    }
+
+    private LocalDate previous(LocalDate date) {
+        int newDayOfMonth = date.getDayOfMonth() - 1;
+        if (newDayOfMonth > 0) {
+            return date.withDayOfMonth(newDayOfMonth);
+        }
+        date = date.with(date.getMonth().minus(1));
+        if (date.getMonth() == Month.DECEMBER) {
+            date = date.withYear(date.getYear() - 1);
+        }
+        return date.withDayOfMonth(date.getMonth().length(isIsoLeap(date.getYear())));
+    }
+
+    @Test(groups={"implementation"})
+    public void test_with_DateTimeField_long_noChange_same() {
+        LocalDate t = TEST_2007_07_15.with(YEAR, 2007);
+        assertSame(t, TEST_2007_07_15);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withYear_int_noChange_same() {
+        LocalDate t = TEST_2007_07_15.withYear(2007);
+        assertSame(t, TEST_2007_07_15);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withMonth_int_noChange_same() {
+        LocalDate t = TEST_2007_07_15.withMonth(7);
+        assertSame(t, TEST_2007_07_15);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withDayOfMonth_noChange_same() {
+        LocalDate t = TEST_2007_07_15.withDayOfMonth(15);
+        assertSame(t, TEST_2007_07_15);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withDayOfYear_noChange_same() {
+        LocalDate t = TEST_2007_07_15.withDayOfYear(31 + 28 + 31 + 30 + 31 + 30 + 15);
+        assertSame(t, TEST_2007_07_15);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plus_Period_zero() {
+        LocalDate t = TEST_2007_07_15.plus(MockSimplePeriod.ZERO_DAYS);
+        assertSame(t, TEST_2007_07_15);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plus_longPeriodUnit_zero() {
+        LocalDate t = TEST_2007_07_15.plus(0, ChronoUnit.DAYS);
+        assertSame(t, TEST_2007_07_15);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusYears_long_noChange_same() {
+        LocalDate t = TEST_2007_07_15.plusYears(0);
+        assertSame(t, TEST_2007_07_15);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusMonths_long_noChange_same() {
+        LocalDate t = TEST_2007_07_15.plusMonths(0);
+        assertSame(t, TEST_2007_07_15);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusWeeks()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="samplePlusWeeksSymmetry")
+    Object[][] provider_samplePlusWeeksSymmetry() {
+        return new Object[][] {
+            {LocalDate.of(-1, 1, 1)},
+            {LocalDate.of(-1, 2, 28)},
+            {LocalDate.of(-1, 3, 1)},
+            {LocalDate.of(-1, 12, 31)},
+            {LocalDate.of(0, 1, 1)},
+            {LocalDate.of(0, 2, 28)},
+            {LocalDate.of(0, 2, 29)},
+            {LocalDate.of(0, 3, 1)},
+            {LocalDate.of(0, 12, 31)},
+            {LocalDate.of(2007, 1, 1)},
+            {LocalDate.of(2007, 2, 28)},
+            {LocalDate.of(2007, 3, 1)},
+            {LocalDate.of(2007, 12, 31)},
+            {LocalDate.of(2008, 1, 1)},
+            {LocalDate.of(2008, 2, 28)},
+            {LocalDate.of(2008, 2, 29)},
+            {LocalDate.of(2008, 3, 1)},
+            {LocalDate.of(2008, 12, 31)},
+            {LocalDate.of(2099, 1, 1)},
+            {LocalDate.of(2099, 2, 28)},
+            {LocalDate.of(2099, 3, 1)},
+            {LocalDate.of(2099, 12, 31)},
+            {LocalDate.of(2100, 1, 1)},
+            {LocalDate.of(2100, 2, 28)},
+            {LocalDate.of(2100, 3, 1)},
+            {LocalDate.of(2100, 12, 31)},
+        };
+    }
+
+    @Test(dataProvider="samplePlusWeeksSymmetry", groups={"implementation"})
+    public void test_plusWeeks_symmetry(LocalDate reference) {
+        for (int weeks = 0; weeks < 365 * 8; weeks++) {
+            LocalDate t = reference.plusWeeks(weeks).plusWeeks(-weeks);
+            assertEquals(t, reference);
+
+            t = reference.plusWeeks(-weeks).plusWeeks(weeks);
+            assertEquals(t, reference);
+        }
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusWeeks_noChange_same() {
+        LocalDate t = TEST_2007_07_15.plusWeeks(0);
+        assertSame(t, TEST_2007_07_15);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusDays()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="samplePlusDaysSymmetry")
+    Object[][] provider_samplePlusDaysSymmetry() {
+        return new Object[][] {
+            {LocalDate.of(-1, 1, 1)},
+            {LocalDate.of(-1, 2, 28)},
+            {LocalDate.of(-1, 3, 1)},
+            {LocalDate.of(-1, 12, 31)},
+            {LocalDate.of(0, 1, 1)},
+            {LocalDate.of(0, 2, 28)},
+            {LocalDate.of(0, 2, 29)},
+            {LocalDate.of(0, 3, 1)},
+            {LocalDate.of(0, 12, 31)},
+            {LocalDate.of(2007, 1, 1)},
+            {LocalDate.of(2007, 2, 28)},
+            {LocalDate.of(2007, 3, 1)},
+            {LocalDate.of(2007, 12, 31)},
+            {LocalDate.of(2008, 1, 1)},
+            {LocalDate.of(2008, 2, 28)},
+            {LocalDate.of(2008, 2, 29)},
+            {LocalDate.of(2008, 3, 1)},
+            {LocalDate.of(2008, 12, 31)},
+            {LocalDate.of(2099, 1, 1)},
+            {LocalDate.of(2099, 2, 28)},
+            {LocalDate.of(2099, 3, 1)},
+            {LocalDate.of(2099, 12, 31)},
+            {LocalDate.of(2100, 1, 1)},
+            {LocalDate.of(2100, 2, 28)},
+            {LocalDate.of(2100, 3, 1)},
+            {LocalDate.of(2100, 12, 31)},
+        };
+    }
+
+    @Test(dataProvider="samplePlusDaysSymmetry", groups={"implementation"})
+    public void test_plusDays_symmetry(LocalDate reference) {
+        for (int days = 0; days < 365 * 8; days++) {
+            LocalDate t = reference.plusDays(days).plusDays(-days);
+            assertEquals(t, reference);
+
+            t = reference.plusDays(-days).plusDays(days);
+            assertEquals(t, reference);
+        }
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusDays_noChange_same() {
+        LocalDate t = TEST_2007_07_15.plusDays(0);
+        assertSame(t, TEST_2007_07_15);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minus_Period_zero() {
+        LocalDate t = TEST_2007_07_15.minus(MockSimplePeriod.ZERO_DAYS);
+        assertSame(t, TEST_2007_07_15);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minus_longPeriodUnit_zero() {
+        LocalDate t = TEST_2007_07_15.minus(0, ChronoUnit.DAYS);
+        assertSame(t, TEST_2007_07_15);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusYears_long_noChange_same() {
+        LocalDate t = TEST_2007_07_15.minusYears(0);
+        assertSame(t, TEST_2007_07_15);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusMonths_long_noChange_same() {
+        LocalDate t = TEST_2007_07_15.minusMonths(0);
+        assertSame(t, TEST_2007_07_15);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusWeeks()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sampleMinusWeeksSymmetry")
+    Object[][] provider_sampleMinusWeeksSymmetry() {
+        return new Object[][] {
+            {LocalDate.of(-1, 1, 1)},
+            {LocalDate.of(-1, 2, 28)},
+            {LocalDate.of(-1, 3, 1)},
+            {LocalDate.of(-1, 12, 31)},
+            {LocalDate.of(0, 1, 1)},
+            {LocalDate.of(0, 2, 28)},
+            {LocalDate.of(0, 2, 29)},
+            {LocalDate.of(0, 3, 1)},
+            {LocalDate.of(0, 12, 31)},
+            {LocalDate.of(2007, 1, 1)},
+            {LocalDate.of(2007, 2, 28)},
+            {LocalDate.of(2007, 3, 1)},
+            {LocalDate.of(2007, 12, 31)},
+            {LocalDate.of(2008, 1, 1)},
+            {LocalDate.of(2008, 2, 28)},
+            {LocalDate.of(2008, 2, 29)},
+            {LocalDate.of(2008, 3, 1)},
+            {LocalDate.of(2008, 12, 31)},
+            {LocalDate.of(2099, 1, 1)},
+            {LocalDate.of(2099, 2, 28)},
+            {LocalDate.of(2099, 3, 1)},
+            {LocalDate.of(2099, 12, 31)},
+            {LocalDate.of(2100, 1, 1)},
+            {LocalDate.of(2100, 2, 28)},
+            {LocalDate.of(2100, 3, 1)},
+            {LocalDate.of(2100, 12, 31)},
+        };
+    }
+
+    @Test(dataProvider="sampleMinusWeeksSymmetry", groups={"implementation"})
+    public void test_minusWeeks_symmetry(LocalDate reference) {
+        for (int weeks = 0; weeks < 365 * 8; weeks++) {
+            LocalDate t = reference.minusWeeks(weeks).minusWeeks(-weeks);
+            assertEquals(t, reference);
+
+            t = reference.minusWeeks(-weeks).minusWeeks(weeks);
+            assertEquals(t, reference);
+        }
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusWeeks_noChange_same() {
+        LocalDate t = TEST_2007_07_15.minusWeeks(0);
+        assertSame(t, TEST_2007_07_15);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusDays()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sampleMinusDaysSymmetry")
+    Object[][] provider_sampleMinusDaysSymmetry() {
+        return new Object[][] {
+            {LocalDate.of(-1, 1, 1)},
+            {LocalDate.of(-1, 2, 28)},
+            {LocalDate.of(-1, 3, 1)},
+            {LocalDate.of(-1, 12, 31)},
+            {LocalDate.of(0, 1, 1)},
+            {LocalDate.of(0, 2, 28)},
+            {LocalDate.of(0, 2, 29)},
+            {LocalDate.of(0, 3, 1)},
+            {LocalDate.of(0, 12, 31)},
+            {LocalDate.of(2007, 1, 1)},
+            {LocalDate.of(2007, 2, 28)},
+            {LocalDate.of(2007, 3, 1)},
+            {LocalDate.of(2007, 12, 31)},
+            {LocalDate.of(2008, 1, 1)},
+            {LocalDate.of(2008, 2, 28)},
+            {LocalDate.of(2008, 2, 29)},
+            {LocalDate.of(2008, 3, 1)},
+            {LocalDate.of(2008, 12, 31)},
+            {LocalDate.of(2099, 1, 1)},
+            {LocalDate.of(2099, 2, 28)},
+            {LocalDate.of(2099, 3, 1)},
+            {LocalDate.of(2099, 12, 31)},
+            {LocalDate.of(2100, 1, 1)},
+            {LocalDate.of(2100, 2, 28)},
+            {LocalDate.of(2100, 3, 1)},
+            {LocalDate.of(2100, 12, 31)},
+        };
+    }
+
+    @Test(dataProvider="sampleMinusDaysSymmetry", groups={"implementation"})
+    public void test_minusDays_symmetry(LocalDate reference) {
+        for (int days = 0; days < 365 * 8; days++) {
+            LocalDate t = reference.minusDays(days).minusDays(-days);
+            assertEquals(t, reference);
+
+            t = reference.minusDays(-days).minusDays(days);
+            assertEquals(t, reference);
+        }
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusDays_noChange_same() {
+        LocalDate t = TEST_2007_07_15.minusDays(0);
+        assertSame(t, TEST_2007_07_15);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_toEpochDay_fromMJDays_symmetry() {
+        long date_0000_01_01 = -678941 - 40587;
+
+        LocalDate test = LocalDate.of(0, 1, 1);
+        for (long i = date_0000_01_01; i < 700000; i++) {
+            assertEquals(LocalDate.ofEpochDay(test.toEpochDay()), test);
+            test = next(test);
+        }
+        test = LocalDate.of(0, 1, 1);
+        for (long i = date_0000_01_01; i > -2000000; i--) {
+            assertEquals(LocalDate.ofEpochDay(test.toEpochDay()), test);
+            test = previous(test);
+        }
+    }
+
+    void doTest_comparisons_LocalDate(LocalDate... localDates) {
+        for (int i = 0; i < localDates.length; i++) {
+            LocalDate a = localDates[i];
+            for (int j = 0; j < localDates.length; j++) {
+                LocalDate b = localDates[j];
+                if (i < j) {
+                    assertTrue(a.compareTo(b) < 0, a + " <=> " + b);
+                    assertEquals(a.isBefore(b), true, a + " <=> " + b);
+                    assertEquals(a.isAfter(b), false, a + " <=> " + b);
+                    assertEquals(a.equals(b), false, a + " <=> " + b);
+                } else if (i > j) {
+                    assertTrue(a.compareTo(b) > 0, a + " <=> " + b);
+                    assertEquals(a.isBefore(b), false, a + " <=> " + b);
+                    assertEquals(a.isAfter(b), true, a + " <=> " + b);
+                    assertEquals(a.equals(b), false, a + " <=> " + b);
+                } else {
+                    assertEquals(a.compareTo(b), 0, a + " <=> " + b);
+                    assertEquals(a.isBefore(b), false, a + " <=> " + b);
+                    assertEquals(a.isAfter(b), false, a + " <=> " + b);
+                    assertEquals(a.equals(b), true, a + " <=> " + b);
+                }
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/TestLocalDateTime.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,570 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.Period;
+import java.time.temporal.ChronoUnit;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test LocalDateTime.
+ */
+@Test
+public class TestLocalDateTime extends AbstractTest {
+
+    private LocalDateTime TEST_2007_07_15_12_30_40_987654321 = LocalDateTime.of(2007, 7, 15, 12, 30, 40, 987654321);
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_immutable() {
+        assertImmutable(LocalDateTime.class);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sampleDates")
+    Object[][] provider_sampleDates() {
+        return new Object[][] {
+            {2008, 7, 5},
+            {2007, 7, 5},
+            {2006, 7, 5},
+            {2005, 7, 5},
+            {2004, 1, 1},
+            {-1, 1, 2},
+        };
+    }
+
+    @DataProvider(name="sampleTimes")
+    Object[][] provider_sampleTimes() {
+        return new Object[][] {
+            {0, 0, 0, 0},
+            {0, 0, 0, 1},
+            {0, 0, 1, 0},
+            {0, 0, 1, 1},
+            {0, 1, 0, 0},
+            {0, 1, 0, 1},
+            {0, 1, 1, 0},
+            {0, 1, 1, 1},
+            {1, 0, 0, 0},
+            {1, 0, 0, 1},
+            {1, 0, 1, 0},
+            {1, 0, 1, 1},
+            {1, 1, 0, 0},
+            {1, 1, 0, 1},
+            {1, 1, 1, 0},
+            {1, 1, 1, 1},
+        };
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withYear_int_noChange() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.withYear(2007);
+        assertSame(t.getDate(), TEST_2007_07_15_12_30_40_987654321.getDate());
+        assertSame(t.getTime(), TEST_2007_07_15_12_30_40_987654321.getTime());
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withMonth_int_noChange() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.withMonth(7);
+        assertSame(t.getDate(), TEST_2007_07_15_12_30_40_987654321.getDate());
+        assertSame(t.getTime(), TEST_2007_07_15_12_30_40_987654321.getTime());
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withDayOfMonth_noChange() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.withDayOfMonth(15);
+        assertSame(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withDayOfYear_noChange() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.withDayOfYear(31 + 28 + 31 + 30 + 31 + 30 + 15);
+        assertSame(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withHour_noChange() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.withHour(12);
+        assertSame(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withHour_toMidnight() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(1, 0)).withHour(0);
+        assertSame(t.getTime(), LocalTime.MIDNIGHT);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withHour_toMidday() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(1, 0)).withHour(12);
+        assertSame(t.getTime(), LocalTime.NOON);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withMinute_noChange() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.withMinute(30);
+        assertSame(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withMinute_toMidnight() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(0, 1)).withMinute(0);
+        assertSame(t.getTime(), LocalTime.MIDNIGHT);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withMinute_toMidday() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(12, 1)).withMinute(0);
+        assertSame(t.getTime(), LocalTime.NOON);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withSecond_noChange() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.withSecond(40);
+        assertSame(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withSecond_toMidnight() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(0, 0, 1)).withSecond(0);
+        assertSame(t.getTime(), LocalTime.MIDNIGHT);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withSecond_toMidday() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(12, 0, 1)).withSecond(0);
+        assertSame(t.getTime(), LocalTime.NOON);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withNanoOfSecond_noChange() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.withNano(987654321);
+        assertSame(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withNanoOfSecond_toMidnight() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(0, 0, 0, 1)).withNano(0);
+        assertSame(t.getTime(), LocalTime.MIDNIGHT);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withNanoOfSecond_toMidday() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(12, 0, 0, 1)).withNano(0);
+        assertSame(t.getTime(), LocalTime.NOON);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plus_adjuster_zero() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plus(Period.ZERO);
+        assertSame(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plus_Period_zero() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plus(MockSimplePeriod.ZERO_DAYS);
+        assertSame(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plus_longPeriodUnit_zero() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plus(0, ChronoUnit.DAYS);
+        assertSame(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusYears_int_noChange() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusYears(0);
+        assertSame(TEST_2007_07_15_12_30_40_987654321, t);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusMonths_int_noChange() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusMonths(0);
+        assertSame(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusWeeks_noChange() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusWeeks(0);
+        assertSame(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusDays_noChange() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusDays(0);
+        assertSame(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusHours_noChange() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusHours(0);
+        assertSame(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusHours_toMidnight() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(23, 0)).plusHours(1);
+        assertSame(t.getTime(), LocalTime.MIDNIGHT);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusHours_toMidday() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(11, 0)).plusHours(1);
+        assertSame(t.getTime(), LocalTime.NOON);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusMinutes_noChange() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusMinutes(0);
+        assertSame(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusMinutes_noChange_oneDay_same() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusMinutes(24 * 60);
+        assertSame(t.getTime(), TEST_2007_07_15_12_30_40_987654321.getTime());
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusMinutes_toMidnight() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(23, 59)).plusMinutes(1);
+        assertSame(t.getTime(), LocalTime.MIDNIGHT);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusMinutes_toMidday() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(11, 59)).plusMinutes(1);
+        assertSame(t.getTime(), LocalTime.NOON);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusSeconds_noChange() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusSeconds(0);
+        assertSame(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusSeconds_noChange_oneDay_same() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusSeconds(24 * 60 * 60);
+        assertSame(t.getTime(), TEST_2007_07_15_12_30_40_987654321.getTime());
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusSeconds_toMidnight() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(23, 59, 59)).plusSeconds(1);
+        assertSame(t.getTime(), LocalTime.MIDNIGHT);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusSeconds_toMidday() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(11, 59, 59)).plusSeconds(1);
+        assertSame(t.getTime(), LocalTime.NOON);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusNanos_noChange() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusNanos(0);
+        assertSame(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusNanos_noChange_oneDay_same() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusNanos(24 * 60 * 60 * 1000000000L);
+        assertSame(t.getTime(), TEST_2007_07_15_12_30_40_987654321.getTime());
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusNanos_toMidnight() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(23, 59, 59, 999999999)).plusNanos(1);
+        assertSame(t.getTime(), LocalTime.MIDNIGHT);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusNanos_toMidday() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(11, 59, 59, 999999999)).plusNanos(1);
+        assertSame(t.getTime(), LocalTime.NOON);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minus_adjuster_zero() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minus(Period.ZERO);
+        assertSame(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minus_Period_zero() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minus(MockSimplePeriod.ZERO_DAYS);
+        assertSame(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minus_longPeriodUnit_zero() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minus(0, ChronoUnit.DAYS);
+        assertSame(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusYears_int_noChange() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusYears(0);
+        assertSame(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusMonths_int_noChange() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusMonths(0);
+        assertSame(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusWeeks_noChange() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusWeeks(0);
+        assertSame(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusDays_noChange() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusDays(0);
+        assertSame(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusHours_noChange() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusHours(0);
+        assertSame(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusHours_toMidnight() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(1, 0)).minusHours(1);
+        assertSame(t.getTime(), LocalTime.MIDNIGHT);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusHours_toMidday() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(13, 0)).minusHours(1);
+        assertSame(t.getTime(), LocalTime.NOON);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusMinutes_noChange() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusMinutes(0);
+        assertSame(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusMinutes_noChange_oneDay_same() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusMinutes(24 * 60);
+        assertSame(t.getTime(), TEST_2007_07_15_12_30_40_987654321.getTime());
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusMinutes_toMidnight() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(0, 1)).minusMinutes(1);
+        assertSame(t.getTime(), LocalTime.MIDNIGHT);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusMinutes_toMidday() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(12, 1)).minusMinutes(1);
+        assertSame(t.getTime(), LocalTime.NOON);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusSeconds_noChange() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusSeconds(0);
+        assertSame(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusSeconds_noChange_oneDay() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusSeconds(24 * 60 * 60);
+        assertEquals(t.getDate(), TEST_2007_07_15_12_30_40_987654321.getDate().minusDays(1));
+        assertSame(t.getTime(), TEST_2007_07_15_12_30_40_987654321.getTime());
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusSeconds_toMidnight() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(0, 0, 1)).minusSeconds(1);
+        assertSame(t.getTime(), LocalTime.MIDNIGHT);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusSeconds_toMidday() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(12, 0, 1)).minusSeconds(1);
+        assertSame(t.getTime(), LocalTime.NOON);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusNanos_noChange() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusNanos(0);
+        assertSame(t, TEST_2007_07_15_12_30_40_987654321);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusNanos_noChange_oneDay() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusNanos(24 * 60 * 60 * 1000000000L);
+        assertEquals(t.getDate(), TEST_2007_07_15_12_30_40_987654321.getDate().minusDays(1));
+        assertSame(t.getTime(), TEST_2007_07_15_12_30_40_987654321.getTime());
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusNanos_toMidnight() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(0, 0, 0, 1)).minusNanos(1);
+        assertSame(t.getTime(), LocalTime.MIDNIGHT);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusNanos_toMidday() {
+        LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(12, 0, 0, 1)).minusNanos(1);
+        assertSame(t.getTime(), LocalTime.NOON);
+    }
+
+    //-----------------------------------------------------------------------
+    // getDate()
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="sampleDates", groups={"implementation"})
+    public void test_getDate(int year, int month, int day) {
+        LocalDate d = LocalDate.of(year, month, day);
+        LocalDateTime dt = LocalDateTime.of(d, LocalTime.MIDNIGHT);
+        assertSame(dt.getDate(), d);
+    }
+
+    //-----------------------------------------------------------------------
+    // getTime()
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="sampleTimes", groups={"implementation"})
+    public void test_getTime(int h, int m, int s, int ns) {
+        LocalTime t = LocalTime.of(h, m, s, ns);
+        LocalDateTime dt = LocalDateTime.of(LocalDate.of(2011, 7, 30), t);
+        assertSame(dt.getTime(), t);
+    }
+
+    void test_comparisons_LocalDateTime(LocalDate... localDates) {
+        test_comparisons_LocalDateTime(
+            localDates,
+            LocalTime.MIDNIGHT,
+            LocalTime.of(0, 0, 0, 999999999),
+            LocalTime.of(0, 0, 59, 0),
+            LocalTime.of(0, 0, 59, 999999999),
+            LocalTime.of(0, 59, 0, 0),
+            LocalTime.of(0, 59, 59, 999999999),
+            LocalTime.NOON,
+            LocalTime.of(12, 0, 0, 999999999),
+            LocalTime.of(12, 0, 59, 0),
+            LocalTime.of(12, 0, 59, 999999999),
+            LocalTime.of(12, 59, 0, 0),
+            LocalTime.of(12, 59, 59, 999999999),
+            LocalTime.of(23, 0, 0, 0),
+            LocalTime.of(23, 0, 0, 999999999),
+            LocalTime.of(23, 0, 59, 0),
+            LocalTime.of(23, 0, 59, 999999999),
+            LocalTime.of(23, 59, 0, 0),
+            LocalTime.of(23, 59, 59, 999999999)
+        );
+    }
+
+    void test_comparisons_LocalDateTime(LocalDate[] localDates, LocalTime... localTimes) {
+        LocalDateTime[] localDateTimes = new LocalDateTime[localDates.length * localTimes.length];
+        int i = 0;
+
+        for (LocalDate localDate : localDates) {
+            for (LocalTime localTime : localTimes) {
+                localDateTimes[i++] = LocalDateTime.of(localDate, localTime);
+            }
+        }
+
+        doTest_comparisons_LocalDateTime(localDateTimes);
+    }
+
+    void doTest_comparisons_LocalDateTime(LocalDateTime[] localDateTimes) {
+        for (int i = 0; i < localDateTimes.length; i++) {
+            LocalDateTime a = localDateTimes[i];
+            for (int j = 0; j < localDateTimes.length; j++) {
+                LocalDateTime b = localDateTimes[j];
+                if (i < j) {
+                    assertTrue(a.compareTo(b) < 0, a + " <=> " + b);
+                    assertEquals(a.isBefore(b), true, a + " <=> " + b);
+                    assertEquals(a.isAfter(b), false, a + " <=> " + b);
+                    assertEquals(a.equals(b), false, a + " <=> " + b);
+                } else if (i > j) {
+                    assertTrue(a.compareTo(b) > 0, a + " <=> " + b);
+                    assertEquals(a.isBefore(b), false, a + " <=> " + b);
+                    assertEquals(a.isAfter(b), true, a + " <=> " + b);
+                    assertEquals(a.equals(b), false, a + " <=> " + b);
+                } else {
+                    assertEquals(a.compareTo(b), 0, a + " <=> " + b);
+                    assertEquals(a.isBefore(b), false, a + " <=> " + b);
+                    assertEquals(a.isAfter(b), false, a + " <=> " + b);
+                    assertEquals(a.equals(b), true, a + " <=> " + b);
+                }
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/TestLocalTime.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertSame;
+
+import java.time.LocalTime;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test LocalTime.
+ */
+@Test
+public class TestLocalTime extends AbstractTest {
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_immutable() {
+        assertImmutable(LocalTime.class);
+    }
+
+    //-----------------------------------------------------------------------
+    private void check(LocalTime time, int h, int m, int s, int n) {
+        assertEquals(time.getHour(), h);
+        assertEquals(time.getMinute(), m);
+        assertEquals(time.getSecond(), s);
+        assertEquals(time.getNano(), n);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck","implementation"})
+    public void constant_MIDNIGHT() {
+        check(LocalTime.MIDNIGHT, 0, 0, 0, 0);
+    }
+
+    @Test(groups={"implementation"})
+    public void constant_MIDNIGHT_same() {
+        assertSame(LocalTime.MIDNIGHT, LocalTime.MIDNIGHT);
+        assertSame(LocalTime.MIDNIGHT, LocalTime.of(0, 0));
+    }
+
+    @Test(groups={"tck","implementation"})
+    public void constant_MIDDAY() {
+        check(LocalTime.NOON, 12, 0, 0, 0);
+    }
+
+    @Test(groups={"implementation"})
+    public void constant_MIDDAY_same() {
+        assertSame(LocalTime.NOON, LocalTime.NOON);
+        assertSame(LocalTime.NOON, LocalTime.of(12, 0));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"tck","implementation"})
+    public void constant_MIN_TIME() {
+        check(LocalTime.MIN, 0, 0, 0, 0);
+    }
+
+    @Test(groups={"implementation"})
+    public void constant_MIN_TIME_same() {
+        assertSame(LocalTime.MIN, LocalTime.of(0, 0));
+    }
+
+    @Test(groups={"tck","implementation"})
+    public void constant_MAX_TIME() {
+        check(LocalTime.MAX, 23, 59, 59, 999999999);
+    }
+
+    @Test(groups={"implementation"})
+    public void constant_MAX_TIME_same() {
+        assertSame(LocalTime.NOON, LocalTime.NOON);
+        assertSame(LocalTime.NOON, LocalTime.of(12, 0));
+    }
+
+    @Test(groups={"implementation"})
+    public void factory_time_2ints_singletons() {
+        for (int i = 0; i < 24; i++) {
+            LocalTime test1 = LocalTime.of(i, 0);
+            LocalTime test2 = LocalTime.of(i, 0);
+            assertSame(test1, test2);
+        }
+    }
+
+    @Test(groups={"implementation"})
+    public void factory_time_3ints_singletons() {
+        for (int i = 0; i < 24; i++) {
+            LocalTime test1 = LocalTime.of(i, 0, 0);
+            LocalTime test2 = LocalTime.of(i, 0, 0);
+            assertSame(test1, test2);
+        }
+    }
+
+    @Test(groups={"implementation"})
+    public void factory_time_4ints_singletons() {
+        for (int i = 0; i < 24; i++) {
+            LocalTime test1 = LocalTime.of(i, 0, 0, 0);
+            LocalTime test2 = LocalTime.of(i, 0, 0, 0);
+            assertSame(test1, test2);
+        }
+    }
+
+    @Test(groups={"implementation"})
+    public void factory_ofSecondOfDay_singletons() {
+        for (int i = 0; i < 24; i++) {
+            LocalTime test1 = LocalTime.ofSecondOfDay(i * 60L * 60L);
+            LocalTime test2 = LocalTime.of(i, 0);
+            assertSame(test1, test2);
+        }
+    }
+
+    @Test(groups={"implementation"})
+    public void factory_ofSecondOfDay7_long_int_singletons() {
+        for (int i = 0; i < 24; i++) {
+            LocalTime test1 = LocalTime.ofSecondOfDay(i * 60L * 60L, 0);
+            LocalTime test2 = LocalTime.of(i, 0);
+            assertSame(test1, test2);
+        }
+    }
+
+    @Test(groups={"implementation"})
+    public void factory_ofNanoOfDay_singletons() {
+        for (int i = 0; i < 24; i++) {
+            LocalTime test1 = LocalTime.ofNanoOfDay(i * 1000000000L * 60L * 60L);
+            LocalTime test2 = LocalTime.of(i, 0);
+            assertSame(test1, test2);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/TestPeriod.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,1575 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time;
+
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.HALF_DAYS;
+import static java.time.temporal.ChronoUnit.HOURS;
+import static java.time.temporal.ChronoUnit.MICROS;
+import static java.time.temporal.ChronoUnit.MILLIS;
+import static java.time.temporal.ChronoUnit.MINUTES;
+import static java.time.temporal.ChronoUnit.MONTHS;
+import static java.time.temporal.ChronoUnit.NANOS;
+import static java.time.temporal.ChronoUnit.SECONDS;
+import static java.time.temporal.ChronoUnit.YEARS;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+
+import java.time.DateTimeException;
+import java.time.Duration;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.Month;
+import java.time.Period;
+import java.time.temporal.YearMonth;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test.
+ */
+@Test
+public class TestPeriod extends AbstractTest {
+
+    //-----------------------------------------------------------------------
+    // basics
+    //-----------------------------------------------------------------------
+    public void test_interfaces() {
+        assertTrue(Serializable.class.isAssignableFrom(Period.class));
+    }
+
+    @DataProvider(name="serialization")
+    Object[][] data_serialization() {
+        return new Object[][] {
+            {Period.ZERO},
+            {Period.of(0, DAYS)},
+            {Period.of(1, DAYS)},
+            {Period.of(1, 2, 3, 4, 5, 6)},
+        };
+    }
+
+    @Test(dataProvider="serialization")
+    public void test_serialization(Period period) throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream oos = new ObjectOutputStream(baos);
+        oos.writeObject(period);
+        oos.close();
+
+        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(
+                baos.toByteArray()));
+        if (period.isZero()) {
+            assertSame(ois.readObject(), period);
+        } else {
+            assertEquals(ois.readObject(), period);
+        }
+    }
+
+    @Test
+    public void test_immutable() {
+        assertImmutable(Period.class);
+    }
+
+    //-----------------------------------------------------------------------
+    // factories
+    //-----------------------------------------------------------------------
+    public void factory_zeroSingleton() {
+        assertSame(Period.ZERO, Period.ZERO);
+        assertSame(Period.of(0, 0, 0, 0, 0, 0), Period.ZERO);
+        assertSame(Period.of(0, 0, 0, 0, 0, 0, 0), Period.ZERO);
+        assertSame(Period.ofDate(0, 0, 0), Period.ZERO);
+        assertSame(Period.ofTime(0, 0, 0), Period.ZERO);
+        assertSame(Period.ofTime(0, 0, 0, 0), Period.ZERO);
+        assertSame(Period.of(0, YEARS), Period.ZERO);
+        assertSame(Period.of(0, MONTHS), Period.ZERO);
+        assertSame(Period.of(0, DAYS), Period.ZERO);
+        assertSame(Period.of(0, HOURS), Period.ZERO);
+        assertSame(Period.of(0, MINUTES), Period.ZERO);
+        assertSame(Period.of(0, SECONDS), Period.ZERO);
+        assertSame(Period.of(0, NANOS), Period.ZERO);
+    }
+
+    //-----------------------------------------------------------------------
+    // of(PeriodProvider)
+    //-----------------------------------------------------------------------
+    public void factory_of_ints() {
+        assertPeriod(Period.of(1, 2, 3, 4, 5, 6), 1, 2, 3, 4, 5, 6, 0);
+        assertPeriod(Period.of(0, 2, 3, 4, 5, 6), 0, 2, 3, 4, 5, 6, 0);
+        assertPeriod(Period.of(1, 0, 0, 0, 0, 0), 1, 0, 0, 0, 0, 0, 0);
+        assertPeriod(Period.of(0, 0, 0, 0, 0, 0), 0, 0, 0, 0, 0, 0, 0);
+        assertPeriod(Period.of(-1, -2, -3, -4, -5, -6), -1, -2, -3, -4, -5, -6, 0);
+    }
+
+    //-----------------------------------------------------------------------
+    // ofDate
+    //-----------------------------------------------------------------------
+    public void factory_ofDate_ints() {
+        assertPeriod(Period.ofDate(1, 2, 3), 1, 2, 3, 0, 0, 0, 0);
+        assertPeriod(Period.ofDate(0, 2, 3), 0, 2, 3, 0, 0, 0, 0);
+        assertPeriod(Period.ofDate(1, 0, 0), 1, 0, 0, 0, 0, 0, 0);
+        assertPeriod(Period.ofDate(0, 0, 0), 0, 0, 0, 0, 0, 0, 0);
+        assertPeriod(Period.ofDate(-1, -2, -3), -1, -2, -3, 0, 0, 0, 0);
+    }
+
+    //-----------------------------------------------------------------------
+    // ofTime
+    //-----------------------------------------------------------------------
+    public void factory_ofTime_3ints() {
+        assertPeriod(Period.ofTime(1, 2, 3), 0, 0, 0, 1, 2, 3, 0);
+        assertPeriod(Period.ofTime(0, 2, 3), 0, 0, 0, 0, 2, 3, 0);
+        assertPeriod(Period.ofTime(1, 0, 0), 0, 0, 0, 1, 0, 0, 0);
+        assertPeriod(Period.ofTime(0, 0, 0), 0, 0, 0, 0, 0, 0, 0);
+        assertPeriod(Period.ofTime(-1, -2, -3), 0, 0, 0, -1, -2, -3, 0);
+    }
+
+    public void factory_ofTime_4ints() {
+        assertPeriod(Period.ofTime(1, 2, 3, 4), 0, 0, 0, 1, 2, 3, 4);
+        assertPeriod(Period.ofTime(0, 2, 3, 4), 0, 0, 0, 0, 2, 3, 4);
+        assertPeriod(Period.ofTime(1, 0, 0, 0), 0, 0, 0, 1, 0, 0, 0);
+        assertPeriod(Period.ofTime(0, 0, 0, 0), 0, 0, 0, 0, 0, 0, 0);
+        assertPeriod(Period.ofTime(-1, -2, -3, -4), 0, 0, 0, -1, -2, -3, -4);
+    }
+
+    //-----------------------------------------------------------------------
+    // of one field
+    //-----------------------------------------------------------------------
+    public void test_factory_of_intPeriodUnit() {
+        assertEquals(Period.of(1, YEARS), Period.of(1, YEARS));
+        assertEquals(Period.of(2, MONTHS), Period.of(2, MONTHS));
+        assertEquals(Period.of(3, DAYS), Period.of(3, DAYS));
+
+        assertEquals(Period.of(1, HALF_DAYS), Period.of(12, HOURS));
+        assertEquals(Period.of(Integer.MAX_VALUE / (3600 * 8), HOURS), Period.of(Integer.MAX_VALUE / (3600 * 8), HOURS));
+        assertEquals(Period.of(-1, MINUTES), Period.of(-1, MINUTES));
+        assertEquals(Period.of(-2, SECONDS), Period.of(-2, SECONDS));
+        assertEquals(Period.of(Integer.MIN_VALUE, NANOS), Period.of(Integer.MIN_VALUE, NANOS));
+        assertEquals(Period.of(2, MILLIS), Period.of(2000000, NANOS));
+        assertEquals(Period.of(2, MICROS), Period.of(2000, NANOS));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_factory_of_intPeriodUnit_null() {
+        Period.of(1, null);
+    }
+
+    //-----------------------------------------------------------------------
+    public void factory_years() {
+        assertPeriod(Period.of(1, YEARS), 1, 0, 0, 0, 0, 0, 0);
+        assertPeriod(Period.of(0, YEARS), 0, 0, 0, 0, 0, 0, 0);
+        assertPeriod(Period.of(-1, YEARS), -1, 0, 0, 0, 0, 0, 0);
+        assertPeriod(Period.of(Integer.MAX_VALUE, YEARS), Integer.MAX_VALUE, 0, 0, 0, 0, 0, 0);
+        assertPeriod(Period.of(Integer.MIN_VALUE, YEARS), Integer.MIN_VALUE, 0, 0, 0, 0, 0, 0);
+    }
+
+    public void factory_months() {
+        assertPeriod(Period.of(1, MONTHS), 0, 1, 0, 0, 0, 0, 0);
+        assertPeriod(Period.of(0, MONTHS), 0, 0, 0, 0, 0, 0, 0);
+        assertPeriod(Period.of(-1, MONTHS), 0, -1, 0, 0, 0, 0, 0);
+        assertPeriod(Period.of(Integer.MAX_VALUE, MONTHS), 0, Integer.MAX_VALUE, 0, 0, 0, 0, 0);
+        assertPeriod(Period.of(Integer.MIN_VALUE, MONTHS), 0, Integer.MIN_VALUE, 0, 0, 0, 0, 0);
+    }
+
+    public void factory_days() {
+        assertPeriod(Period.of(1, DAYS), 0, 0, 1, 0, 0, 0, 0);
+        assertPeriod(Period.of(0, DAYS), 0, 0, 0, 0, 0, 0, 0);
+        assertPeriod(Period.of(-1, DAYS), 0, 0, -1, 0, 0, 0, 0);
+        assertPeriod(Period.of(Integer.MAX_VALUE, DAYS), 0, 0, Integer.MAX_VALUE, 0, 0, 0, 0);
+        assertPeriod(Period.of(Integer.MIN_VALUE, DAYS), 0, 0, Integer.MIN_VALUE, 0, 0, 0, 0);
+    }
+
+    public void factory_hours() {
+        assertPeriod(Period.of(1, HOURS), 0, 0, 0, 1, 0, 0, 0);
+        assertPeriod(Period.of(0, HOURS), 0, 0, 0, 0, 0, 0, 0);
+        assertPeriod(Period.of(-1, HOURS), 0, 0, 0, -1, 0, 0, 0);
+        assertPeriod(Period.of(Integer.MAX_VALUE / (3600 * 8), HOURS), 0, 0, 0, Integer.MAX_VALUE / (3600 * 8), 0, 0, 0);
+        assertPeriod(Period.of(Integer.MIN_VALUE / (3600 * 8), HOURS), 0, 0, 0, Integer.MIN_VALUE / (3600 * 8), 0, 0, 0);
+    }
+
+    public void factory_minutes() {
+        assertPeriod(Period.of(1, MINUTES), 0, 0, 0, 0, 1, 0, 0);
+        assertPeriod(Period.of(0, MINUTES), 0, 0, 0, 0, 0, 0, 0);
+        assertPeriod(Period.of(-1, MINUTES), 0, 0, 0, 0, -1, 0, 0);
+        int val = Integer.MAX_VALUE / (60 * 8);
+        assertPeriod(Period.of(val, MINUTES), 0, 0, 0,
+                        (int) (val / 60L),
+                        (int) (val % 60),
+                        0, 0);
+        val = Integer.MIN_VALUE / (60 * 8);
+        assertPeriod(Period.of(val, MINUTES), 0, 0, 0,
+                        (int) (val / 60L),
+                        (int) (val % 60),
+                        0, 0);
+    }
+
+    public void factory_seconds() {
+        assertPeriod(Period.of(1, SECONDS), 0, 0, 0, 0, 0, 1, 0);
+        assertPeriod(Period.of(0, SECONDS), 0, 0, 0, 0, 0, 0, 0);
+        assertPeriod(Period.of(-1, SECONDS), 0, 0, 0, 0, 0, -1, 0);
+        assertPeriod(Period.of(Integer.MAX_VALUE, SECONDS), 0, 0, 0,
+                        (int) (Integer.MAX_VALUE / 3600L),
+                        (int) ((Integer.MAX_VALUE / 60L) % 60),
+                        (int) (Integer.MAX_VALUE % 60),
+                        0);
+        assertPeriod(Period.of(Integer.MIN_VALUE, SECONDS), 0, 0, 0,
+                        (int) (Integer.MIN_VALUE / 3600L),
+                        (int) ((Integer.MIN_VALUE / 60L) % 60),
+                        (int) (Integer.MIN_VALUE % 60),
+                        0);
+    }
+
+    public void factory_nanos() {
+        assertPeriod(Period.of(1, NANOS), 0, 0, 0, 0, 0, 0, 1);
+        assertPeriod(Period.of(0, NANOS), 0, 0, 0, 0, 0, 0, 0);
+        assertPeriod(Period.of(-1, NANOS), 0, 0, 0, 0, 0, 0, -1);
+        assertPeriod(Period.of(Long.MAX_VALUE, NANOS), 0, 0, 0,
+                        (int) (Long.MAX_VALUE / 3600_000_000_000L),
+                        (int) ((Long.MAX_VALUE / 60_000_000_000L) % 60),
+                        (int) ((Long.MAX_VALUE / 1_000_000_000L) % 60),
+                        Long.MAX_VALUE % 1_000_000_000L);
+        assertPeriod(Period.of(Long.MIN_VALUE, NANOS), 0, 0, 0,
+                        (int) (Long.MIN_VALUE / 3600_000_000_000L),
+                        (int) ((Long.MIN_VALUE / 60_000_000_000L) % 60),
+                        (int) ((Long.MIN_VALUE / 1_000_000_000L) % 60),
+                        Long.MIN_VALUE % 1_000_000_000L);
+    }
+
+    //-----------------------------------------------------------------------
+    // of(Duration)
+    //-----------------------------------------------------------------------
+    public void factory_duration() {
+        assertPeriod(Period.of(Duration.ofSeconds(2, 3)), 0, 0, 0, 0, 0, 2, 3);
+        assertPeriod(Period.of(Duration.ofSeconds(59, 3)), 0, 0, 0, 0, 0, 59, 3);
+        assertPeriod(Period.of(Duration.ofSeconds(60, 3)), 0, 0, 0, 0, 1, 0, 3);
+        assertPeriod(Period.of(Duration.ofSeconds(61, 3)), 0, 0, 0, 0, 1, 1, 3);
+        assertPeriod(Period.of(Duration.ofSeconds(3599, 3)), 0, 0, 0, 0, 59, 59, 3);
+        assertPeriod(Period.of(Duration.ofSeconds(3600, 3)), 0, 0, 0, 1, 0, 0, 3);
+    }
+
+    public void factory_duration_negative() {
+        assertPeriod(Period.of(Duration.ofSeconds(-2, 3)), 0, 0, 0, 0, 0, -1, -999999997);
+        assertPeriod(Period.of(Duration.ofSeconds(-59, 3)), 0, 0, 0, 0, 0, -58, -999999997);
+        assertPeriod(Period.of(Duration.ofSeconds(-60, 3)), 0, 0, 0, 0, 0, -59, -999999997);
+        assertPeriod(Period.of(Duration.ofSeconds(-60, -3)), 0, 0, 0, 0, -1, 0, -3);
+
+        assertPeriod(Period.of(Duration.ofSeconds(2, -3)), 0, 0, 0, 0, 0, 1, 999999997);
+    }
+
+    public void factory_duration_big() {
+        Duration dur = Duration.ofSeconds(Integer.MAX_VALUE, 3);
+        long secs = Integer.MAX_VALUE;
+        assertPeriod(Period.of(dur), 0, 0, 0, (int) (secs / 3600), (int) ((secs % 3600) / 60), (int) (secs % 60), 3);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void factory_duration_null() {
+        Period.of((Duration) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // between
+    //-----------------------------------------------------------------------
+    @DataProvider(name="betweenDates")
+    Object[][] data_betweenDates() {
+        return new Object[][] {
+            {2010, 1, 1, 2010, 1, 1,  0, 0, 0},
+            {2010, 1, 1, 2010, 1, 2,  0, 0, 1},
+            {2010, 1, 1, 2010, 2, 1,  0, 1, 0},
+            {2010, 1, 1, 2010, 2, 2,  0, 1, 1},
+            {2010, 1, 1, 2011, 1, 1,  1, 0, 0},
+
+            {2010, 6, 12, 2010, 1, 1,  0, -5, -11},
+            {2010, 6, 12, 2010, 1, 2,  0, -5, -10},
+            {2010, 6, 12, 2010, 2, 1,  0, -4, -11},
+            {2010, 6, 12, 2010, 9, 24,  0, 3, 12},
+
+            {2010, 6, 12, 2009, 1, 1,  -1, -5, -11},
+            {2010, 6, 12, 2009, 1, 2,  -1, -5, -10},
+            {2010, 6, 12, 2009, 2, 1,  -1, -4, -11},
+            {2010, 6, 12, 2009, 9, 24,  0, -9, 12},
+
+            {2010, 6, 12, 2008, 1, 1,  -2, -5, -11},
+            {2010, 6, 12, 2008, 1, 2,  -2, -5, -10},
+            {2010, 6, 12, 2008, 2, 1,  -2, -4, -11},
+            {2010, 6, 12, 2008, 9, 24,  -1, -9, 12},
+        };
+    }
+
+    @Test(dataProvider="betweenDates")
+    public void factory_between_LocalDate(int y1, int m1, int d1, int y2, int m2, int d2, int ye, int me, int de) {
+        LocalDate start = LocalDate.of(y1, m1, d1);
+        LocalDate end = LocalDate.of(y2, m2, d2);
+        Period test = Period.between(start, end);
+        assertPeriod(test, ye, me, de, 0, 0, 0, 0);
+        //assertEquals(start.plus(test), end);
+    }
+
+    @DataProvider(name="betweenTimes")
+    Object[][] data_betweenTimes() {
+        return new Object[][] {
+            {12, 30, 40, 12, 30, 45,  0, 0, 5},
+            {12, 30, 40, 12, 35, 40,  0, 5, 0},
+            {12, 30, 40, 13, 30, 40,  1, 0, 0},
+
+            {12, 30, 40, 12, 30, 35,  0, 0, -5},
+            {12, 30, 40, 12, 25, 40,  0, -5, 0},
+            {12, 30, 40, 11, 30, 40,  -1, 0, 0},
+        };
+    }
+
+    @Test(dataProvider="betweenTimes")
+    public void factory_between_LocalTime(int h1, int m1, int s1, int h2, int m2, int s2, int he, int me, int se) {
+        LocalTime start = LocalTime.of(h1, m1, s1);
+        LocalTime end = LocalTime.of(h2, m2, s2);
+        Period test = Period.between(start, end);
+        assertPeriod(test, 0, 0, 0, he, me, se, 0);
+        //assertEquals(start.plus(test), end);
+    }
+
+    public void factory_between_YearMonth() {
+        assertPeriod(Period.between(YearMonth.of(2012, 6), YearMonth.of(2013, 7)), 1, 1, 0, 0, 0, 0, 0);
+        assertPeriod(Period.between(YearMonth.of(2012, 6), YearMonth.of(2013, 3)), 0, 9, 0, 0, 0, 0, 0);
+        assertPeriod(Period.between(YearMonth.of(2012, 6), YearMonth.of(2011, 7)), 0, -11, 0, 0, 0, 0, 0);
+    }
+
+    public void factory_between_Month() {
+        assertPeriod(Period.between(Month.FEBRUARY, Month.MAY), 0, 3, 0, 0, 0, 0, 0);
+        assertPeriod(Period.between(Month.NOVEMBER, Month.MAY), 0, -6, 0, 0, 0, 0, 0);
+    }
+
+    //-----------------------------------------------------------------------
+    // betweenISO
+    //-----------------------------------------------------------------------
+    @DataProvider(name="betweenISO")
+    Object[][] data_betweenISO() {
+        return new Object[][] {
+            {2010, 1, 1, 2010, 1, 1, 0, 0, 0},
+            {2010, 1, 1, 2010, 1, 2, 0, 0, 1},
+            {2010, 1, 1, 2010, 1, 31, 0, 0, 30},
+            {2010, 1, 1, 2010, 2, 1, 0, 1, 0},
+            {2010, 1, 1, 2010, 2, 28, 0, 1, 27},
+            {2010, 1, 1, 2010, 3, 1, 0, 2, 0},
+            {2010, 1, 1, 2010, 12, 31, 0, 11, 30},
+            {2010, 1, 1, 2011, 1, 1, 1, 0, 0},
+            {2010, 1, 1, 2011, 12, 31, 1, 11, 30},
+            {2010, 1, 1, 2012, 1, 1, 2, 0, 0},
+
+            {2010, 1, 10, 2010, 1, 1, 0, 0, -9},
+            {2010, 1, 10, 2010, 1, 2, 0, 0, -8},
+            {2010, 1, 10, 2010, 1, 9, 0, 0, -1},
+            {2010, 1, 10, 2010, 1, 10, 0, 0, 0},
+            {2010, 1, 10, 2010, 1, 11, 0, 0, 1},
+            {2010, 1, 10, 2010, 1, 31, 0, 0, 21},
+            {2010, 1, 10, 2010, 2, 1, 0, 0, 22},
+            {2010, 1, 10, 2010, 2, 9, 0, 0, 30},
+            {2010, 1, 10, 2010, 2, 10, 0, 1, 0},
+            {2010, 1, 10, 2010, 2, 28, 0, 1, 18},
+            {2010, 1, 10, 2010, 3, 1, 0, 1, 19},
+            {2010, 1, 10, 2010, 3, 9, 0, 1, 27},
+            {2010, 1, 10, 2010, 3, 10, 0, 2, 0},
+            {2010, 1, 10, 2010, 12, 31, 0, 11, 21},
+            {2010, 1, 10, 2011, 1, 1, 0, 11, 22},
+            {2010, 1, 10, 2011, 1, 9, 0, 11, 30},
+            {2010, 1, 10, 2011, 1, 10, 1, 0, 0},
+
+            {2010, 3, 30, 2011, 5, 1, 1, 1, 1},
+            {2010, 4, 30, 2011, 5, 1, 1, 0, 1},
+
+            {2010, 2, 28, 2012, 2, 27, 1, 11, 30},
+            {2010, 2, 28, 2012, 2, 28, 2, 0, 0},
+            {2010, 2, 28, 2012, 2, 29, 2, 0, 1},
+
+            {2012, 2, 28, 2014, 2, 27, 1, 11, 30},
+            {2012, 2, 28, 2014, 2, 28, 2, 0, 0},
+            {2012, 2, 28, 2014, 3, 1, 2, 0, 1},
+
+            {2012, 2, 29, 2014, 2, 28, 1, 11, 30},
+            {2012, 2, 29, 2014, 3, 1, 2, 0, 1},
+            {2012, 2, 29, 2014, 3, 2, 2, 0, 2},
+
+            {2012, 2, 29, 2016, 2, 28, 3, 11, 30},
+            {2012, 2, 29, 2016, 2, 29, 4, 0, 0},
+            {2012, 2, 29, 2016, 3, 1, 4, 0, 1},
+
+            {2010, 1, 1, 2009, 12, 31, 0, 0, -1},
+            {2010, 1, 1, 2009, 12, 30, 0, 0, -2},
+            {2010, 1, 1, 2009, 12, 2, 0, 0, -30},
+            {2010, 1, 1, 2009, 12, 1, 0, -1, 0},
+            {2010, 1, 1, 2009, 11, 30, 0, -1, -1},
+            {2010, 1, 1, 2009, 11, 2, 0, -1, -29},
+            {2010, 1, 1, 2009, 11, 1, 0, -2, 0},
+            {2010, 1, 1, 2009, 1, 2, 0, -11, -30},
+            {2010, 1, 1, 2009, 1, 1, -1, 0, 0},
+
+            {2010, 1, 15, 2010, 1, 15, 0, 0, 0},
+            {2010, 1, 15, 2010, 1, 14, 0, 0, -1},
+            {2010, 1, 15, 2010, 1, 1, 0, 0, -14},
+            {2010, 1, 15, 2009, 12, 31, 0, 0, -15},
+            {2010, 1, 15, 2009, 12, 16, 0, 0, -30},
+            {2010, 1, 15, 2009, 12, 15, 0, -1, 0},
+            {2010, 1, 15, 2009, 12, 14, 0, -1, -1},
+
+            {2010, 2, 28, 2009, 3, 1, 0, -11, -27},
+            {2010, 2, 28, 2009, 2, 28, -1, 0, 0},
+            {2010, 2, 28, 2009, 2, 27, -1, 0, -1},
+
+            {2010, 2, 28, 2008, 2, 29, -1, -11, -28},
+            {2010, 2, 28, 2008, 2, 28, -2, 0, 0},
+            {2010, 2, 28, 2008, 2, 27, -2, 0, -1},
+
+            {2012, 2, 29, 2009, 3, 1, -2, -11, -28},
+            {2012, 2, 29, 2009, 2, 28, -3, 0, -1},
+            {2012, 2, 29, 2009, 2, 27, -3, 0, -2},
+
+            {2012, 2, 29, 2008, 3, 1, -3, -11, -28},
+            {2012, 2, 29, 2008, 2, 29, -4, 0, 0},
+            {2012, 2, 29, 2008, 2, 28, -4, 0, -1},
+        };
+    }
+
+    @Test(dataProvider="betweenISO")
+    public void factory_betweenISO_LocalDate(int y1, int m1, int d1, int y2, int m2, int d2, int ye, int me, int de) {
+        LocalDate start = LocalDate.of(y1, m1, d1);
+        LocalDate end = LocalDate.of(y2, m2, d2);
+        Period test = Period.betweenISO(start, end);
+        assertPeriod(test, ye, me, de, 0, 0, 0, 0);
+        //assertEquals(start.plus(test), end);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void factory_betweenISO_LocalDate_nullFirst() {
+        Period.betweenISO((LocalDate) null, LocalDate.of(2010, 1, 1));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void factory_betweenISO_LocalDate_nullSecond() {
+        Period.betweenISO(LocalDate.of(2010, 1, 1), (LocalDate) null);
+    }
+
+    //-------------------------------------------------------------------------
+    @Test(expectedExceptions=NullPointerException.class)
+    public void factory_betweenISO_LocalTime_nullFirst() {
+        Period.betweenISO((LocalTime) null, LocalTime.of(12, 30));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void factory_betweenISO_LocalTime_nullSecond() {
+        Period.betweenISO(LocalTime.of(12, 30), (LocalTime) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // parse()
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="toStringAndParse")
+    public void test_parse(Period test, String expected) {
+        assertEquals(test, Period.parse(expected));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_parse_nullText() {
+        Period.parse((String) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // isZero()
+    //-----------------------------------------------------------------------
+    public void test_isZero() {
+        assertEquals(Period.of(1, 2, 3, 4, 5, 6, 7).isZero(), false);
+        assertEquals(Period.of(1, 2, 3, 0, 0, 0, 0).isZero(), false);
+        assertEquals(Period.of(0, 0, 0, 4, 5, 6, 7).isZero(), false);
+        assertEquals(Period.of(1, 0, 0, 0, 0, 0, 0).isZero(), false);
+        assertEquals(Period.of(0, 2, 0, 0, 0, 0, 0).isZero(), false);
+        assertEquals(Period.of(0, 0, 3, 0, 0, 0, 0).isZero(), false);
+        assertEquals(Period.of(0, 0, 0, 4, 0, 0, 0).isZero(), false);
+        assertEquals(Period.of(0, 0, 0, 0, 5, 0, 0).isZero(), false);
+        assertEquals(Period.of(0, 0, 0, 0, 0, 6, 0).isZero(), false);
+        assertEquals(Period.of(0, 0, 0, 0, 0, 0, 7).isZero(), false);
+        assertEquals(Period.of(0, 0, 0, 0, 0, 0).isZero(), true);
+    }
+
+    //-----------------------------------------------------------------------
+    // isPositive()
+    //-----------------------------------------------------------------------
+    public void test_isPositive() {
+        assertEquals(Period.of(1, 2, 3, 4, 5, 6, 7).isPositive(), true);
+        assertEquals(Period.of(1, 2, 3, 0, 0, 0, 0).isPositive(), true);
+        assertEquals(Period.of(0, 0, 0, 4, 5, 6, 7).isPositive(), true);
+        assertEquals(Period.of(1, 0, 0, 0, 0, 0, 0).isPositive(), true);
+        assertEquals(Period.of(0, 2, 0, 0, 0, 0, 0).isPositive(), true);
+        assertEquals(Period.of(0, 0, 3, 0, 0, 0, 0).isPositive(), true);
+        assertEquals(Period.of(0, 0, 0, 4, 0, 0, 0).isPositive(), true);
+        assertEquals(Period.of(0, 0, 0, 0, 5, 0, 0).isPositive(), true);
+        assertEquals(Period.of(0, 0, 0, 0, 0, 6, 0).isPositive(), true);
+        assertEquals(Period.of(0, 0, 0, 0, 0, 0, 7).isPositive(), true);
+        assertEquals(Period.of(-1, -2, -3, -4, -5, -6, -7).isPositive(), false);
+        assertEquals(Period.of(-1, -2, 3, 4, -5, -6, -7).isPositive(), false);
+        assertEquals(Period.of(-1, 0, 0, 0, 0, 0, 0).isPositive(), false);
+        assertEquals(Period.of(0, -2, 0, 0, 0, 0, 0).isPositive(), false);
+        assertEquals(Period.of(0, 0, -3, 0, 0, 0, 0).isPositive(), false);
+        assertEquals(Period.of(0, 0, 0, -4, 0, 0, 0).isPositive(), false);
+        assertEquals(Period.of(0, 0, 0, 0, -5, 0, 0).isPositive(), false);
+        assertEquals(Period.of(0, 0, 0, 0, 0, -6, 0).isPositive(), false);
+        assertEquals(Period.of(0, 0, 0, 0, 0, 0, -7).isPositive(), false);
+        assertEquals(Period.of(0, 0, 0, 0, 0, 0).isPositive(), false);
+    }
+
+    //-----------------------------------------------------------------------
+    // withYears()
+    //-----------------------------------------------------------------------
+    public void test_withYears() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertPeriod(test.withYears(10), 10, 2, 3, 4, 5, 6, 7);
+    }
+
+    public void test_withYears_noChange() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertSame(test.withYears(1), test);
+    }
+
+    public void test_withYears_toZero() {
+        Period test = Period.of(1, YEARS);
+        assertSame(test.withYears(0), Period.ZERO);
+    }
+
+    //-----------------------------------------------------------------------
+    // withMonths()
+    //-----------------------------------------------------------------------
+    public void test_withMonths() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertPeriod(test.withMonths(10), 1, 10, 3, 4, 5, 6, 7);
+    }
+
+    public void test_withMonths_noChange() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertSame(test.withMonths(2), test);
+    }
+
+    public void test_withMonths_toZero() {
+        Period test = Period.of(1, MONTHS);
+        assertSame(test.withMonths(0), Period.ZERO);
+    }
+
+    //-----------------------------------------------------------------------
+    // withDays()
+    //-----------------------------------------------------------------------
+    public void test_withDays() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertPeriod(test.withDays(10), 1, 2, 10, 4, 5, 6, 7);
+    }
+
+    public void test_withDays_noChange() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertSame(test.withDays(3), test);
+    }
+
+    public void test_withDays_toZero() {
+        Period test = Period.of(1, DAYS);
+        assertSame(test.withDays(0), Period.ZERO);
+    }
+
+    //-----------------------------------------------------------------------
+    // withTimeNanos()
+    //-----------------------------------------------------------------------
+    public void test_withNanos() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertPeriod(test.withTimeNanos(10), 1, 2, 3, 0, 0, 0, 10);
+    }
+
+    public void test_withNanos_noChange() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertSame(test.withTimeNanos(((4 * 60 + 5) * 60 + 6) * 1_000_000_000L + 7), test);
+    }
+
+    public void test_withNanos_toZero() {
+        Period test = Period.of(1, NANOS);
+        assertSame(test.withTimeNanos(0), Period.ZERO);
+    }
+
+
+
+    //-----------------------------------------------------------------------
+    // plusYears()
+    //-----------------------------------------------------------------------
+    public void test_plusYears() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertPeriod(test.plus(10, YEARS), 11, 2, 3, 4, 5, 6, 7);
+        assertPeriod(test.plus(Period.of(10, YEARS)), 11, 2, 3, 4, 5, 6, 7);
+    }
+
+    public void test_plusYears_noChange() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertSame(test.plus(0, YEARS), test);
+        assertPeriod(test.plus(Period.of(0, YEARS)), 1, 2, 3, 4, 5, 6, 7);
+    }
+
+    public void test_plusYears_toZero() {
+        Period test = Period.of(-1, YEARS);
+        assertSame(test.plus(1, YEARS), Period.ZERO);
+        assertSame(test.plus(Period.of(1, YEARS)), Period.ZERO);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_plusYears_overflowTooBig() {
+        Period test = Period.of(Integer.MAX_VALUE, YEARS);
+        test.plus(1, YEARS);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_plusYears_overflowTooSmall() {
+        Period test = Period.of(Integer.MIN_VALUE, YEARS);
+        test.plus(-1, YEARS);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusMonths()
+    //-----------------------------------------------------------------------
+    public void test_plusMonths() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertPeriod(test.plus(10, MONTHS), 1, 12, 3, 4, 5, 6, 7);
+        assertPeriod(test.plus(Period.of(10, MONTHS)), 1, 12, 3, 4, 5, 6, 7);
+    }
+
+    public void test_plusMonths_noChange() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertSame(test.plus(0, MONTHS), test);
+        assertEquals(test.plus(Period.of(0, MONTHS)), test);
+    }
+
+    public void test_plusMonths_toZero() {
+        Period test = Period.of(-1, MONTHS);
+        assertSame(test.plus(1, MONTHS), Period.ZERO);
+        assertSame(test.plus(Period.of(1, MONTHS)), Period.ZERO);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_plusMonths_overflowTooBig() {
+        Period test = Period.of(Integer.MAX_VALUE, MONTHS);
+        test.plus(1, MONTHS);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_plusMonths_overflowTooSmall() {
+        Period test = Period.of(Integer.MIN_VALUE, MONTHS);
+        test.plus(-1, MONTHS);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusDays()
+    //-----------------------------------------------------------------------
+    public void test_plusDays() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertPeriod(test.plus(10, DAYS), 1, 2, 13, 4, 5, 6, 7);
+    }
+
+    public void test_plusDays_noChange() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertSame(test.plus(0, DAYS), test);
+    }
+
+    public void test_plusDays_toZero() {
+        Period test = Period.of(-1, DAYS);
+        assertSame(test.plus(1, DAYS), Period.ZERO);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_plusDays_overflowTooBig() {
+        Period test = Period.of(Integer.MAX_VALUE, DAYS);
+        test.plus(1, DAYS);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_plusDays_overflowTooSmall() {
+        Period test = Period.of(Integer.MIN_VALUE, DAYS);
+        test.plus(-1, DAYS);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusHours()
+    //-----------------------------------------------------------------------
+    public void test_plusHours() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertPeriod(test.plus(10, HOURS), 1, 2, 3, 14, 5, 6, 7);
+    }
+
+    public void test_plusHours_noChange() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertSame(test.plus(0, HOURS), test);
+    }
+
+    public void test_plusHours_toZero() {
+        Period test = Period.of(-1, HOURS);
+        assertSame(test.plus(1, HOURS), Period.ZERO);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_plusHours_overflowTooBig() {
+        Period test = Period.of(Integer.MAX_VALUE, HOURS);
+        test.plus(1, HOURS);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_plusHours_overflowTooSmall() {
+        Period test = Period.of(Integer.MIN_VALUE, HOURS);
+        test.plus(-1, HOURS);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusMinutes()
+    //-----------------------------------------------------------------------
+    public void test_plusMinutes() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertPeriod(test.plus(10, MINUTES), 1, 2, 3, 4, 15, 6, 7);
+    }
+
+    public void test_plusMinutes_noChange() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertSame(test.plus(0, MINUTES), test);
+    }
+
+    public void test_plusMinutes_toZero() {
+        Period test = Period.of(-1, MINUTES);
+        assertSame(test.plus(1, MINUTES), Period.ZERO);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusSeconds()
+    //-----------------------------------------------------------------------
+    public void test_plusSeconds() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertPeriod(test.plus(10, SECONDS), 1, 2, 3, 4, 5, 16, 7);
+    }
+
+    public void test_plusSeconds_noChange() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertSame(test.plus(0, SECONDS), test);
+    }
+
+    public void test_plusSeconds_toZero() {
+        Period test = Period.of(-1, SECONDS);
+        assertSame(test.plus(1, SECONDS), Period.ZERO);
+    }
+
+    //-----------------------------------------------------------------------
+    // plusNanos()
+    //-----------------------------------------------------------------------
+    public void test_plusNanos() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertPeriod(test.plus(10, NANOS), 1, 2, 3, 4, 5, 6, 17);
+    }
+
+    public void test_plusNanos_noChange() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertSame(test.plus(0, NANOS), test);
+    }
+
+    public void test_plusNanos_toZero() {
+        Period test = Period.of(-1, NANOS);
+        assertSame(test.plus(1, NANOS), Period.ZERO);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_plusNanos_overflowTooBig() {
+        Period test = Period.of(Long.MAX_VALUE, NANOS);
+        test.plus(1, NANOS);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_plusNanos_overflowTooSmall() {
+        Period test = Period.of(Long.MIN_VALUE, NANOS);
+        test.plus(-1, NANOS);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusYears()
+    //-----------------------------------------------------------------------
+    public void test_minusYears() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertPeriod(test.minus(10, YEARS), -9, 2, 3, 4, 5, 6, 7);
+    }
+
+    public void test_minusYears_noChange() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertSame(test.minus(0, YEARS), test);
+    }
+
+    public void test_minusYears_toZero() {
+        Period test = Period.of(1, YEARS);
+        assertSame(test.minus(1, YEARS), Period.ZERO);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_minusYears_overflowTooBig() {
+        Period test = Period.of(Integer.MAX_VALUE, YEARS);
+        test.minus(-1, YEARS);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_minusYears_overflowTooSmall() {
+        Period test = Period.of(Integer.MIN_VALUE, YEARS);
+        test.minus(1, YEARS);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusMonths()
+    //-----------------------------------------------------------------------
+    public void test_minusMonths() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertPeriod(test.minus(10, MONTHS), 1, -8, 3, 4, 5, 6, 7);
+    }
+
+    public void test_minusMonths_noChange() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertSame(test.minus(0, MONTHS), test);
+    }
+
+    public void test_minusMonths_toZero() {
+        Period test = Period.of(1, MONTHS);
+        assertSame(test.minus(1, MONTHS), Period.ZERO);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_minusMonths_overflowTooBig() {
+        Period test = Period.of(Integer.MAX_VALUE, MONTHS);
+        test.minus(-1, MONTHS);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_minusMonths_overflowTooSmall() {
+        Period test = Period.of(Integer.MIN_VALUE, MONTHS);
+        test.minus(1, MONTHS);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusDays()
+    //-----------------------------------------------------------------------
+    public void test_minusDays() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertPeriod(test.minus(10, DAYS), 1, 2, -7, 4, 5, 6, 7);
+    }
+
+    public void test_minusDays_noChange() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertSame(test.minus(0, DAYS), test);
+    }
+
+    public void test_minusDays_toZero() {
+        Period test = Period.of(1, DAYS);
+        assertSame(test.minus(1, DAYS), Period.ZERO);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_minusDays_overflowTooBig() {
+        Period test = Period.of(Integer.MAX_VALUE, DAYS);
+        test.minus(-1, DAYS);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_minusDays_overflowTooSmall() {
+        Period test = Period.of(Integer.MIN_VALUE, DAYS);
+        test.minus(1, DAYS);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusHours()
+    //-----------------------------------------------------------------------
+    public void test_minusHours() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertPeriod(test.minus(10, HOURS), 1, 2, 3, -5, -54, -53, -999999993);
+        assertEquals(test.minus(10, HOURS).plus(10, HOURS), test);
+    }
+
+    public void test_minusHours_noChange() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertSame(test.minus(0, HOURS), test);
+    }
+
+    public void test_minusHours_toZero() {
+        Period test = Period.of(1, HOURS);
+        assertSame(test.minus(1, HOURS), Period.ZERO);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_minusHours_overflowTooBig() {
+        Period test = Period.of(Integer.MAX_VALUE, HOURS);
+        test.minus(-1, HOURS);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_minusHours_overflowTooSmall() {
+        Period test = Period.of(Integer.MIN_VALUE, HOURS);
+        test.minus(1, HOURS);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusMinutes()
+    //-----------------------------------------------------------------------
+    public void test_minusMinutes() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertPeriod(test.minus(10, MINUTES), 1, 2, 3, 3, 55, 6, 7);
+        assertEquals(test.minus(10, MINUTES).plus(10, MINUTES), test);
+    }
+
+    public void test_minusMinutes_noChange() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertSame(test.minus(0, MINUTES), test);
+    }
+
+    public void test_minusMinutes_toZero() {
+        Period test = Period.of(1, MINUTES);
+        assertSame(test.minus(1, MINUTES), Period.ZERO);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusSeconds()
+    //-----------------------------------------------------------------------
+    public void test_minusSeconds() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertPeriod(test.minus(10, SECONDS), 1, 2, 3, 4, 4, 56, 7);
+        assertEquals(test.minus(10, SECONDS).plus(10, SECONDS), test);
+    }
+
+    public void test_minusSeconds_noChange() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertSame(test.minus(0, SECONDS), test);
+    }
+
+    public void test_minusSeconds_toZero() {
+        Period test = Period.of(1, SECONDS);
+        assertSame(test.minus(1, SECONDS), Period.ZERO);
+    }
+
+    //-----------------------------------------------------------------------
+    // minusNanos()
+    //-----------------------------------------------------------------------
+    public void test_minusNanos() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertPeriod(test.minus(10, NANOS), 1, 2, 3, 4, 5, 5, 999999997);
+    }
+
+    public void test_minusNanos_noChange() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertSame(test.minus(0, NANOS), test);
+    }
+
+    public void test_minusNanos_toZero() {
+        Period test = Period.of(1, NANOS);
+        assertSame(test.minus(1, NANOS), Period.ZERO);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_minusNanos_overflowTooBig() {
+        Period test = Period.of(Long.MAX_VALUE, NANOS);
+        test.minus(-1, NANOS);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_minusNanos_overflowTooSmall() {
+        Period test = Period.of(Long.MIN_VALUE, NANOS);
+        test.minus(1, NANOS);
+    }
+
+    //-----------------------------------------------------------------------
+    // multipliedBy()
+    //-----------------------------------------------------------------------
+    public void test_multipliedBy() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertPeriod(test.multipliedBy(2), 2, 4, 6, 8, 10, 12, 14);
+        assertPeriod(test.multipliedBy(-3), -3, -6, -9, -12, -15, -18, -21);
+    }
+
+    public void test_multipliedBy_zeroBase() {
+        assertSame(Period.ZERO.multipliedBy(2), Period.ZERO);
+    }
+
+    public void test_multipliedBy_zero() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertSame(test.multipliedBy(0), Period.ZERO);
+    }
+
+    public void test_multipliedBy_one() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertSame(test.multipliedBy(1), test);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_multipliedBy_overflowTooBig() {
+        Period test = Period.of(Integer.MAX_VALUE / 2 + 1, YEARS);
+        test.multipliedBy(2);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_multipliedBy_overflowTooSmall() {
+        Period test = Period.of(Integer.MIN_VALUE / 2 - 1, YEARS);
+        test.multipliedBy(2);
+    }
+
+    //-----------------------------------------------------------------------
+    // negated()
+    //-----------------------------------------------------------------------
+    public void test_negated() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6, 7);
+        assertPeriod(test.negated(), -1, -2, -3, -4, -5, -6, -7);
+    }
+
+    public void test_negated_zero() {
+        assertSame(Period.ZERO.negated(), Period.ZERO);
+    }
+
+    public void test_negated_max() {
+        assertPeriod(Period.of(Integer.MAX_VALUE, YEARS).negated(), -Integer.MAX_VALUE, 0, 0, 0, 0, 0, 0);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_negated_overflow() {
+        Period.of(Integer.MIN_VALUE, YEARS).negated();
+    }
+
+    //-----------------------------------------------------------------------
+    // normalizedHoursToDays()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="normalizedHoursToDays")
+    Object[][] data_normalizedHoursToDays() {
+        return new Object[][] {
+            {0, 0,  0, 0},
+            {1, 0,  1, 0},
+            {-1, 0,  -1, 0},
+
+            {1, 1,  1, 1},
+            {1, 23,  1, 23},
+            {1, 24,  2, 0},
+            {1, 25,  2, 1},
+
+            {1, -1,  0, 23},
+            {1, -23,  0, 1},
+            {1, -24,  0, 0},
+            {1, -25,  0, -1},
+            {1, -47,  0, -23},
+            {1, -48,  -1, 0},
+            {1, -49,  -1, -1},
+
+            {-1, 1,  0, -23},
+            {-1, 23,  0, -1},
+            {-1, 24,  0, 0},
+            {-1, 25,  0, 1},
+            {-1, 47,  0, 23},
+            {-1, 48,  1, 0},
+            {-1, 49,  1, 1},
+
+            {-1, -1,  -1, -1},
+            {-1, -23,  -1, -23},
+            {-1, -24,  -2, 0},
+            {-1, -25,  -2, -1},
+        };
+    }
+
+    @Test(dataProvider="normalizedHoursToDays")
+    public void test_normalizedHoursToDays(int inputDays, int inputHours, int expectedDays, int expectedHours) {
+        assertPeriod(Period.of(0, 0, inputDays, inputHours, 0, 0, 0).normalizedHoursToDays(), 0, 0, expectedDays, expectedHours, 0, 0, 0);
+    }
+
+    @Test(dataProvider="normalizedHoursToDays")
+    public void test_normalizedHoursToDays_yearsMonthsUnaffected(int inputDays, int inputHours, int expectedDays, int expectedHours) {
+        assertPeriod(Period.of(12, 6, inputDays, inputHours, 0, 0, 0).normalizedHoursToDays(), 12, 6, expectedDays, expectedHours, 0, 0, 0);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_normalizedHoursToDays_min() {
+        Period base = Period.of(0, 0, Integer.MIN_VALUE, -24, 0, 0, 0);
+        base.normalizedHoursToDays();
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_normalizedHoursToDays_max() {
+        Period base = Period.of(0, 0, Integer.MAX_VALUE, 24, 0, 0, 0);
+        base.normalizedHoursToDays();
+    }
+
+    //-----------------------------------------------------------------------
+    // normalizedDaysToHours()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="normalizedDaysToHours")
+    Object[][] data_normalizedDaysToHours() {
+        return new Object[][] {
+            {0, 0, 0,  0, 0},
+
+            {1, 0, 0,  24, 0},
+            {1, 1, 0,  25, 0},
+            {1, 23, 0,  47, 0},
+            {1, 24, 0,  48, 0},
+            {1, 25, 0,  49, 0},
+            {2, 23, 0,  71, 0},
+            {2, 24, 0,  72, 0},
+            {2, 25, 0,  73, 0},
+
+            {1, 0, 0,  24, 0},
+            {1, -1, 0,  23, 0},
+            {1, -23, 0,  1, 0},
+            {1, -24, 0,  0, 0},
+            {1, -25, 0,  -1, 0},
+            {2, -23, 0,  25, 0},
+            {2, -24, 0,  24, 0},
+            {2, -25, 0,  23, 0},
+
+            {-1, 0, 0,  -24, 0},
+            {-1, 1, 0,  -23, 0},
+            {-1, 23, 0,  -1, 0},
+            {-1, 24, 0,  0, 0},
+            {-1, 25, 0,  1, 0},
+            {-2, 23, 0,  -25, 0},
+            {-2, 24, 0,  -24, 0},
+            {-2, 25, 0,  -23, 0},
+
+            {-1, 0, 0,  -24, 0},
+            {-1, -1, 0,  -25, 0},
+            {-1, -23, 0,  -47, 0},
+            {-1, -24, 0,  -48, 0},
+            {-1, -25, 0,  -49, 0},
+
+            // minutes
+            {1, -1, -1,  22, 59},
+            {1, -23, -1,  0, 59},
+            {1, -24, -1,  0, -1},
+            {1, -25, -1,  -1, -1},
+            {-1, 1, 1,  -22, -59},
+            {-1, 23, 1,  0, -59},
+            {-1, 24, 1,  0, 1},
+            {-1, 25, 1,  1, 1},
+        };
+    }
+
+    @Test(dataProvider="normalizedDaysToHours")
+    public void test_normalizedDaysToHours(int inputDays, int inputHours, int inputMinutes, int expectedHours, int expectedMinutes) {
+        assertPeriod(Period.of(0, 0, inputDays, inputHours, inputMinutes, 0).normalizedDaysToHours(), 0, 0, 0, expectedHours, expectedMinutes, 0, 0);
+    }
+
+    @Test(dataProvider="normalizedDaysToHours")
+    public void test_normalizedDaysToHours_yearsMonthsUnaffected(int inputDays, int inputHours, int inputMinutes, int expectedHours, int expectedMinutes) {
+        assertPeriod(Period.of(12, 6, inputDays, inputHours, inputMinutes, 0).normalizedDaysToHours(), 12, 6, 0, expectedHours, expectedMinutes, 0, 0);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_normalizedDaysToHours_min() {
+        Period base = Period.of(0, 0, -1_000, -10_000_000, 0, 0, 0);
+        base.normalizedDaysToHours();
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_normalizedDaysToHours_max() {
+        Period base = Period.of(0, 0, 1_000, 10_000_000, 0, 0, 0);
+        base.normalizedDaysToHours();
+    }
+
+    //-----------------------------------------------------------------------
+    // normalizedMonthsISO()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="normalizedMonthsISO")
+    Object[][] data_normalizedMonthsISO() {
+        return new Object[][] {
+            {0, 0,  0, 0},
+            {1, 0,  1, 0},
+            {-1, 0,  -1, 0},
+
+            {1, 1,  1, 1},
+            {1, 2,  1, 2},
+            {1, 11,  1, 11},
+            {1, 12,  2, 0},
+            {1, 13,  2, 1},
+            {1, 23,  2, 11},
+            {1, 24,  3, 0},
+            {1, 25,  3, 1},
+
+            {1, -1,  0, 11},
+            {1, -2,  0, 10},
+            {1, -11,  0, 1},
+            {1, -12,  0, 0},
+            {1, -13,  0, -1},
+            {1, -23,  0, -11},
+            {1, -24,  -1, 0},
+            {1, -25,  -1, -1},
+            {1, -35,  -1, -11},
+            {1, -36,  -2, 0},
+            {1, -37,  -2, -1},
+
+            {-1, 1,  0, -11},
+            {-1, 11,  0, -1},
+            {-1, 12,  0, 0},
+            {-1, 13,  0, 1},
+            {-1, 23,  0, 11},
+            {-1, 24,  1, 0},
+            {-1, 25,  1, 1},
+
+            {-1, -1,  -1, -1},
+            {-1, -11,  -1, -11},
+            {-1, -12,  -2, 0},
+            {-1, -13,  -2, -1},
+        };
+    }
+
+    @Test(dataProvider="normalizedMonthsISO")
+    public void test_normalizedMonthsISO(int inputYears, int inputMonths, int expectedYears, int expectedMonths) {
+        assertPeriod(Period.ofDate(inputYears, inputMonths, 0).normalizedMonthsISO(), expectedYears, expectedMonths, 0, 0, 0, 0, 0);
+    }
+
+    @Test(dataProvider="normalizedMonthsISO")
+    public void test_normalizedMonthsISO_daysTimeUnaffected(int inputYears, int inputMonths, int expectedYears, int expectedMonths) {
+        assertPeriod(Period.of(inputYears, inputMonths, 5, 12, 30, 0, 0).normalizedMonthsISO(), expectedYears, expectedMonths, 5, 12, 30, 0, 0);
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_normalizedMonthsISO_min() {
+        Period base = Period.ofDate(Integer.MIN_VALUE, -12, 0);
+        base.normalizedMonthsISO();
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_normalizedMonthsISO_max() {
+        Period base = Period.ofDate(Integer.MAX_VALUE, 12, 0);
+        base.normalizedMonthsISO();
+    }
+
+    //-----------------------------------------------------------------------
+    // addTo()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="addTo")
+    Object[][] data_addTo() {
+        return new Object[][] {
+            {pymd(0, 0, 0),  date(2012, 6, 30), date(2012, 6, 30)},
+
+            {pymd(1, 0, 0),  date(2012, 6, 10), date(2013, 6, 10)},
+            {pymd(0, 1, 0),  date(2012, 6, 10), date(2012, 7, 10)},
+            {pymd(0, 0, 1),  date(2012, 6, 10), date(2012, 6, 11)},
+
+            {pymd(-1, 0, 0),  date(2012, 6, 10), date(2011, 6, 10)},
+            {pymd(0, -1, 0),  date(2012, 6, 10), date(2012, 5, 10)},
+            {pymd(0, 0, -1),  date(2012, 6, 10), date(2012, 6, 9)},
+
+            {pymd(1, 2, 3),  date(2012, 6, 27), date(2013, 8, 30)},
+            {pymd(1, 2, 3),  date(2012, 6, 28), date(2013, 8, 31)},
+            {pymd(1, 2, 3),  date(2012, 6, 29), date(2013, 9, 1)},
+            {pymd(1, 2, 3),  date(2012, 6, 30), date(2013, 9, 2)},
+            {pymd(1, 2, 3),  date(2012, 7, 1), date(2013, 9, 4)},
+
+            {pymd(1, 0, 0),  date(2011, 2, 28), date(2012, 2, 28)},
+            {pymd(4, 0, 0),  date(2011, 2, 28), date(2015, 2, 28)},
+            {pymd(1, 0, 0),  date(2012, 2, 29), date(2013, 2, 28)},
+            {pymd(4, 0, 0),  date(2012, 2, 29), date(2016, 2, 29)},
+
+            {pymd(1, 1, 0),  date(2011, 1, 29), date(2012, 2, 29)},
+            {pymd(1, 2, 0),  date(2012, 2, 29), date(2013, 4, 29)},
+        };
+    }
+
+    @Test(dataProvider="addTo")
+    public void test_addTo(Period period, LocalDate baseDate, LocalDate expected) {
+        assertEquals(period.addTo(baseDate), expected);
+    }
+
+    @Test(dataProvider="addTo")
+    public void test_addTo_usingLocalDatePlus(Period period, LocalDate baseDate, LocalDate expected) {
+        assertEquals(baseDate.plus(period), expected);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_addTo_nullZero() {
+        Period.ZERO.addTo(null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_addTo_nullNonZero() {
+        Period.of(2, DAYS).addTo(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // subtractFrom()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="subtractFrom")
+    Object[][] data_subtractFrom() {
+        return new Object[][] {
+            {pymd(0, 0, 0),  date(2012, 6, 30), date(2012, 6, 30)},
+
+            {pymd(1, 0, 0),  date(2012, 6, 10), date(2011, 6, 10)},
+            {pymd(0, 1, 0),  date(2012, 6, 10), date(2012, 5, 10)},
+            {pymd(0, 0, 1),  date(2012, 6, 10), date(2012, 6, 9)},
+
+            {pymd(-1, 0, 0),  date(2012, 6, 10), date(2013, 6, 10)},
+            {pymd(0, -1, 0),  date(2012, 6, 10), date(2012, 7, 10)},
+            {pymd(0, 0, -1),  date(2012, 6, 10), date(2012, 6, 11)},
+
+            {pymd(1, 2, 3),  date(2012, 8, 30), date(2011, 6, 27)},
+            {pymd(1, 2, 3),  date(2012, 8, 31), date(2011, 6, 27)},
+            {pymd(1, 2, 3),  date(2012, 9, 1), date(2011, 6, 28)},
+            {pymd(1, 2, 3),  date(2012, 9, 2), date(2011, 6, 29)},
+            {pymd(1, 2, 3),  date(2012, 9, 3), date(2011, 6, 30)},
+            {pymd(1, 2, 3),  date(2012, 9, 4), date(2011, 7, 1)},
+
+            {pymd(1, 0, 0),  date(2011, 2, 28), date(2010, 2, 28)},
+            {pymd(4, 0, 0),  date(2011, 2, 28), date(2007, 2, 28)},
+            {pymd(1, 0, 0),  date(2012, 2, 29), date(2011, 2, 28)},
+            {pymd(4, 0, 0),  date(2012, 2, 29), date(2008, 2, 29)},
+
+            {pymd(1, 1, 0),  date(2013, 3, 29), date(2012, 2, 29)},
+            {pymd(1, 2, 0),  date(2012, 2, 29), date(2010, 12, 29)},
+        };
+    }
+
+    @Test(dataProvider="subtractFrom")
+    public void test_subtractFrom(Period period, LocalDate baseDate, LocalDate expected) {
+        assertEquals(period.subtractFrom(baseDate), expected);
+    }
+
+    @Test(dataProvider="subtractFrom")
+    public void test_subtractFrom_usingLocalDateMinus(Period period, LocalDate baseDate, LocalDate expected) {
+        assertEquals(baseDate.minus(period), expected);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_subtractFrom_nullZero() {
+        Period.ZERO.subtractFrom(null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_subtractFrom_nullNonZero() {
+        Period.of(2, DAYS).subtractFrom(null);
+    }
+
+    //-----------------------------------------------------------------------
+    // toDuration()
+    //-----------------------------------------------------------------------
+    public void test_toDuration() {
+        assertEquals(Period.ZERO.toDuration(), Duration.of(0, SECONDS));
+        assertEquals(Period.of(0, 0, 0, 4, 5, 6, 7).toDuration(), Duration.ofSeconds((4 * 60 + 5) * 60L + 6, 7));
+    }
+
+    public void test_toDuration_calculation() {
+        assertEquals(Period.of(0, 0, 0, 2, 0, 0, 0).toDuration(), Duration.ofSeconds(2 * 3600));
+        assertEquals(Period.of(0, 0, 0, 0, 2, 0, 0).toDuration(), Duration.of(120, SECONDS));
+        assertEquals(Period.of(0, 0, 0, 0, 0, 2, 0).toDuration(), Duration.of(2, SECONDS));
+
+        assertEquals(Period.of(0, 0, 0, 0, 0, 3, 1000000000L - 1).toDuration(), Duration.ofSeconds(3, 999999999));
+        assertEquals(Period.of(0, 0, 0, 0, 0, 3, 1000000000L).toDuration(), Duration.ofSeconds(4, 0));
+    }
+
+    public void test_toDuration_negatives() {
+        assertEquals(Period.of(0, 0, 0, 0, 0, 2, 1).toDuration(), Duration.ofSeconds(2, 1));
+        assertEquals(Period.of(0, 0, 0, 0, 0, 2, -1).toDuration(), Duration.ofSeconds(1, 999999999));
+        assertEquals(Period.of(0, 0, 0, 0, 0, -2, 1).toDuration(), Duration.ofSeconds(-2, 1));
+        assertEquals(Period.of(0, 0, 0, 0, 0, -2, -1).toDuration(), Duration.ofSeconds(-3, 999999999));
+    }
+
+    @Test(expectedExceptions=DateTimeException.class)
+    public void test_toDuration_years() {
+        Period.of(1, 0, 0, 4, 5, 6, 7).toDuration();
+    }
+
+    @Test(expectedExceptions=DateTimeException.class)
+    public void test_toDuration_months() {
+        Period.of(0, 1, 0, 4, 5, 6, 7).toDuration();
+    }
+
+    @Test(expectedExceptions=DateTimeException.class)
+    public void test_toDuration_days() {
+        Duration test = Period.of(0, 0, 1, 4, 5, 6, 7).toDuration();
+        assertEquals(test, Duration.ofSeconds(101106, 7L));
+    }
+
+    //-----------------------------------------------------------------------
+    // equals() / hashCode()
+    //-----------------------------------------------------------------------
+    public void test_equals() {
+        assertEquals(Period.of(1, 0, 0, 0, 0, 0).equals(Period.of(1, YEARS)), true);
+        assertEquals(Period.of(0, 1, 0, 0, 0, 0).equals(Period.of(1, MONTHS)), true);
+        assertEquals(Period.of(0, 0, 1, 0, 0, 0).equals(Period.of(1, DAYS)), true);
+        assertEquals(Period.of(0, 0, 0, 1, 0, 0).equals(Period.of(1, HOURS)), true);
+        assertEquals(Period.of(0, 0, 0, 0, 1, 0).equals(Period.of(1, MINUTES)), true);
+        assertEquals(Period.of(0, 0, 0, 0, 0, 1).equals(Period.of(1, SECONDS)), true);
+        assertEquals(Period.of(1, 2, 3, 0, 0, 0).equals(Period.ofDate(1, 2, 3)), true);
+        assertEquals(Period.of(0, 0, 0, 1, 2, 3).equals(Period.ofTime(1, 2, 3)), true);
+        assertEquals(Period.of(1, 2, 3, 4, 5, 6).equals(Period.of(1, 2, 3, 4, 5, 6)), true);
+
+        assertEquals(Period.of(1, YEARS).equals(Period.of(1, YEARS)), true);
+        assertEquals(Period.of(1, YEARS).equals(Period.of(2, YEARS)), false);
+
+        assertEquals(Period.of(1, MONTHS).equals(Period.of(1, MONTHS)), true);
+        assertEquals(Period.of(1, MONTHS).equals(Period.of(2, MONTHS)), false);
+
+        assertEquals(Period.of(1, DAYS).equals(Period.of(1, DAYS)), true);
+        assertEquals(Period.of(1, DAYS).equals(Period.of(2, DAYS)), false);
+
+        assertEquals(Period.of(1, HOURS).equals(Period.of(1, HOURS)), true);
+        assertEquals(Period.of(1, HOURS).equals(Period.of(2, HOURS)), false);
+
+        assertEquals(Period.of(1, MINUTES).equals(Period.of(1, MINUTES)), true);
+        assertEquals(Period.of(1, MINUTES).equals(Period.of(2, MINUTES)), false);
+
+        assertEquals(Period.of(1, SECONDS).equals(Period.of(1, SECONDS)), true);
+        assertEquals(Period.of(1, SECONDS).equals(Period.of(2, SECONDS)), false);
+
+        assertEquals(Period.ofDate(1, 2, 3).equals(Period.ofDate(1, 2, 3)), true);
+        assertEquals(Period.ofDate(1, 2, 3).equals(Period.ofDate(0, 2, 3)), false);
+        assertEquals(Period.ofDate(1, 2, 3).equals(Period.ofDate(1, 0, 3)), false);
+        assertEquals(Period.ofDate(1, 2, 3).equals(Period.ofDate(1, 2, 0)), false);
+
+        assertEquals(Period.ofTime(1, 2, 3).equals(Period.ofTime(1, 2, 3)), true);
+        assertEquals(Period.ofTime(1, 2, 3).equals(Period.ofTime(0, 2, 3)), false);
+        assertEquals(Period.ofTime(1, 2, 3).equals(Period.ofTime(1, 0, 3)), false);
+        assertEquals(Period.ofTime(1, 2, 3).equals(Period.ofTime(1, 2, 0)), false);
+    }
+
+    public void test_equals_self() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6);
+        assertEquals(test.equals(test), true);
+    }
+
+    public void test_equals_null() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6);
+        assertEquals(test.equals(null), false);
+    }
+
+    public void test_equals_otherClass() {
+        Period test = Period.of(1, 2, 3, 4, 5, 6);
+        assertEquals(test.equals(""), false);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_hashCode() {
+        Period test5 = Period.of(5, DAYS);
+        Period test6 = Period.of(6, DAYS);
+        Period test5M = Period.of(5, MONTHS);
+        Period test5Y = Period.of(5, YEARS);
+        assertEquals(test5.hashCode() == test5.hashCode(), true);
+        assertEquals(test5.hashCode() == test6.hashCode(), false);
+        assertEquals(test5.hashCode() == test5M.hashCode(), false);
+        assertEquals(test5.hashCode() == test5Y.hashCode(), false);
+    }
+
+    //-----------------------------------------------------------------------
+    // toString()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="toStringAndParse")
+    Object[][] data_toString() {
+        return new Object[][] {
+            {Period.ZERO, "PT0S"},
+            {Period.of(0, DAYS), "PT0S"},
+            {Period.of(1, YEARS), "P1Y"},
+            {Period.of(1, MONTHS), "P1M"},
+            {Period.of(1, DAYS), "P1D"},
+            {Period.of(1, HOURS), "PT1H"},
+            {Period.of(1, MINUTES), "PT1M"},
+            {Period.of(1, SECONDS), "PT1S"},
+            {Period.of(12, SECONDS), "PT12S"},
+            {Period.of(123, SECONDS), "PT2M3S"},
+            {Period.of(1234, SECONDS), "PT20M34S"},
+            {Period.of(-1, SECONDS), "PT-1S"},
+            {Period.of(-12, SECONDS), "PT-12S"},
+            {Period.of(-123, SECONDS), "PT-2M-3S"},
+            {Period.of(-1234, SECONDS), "PT-20M-34S"},
+            {Period.of(1, 2, 3, 4, 5, 6), "P1Y2M3DT4H5M6S"},
+            {Period.of(1, 2, 3, 4, 5, 6, 700000000), "P1Y2M3DT4H5M6.7S"},
+            {Period.of(0, 0, 0, 0, 0, 0, 100000000), "PT0.1S"},
+            {Period.of(0, 0, 0, 0, 0, 0, -100000000), "PT-0.1S"},
+            {Period.of(0, 0, 0, 0, 0, 1, -900000000), "PT0.1S"},
+            {Period.of(0, 0, 0, 0, 0, -1, 900000000), "PT-0.1S"},
+            {Period.of(0, 0, 0, 0, 0, 1, 100000000), "PT1.1S"},
+            {Period.of(0, 0, 0, 0, 0, 1, -100000000), "PT0.9S"},
+            {Period.of(0, 0, 0, 0, 0, -1, 100000000), "PT-0.9S"},
+            {Period.of(0, 0, 0, 0, 0, -1, -100000000), "PT-1.1S"},
+            {Period.of(0, 0, 0, 0, 0, 0, 10000000), "PT0.01S"},
+            {Period.of(0, 0, 0, 0, 0, 0, -10000000), "PT-0.01S"},
+            {Period.of(0, 0, 0, 0, 0, 0, 1000000), "PT0.001S"},
+            {Period.of(0, 0, 0, 0, 0, 0, -1000000), "PT-0.001S"},
+            {Period.of(0, 0, 0, 0, 0, 0, 1000), "PT0.000001S"},
+            {Period.of(0, 0, 0, 0, 0, 0, -1000), "PT-0.000001S"},
+            {Period.of(0, 0, 0, 0, 0, 0, 1), "PT0.000000001S"},
+            {Period.of(0, 0, 0, 0, 0, 0, -1), "PT-0.000000001S"},
+        };
+    }
+
+    @Test(groups="tck", dataProvider="toStringAndParse")
+    public void test_toString(Period input, String expected) {
+        assertEquals(input.toString(), expected);
+    }
+
+    //-----------------------------------------------------------------------
+    private void assertPeriod(Period test, int y, int mo, int d, int h, int mn, int s, long n) {
+        assertEquals(test.getYears(), y, "years");
+        assertEquals(test.getMonths(), mo, "months");
+        assertEquals(test.getDays(), d, "days");
+        assertEquals(test.getHours(), h, "hours");
+        assertEquals(test.getMinutes(), mn, "mins");
+        assertEquals(test.getSeconds(), s, "secs");
+        assertEquals(test.getNanos(), n, "nanos");
+        assertEquals(test.getTimeNanos(), (((h * 60L + mn) * 60 + s) * 1_000_000_000L + n), "total nanos");
+    }
+
+    private static Period pymd(int y, int m, int d) {
+        return Period.ofDate(y, m, d);
+    }
+
+    private static LocalDate date(int y, int m, int d) {
+        return LocalDate.of(y, m, d);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/TestPeriodParser.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time;
+
+import java.time.*;
+
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.HOURS;
+import static java.time.temporal.ChronoUnit.MINUTES;
+import static java.time.temporal.ChronoUnit.MONTHS;
+import static java.time.temporal.ChronoUnit.NANOS;
+import static java.time.temporal.ChronoUnit.SECONDS;
+import static java.time.temporal.ChronoUnit.YEARS;
+import static org.testng.Assert.assertEquals;
+
+import java.time.format.DateTimeParseException;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test PeriodParser.
+ */
+@Test
+public class TestPeriodParser {
+
+    //-----------------------------------------------------------------------
+    // parse(String)
+    //-----------------------------------------------------------------------
+    @DataProvider(name="Parse")
+    Object[][] provider_factory_parse() {
+        return new Object[][] {
+            {"Pt0S", Period.ZERO},
+            {"pT0S", Period.ZERO},
+            {"PT0S", Period.ZERO},
+            {"Pt0s", Period.ZERO},
+            {"pt0s", Period.ZERO},
+            {"P0Y0M0DT0H0M0.0S", Period.ZERO},
+
+            {"P1Y", Period.of(1, YEARS)},
+            {"P100Y", Period.of(100, YEARS)},
+            {"P-25Y", Period.of(-25, YEARS)},
+            {"P" + Integer.MAX_VALUE + "Y", Period.of(Integer.MAX_VALUE, YEARS)},
+            {"P" + Integer.MIN_VALUE + "Y", Period.of(Integer.MIN_VALUE, YEARS)},
+
+            {"P1M", Period.of(1, MONTHS)},
+            {"P0M", Period.of(0, MONTHS)},
+            {"P-1M", Period.of(-1, MONTHS)},
+            {"P" + Integer.MAX_VALUE + "M", Period.of(Integer.MAX_VALUE, MONTHS)},
+            {"P" + Integer.MIN_VALUE + "M", Period.of(Integer.MIN_VALUE, MONTHS)},
+
+            {"P1D", Period.of(1, DAYS)},
+            {"P0D", Period.of(0, DAYS)},
+            {"P-1D", Period.of(-1, DAYS)},
+            {"P" + Integer.MAX_VALUE + "D", Period.of(Integer.MAX_VALUE, DAYS)},
+            {"P" + Integer.MIN_VALUE + "D", Period.of(Integer.MIN_VALUE, DAYS)},
+
+            {"P2Y3M25D", Period.ofDate(2, 3, 25)},
+
+            {"PT1H", Period.of(1, HOURS)},
+            {"PT-1H", Period.of(-1, HOURS)},
+            {"PT24H", Period.of(24, HOURS)},
+            {"PT-24H", Period.of(-24, HOURS)},
+            {"PT" + Integer.MAX_VALUE / (3600 * 8) + "H", Period.of(Integer.MAX_VALUE / (3600 * 8), HOURS)},
+            {"PT" + Integer.MIN_VALUE / (3600 * 8) + "H", Period.of(Integer.MIN_VALUE / (3600 * 8), HOURS)},
+
+            {"PT1M", Period.of(1, MINUTES)},
+            {"PT-1M", Period.of(-1, MINUTES)},
+            {"PT60M", Period.of(60, MINUTES)},
+            {"PT-60M", Period.of(-60, MINUTES)},
+            {"PT" + Integer.MAX_VALUE / (60 * 8) + "M", Period.of(Integer.MAX_VALUE / (60 * 8), MINUTES)},
+            {"PT" + Integer.MIN_VALUE / (60 * 8) + "M", Period.of(Integer.MIN_VALUE / (60 * 8), MINUTES)},
+
+            {"PT1S", Period.of(1, SECONDS)},
+            {"PT-1S", Period.of(-1, SECONDS)},
+            {"PT60S", Period.of(60, SECONDS)},
+            {"PT-60S", Period.of(-60, SECONDS)},
+            {"PT" + Integer.MAX_VALUE + "S", Period.of(Integer.MAX_VALUE, SECONDS)},
+            {"PT" + Integer.MIN_VALUE + "S", Period.of(Integer.MIN_VALUE, SECONDS)},
+
+            {"PT0.1S", Period.of( 0, 0, 0, 0, 0, 0, 100000000 ) },
+            {"PT-0.1S", Period.of( 0, 0, 0, 0, 0, 0, -100000000 ) },
+            {"PT1.1S", Period.of( 0, 0, 0, 0, 0, 1, 100000000 ) },
+            {"PT-1.1S", Period.of( 0, 0, 0, 0, 0, -1, -100000000 ) },
+            {"PT1.0001S", Period.of(1, SECONDS).plus( 100000, NANOS ) },
+            {"PT1.0000001S", Period.of(1, SECONDS).plus( 100, NANOS ) },
+            {"PT1.123456789S", Period.of( 0, 0, 0, 0, 0, 1, 123456789 ) },
+            {"PT1.999999999S", Period.of( 0, 0, 0, 0, 0, 1, 999999999 ) },
+
+        };
+    }
+
+    @Test(dataProvider="Parse")
+    public void factory_parse(String text, Period expected) {
+        Period p = Period.parse(text);
+        assertEquals(p, expected);
+    }
+
+    @Test(dataProvider="Parse")
+    public void factory_parse_comma(String text, Period expected) {
+        if (text.contains(".")) {
+            text = text.replace('.', ',');
+            Period p = Period.parse(text);
+            assertEquals(p, expected);
+        }
+    }
+
+    @DataProvider(name="ParseFailures")
+    Object[][] provider_factory_parseFailures() {
+        return new Object[][] {
+            {"", 0},
+            {"PTS", 2},
+            {"AT0S", 0},
+            {"PA0S", 1},
+            {"PT0A", 3},
+
+            {"PT+S", 2},
+            {"PT-S", 2},
+            {"PT.S", 2},
+            {"PTAS", 2},
+
+            {"PT+0S", 2},
+            {"PT-0S", 2},
+            {"PT+1S", 2},
+            {"PT-.S", 2},
+
+            {"PT1ABC2S", 3},
+            {"PT1.1ABC2S", 5},
+
+            {"PT123456789123456789123456789S", 2},
+            {"PT0.1234567891S", 4},
+            {"PT1.S", 2},
+            {"PT.1S", 2},
+
+            {"PT2.-3S", 2},
+            {"PT-2.-3S", 2},
+
+            {"P1Y1MT1DT1M1S", 7},
+            {"P1Y1MT1HT1M1S", 8},
+            {"P1YMD", 3},
+            {"PT1ST1D", 4},
+            {"P1Y2Y", 4},
+            {"PT1M+3S", 4},
+
+            {"PT1S1", 4},
+            {"PT1S.", 4},
+            {"PT1SA", 4},
+            {"PT1M1", 4},
+            {"PT1M.", 4},
+            {"PT1MA", 4},
+        };
+    }
+
+    @Test(dataProvider="ParseFailures", expectedExceptions=DateTimeParseException.class)
+    public void factory_parseFailures(String text, int errPos) {
+        try {
+            Period.parse(text);
+        } catch (DateTimeParseException ex) {
+            assertEquals(ex.getParsedString(), text);
+            assertEquals(ex.getErrorIndex(), errPos);
+            throw ex;
+        }
+    }
+
+    @Test(dataProvider="ParseFailures", expectedExceptions=DateTimeParseException.class)
+    public void factory_parseFailures_comma(String text, int errPos) {
+        text = text.replace('.', ',');
+        try {
+            Period.parse(text);
+        } catch (DateTimeParseException ex) {
+            assertEquals(ex.getParsedString(), text);
+            assertEquals(ex.getErrorIndex(), errPos);
+            throw ex;
+        }
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class)
+    public void factory_parse_tooBig() {
+        String text = "PT" + Long.MAX_VALUE + "1S";
+        Period.parse(text);
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class)
+    public void factory_parse_tooBig_decimal() {
+        String text = "PT" + Long.MAX_VALUE + "1.1S";
+        Period.parse(text);
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class)
+    public void factory_parse_tooSmall() {
+        String text = "PT" + Long.MIN_VALUE + "1S";
+        Period.parse(text);
+    }
+
+    @Test(expectedExceptions=DateTimeParseException.class)
+    public void factory_parse_tooSmall_decimal() {
+        String text = "PT" + Long.MIN_VALUE + ".1S";
+        Period.parse(text);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void factory_parse_null() {
+        Period.parse(null);
+    }
+
+    @DataProvider(name="ParseSequenceFailures")
+    Object[][] provider_factory_parseSequenceFailures() {
+        return new Object[][] {
+            {"P0M0Y0DT0H0M0.0S"},
+            {"P0M0D0YT0H0M0.0S"},
+            {"P0S0D0YT0S0M0.0H"},
+            {"PT0M0H0.0S"},
+            {"PT0M0H"},
+            {"PT0S0M"},
+            {"PT0.0M2S"},
+        };
+    }
+
+    @Test(dataProvider="ParseSequenceFailures", expectedExceptions=DateTimeParseException.class)
+    public void factory_parse_badSequence(String text) {
+        Period.parse(text);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/TestZoneId.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,1084 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time;
+
+import java.time.*;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.SimpleTimeZone;
+import java.util.TimeZone;
+
+import java.time.temporal.Queries;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalField;
+import java.time.format.TextStyle;
+import java.time.zone.ZoneOffsetTransition;
+import java.time.zone.ZoneRules;
+import java.time.zone.ZoneRulesException;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test ZoneId.
+ */
+@Test
+public class TestZoneId extends AbstractTest {
+
+    private static final ZoneId ZONE_PARIS = ZoneId.of("Europe/Paris");
+    public static final String LATEST_TZDB = "2010i";
+    private static final int OVERLAP = 2;
+    private static final int GAP = 0;
+
+    //-----------------------------------------------------------------------
+    // Basics
+    //-----------------------------------------------------------------------
+    public void test_immutable() {
+        Class<ZoneId> cls = ZoneId.class;
+        assertTrue(Modifier.isPublic(cls.getModifiers()));
+        Field[] fields = cls.getDeclaredFields();
+        for (Field field : fields) {
+            if (Modifier.isStatic(field.getModifiers()) == false) {
+                assertTrue(Modifier.isPrivate(field.getModifiers()));
+                assertTrue(Modifier.isFinal(field.getModifiers()) ||
+                        (Modifier.isVolatile(field.getModifiers()) && Modifier.isTransient(field.getModifiers())));
+            }
+        }
+    }
+
+    public void test_serialization_UTC() throws Exception {
+        ZoneId test = ZoneOffset.UTC;
+        assertSerializableAndSame(test);
+    }
+
+    public void test_serialization_fixed() throws Exception {
+        ZoneId test = ZoneId.of("UTC+01:30");
+        assertSerializable(test);
+    }
+
+    public void test_serialization_Europe() throws Exception {
+        ZoneId test = ZoneId.of("Europe/London");
+        assertSerializable(test);
+    }
+
+    public void test_serialization_America() throws Exception {
+        ZoneId test = ZoneId.of("America/Chicago");
+        assertSerializable(test);
+    }
+
+    //-----------------------------------------------------------------------
+    // UTC
+    //-----------------------------------------------------------------------
+    public void test_constant_UTC() {
+        ZoneId test = ZoneOffset.UTC;
+        assertEquals(test.getId(), "Z");
+        assertEquals(test.getText(TextStyle.FULL, Locale.UK), "Z");
+        assertEquals(test.getRules().isFixedOffset(), true);
+        assertEquals(test.getRules().getOffset(Instant.ofEpochSecond(0L)), ZoneOffset.UTC);
+        checkOffset(test.getRules(), createLDT(2008, 6, 30), ZoneOffset.UTC, 1);
+        assertSame(test, ZoneId.of("UTC+00"));
+    }
+
+    //-----------------------------------------------------------------------
+    // OLD_IDS_PRE_2005
+    //-----------------------------------------------------------------------
+    public void test_constant_OLD_IDS_PRE_2005() {
+        Map<String, String> ids = ZoneId.OLD_IDS_PRE_2005;
+        assertEquals(ids.get("EST"), "America/Indianapolis");
+        assertEquals(ids.get("MST"), "America/Phoenix");
+        assertEquals(ids.get("HST"), "Pacific/Honolulu");
+        assertEquals(ids.get("ACT"), "Australia/Darwin");
+        assertEquals(ids.get("AET"), "Australia/Sydney");
+        assertEquals(ids.get("AGT"), "America/Argentina/Buenos_Aires");
+        assertEquals(ids.get("ART"), "Africa/Cairo");
+        assertEquals(ids.get("AST"), "America/Anchorage");
+        assertEquals(ids.get("BET"), "America/Sao_Paulo");
+        assertEquals(ids.get("BST"), "Asia/Dhaka");
+        assertEquals(ids.get("CAT"), "Africa/Harare");
+        assertEquals(ids.get("CNT"), "America/St_Johns");
+        assertEquals(ids.get("CST"), "America/Chicago");
+        assertEquals(ids.get("CTT"), "Asia/Shanghai");
+        assertEquals(ids.get("EAT"), "Africa/Addis_Ababa");
+        assertEquals(ids.get("ECT"), "Europe/Paris");
+        assertEquals(ids.get("IET"), "America/Indiana/Indianapolis");
+        assertEquals(ids.get("IST"), "Asia/Kolkata");
+        assertEquals(ids.get("JST"), "Asia/Tokyo");
+        assertEquals(ids.get("MIT"), "Pacific/Apia");
+        assertEquals(ids.get("NET"), "Asia/Yerevan");
+        assertEquals(ids.get("NST"), "Pacific/Auckland");
+        assertEquals(ids.get("PLT"), "Asia/Karachi");
+        assertEquals(ids.get("PNT"), "America/Phoenix");
+        assertEquals(ids.get("PRT"), "America/Puerto_Rico");
+        assertEquals(ids.get("PST"), "America/Los_Angeles");
+        assertEquals(ids.get("SST"), "Pacific/Guadalcanal");
+        assertEquals(ids.get("VST"), "Asia/Ho_Chi_Minh");
+    }
+
+    @Test(expectedExceptions=UnsupportedOperationException.class)
+    public void test_constant_OLD_IDS_PRE_2005_immutable() {
+        Map<String, String> ids = ZoneId.OLD_IDS_PRE_2005;
+        ids.clear();
+    }
+
+    //-----------------------------------------------------------------------
+    // OLD_IDS_POST_2005
+    //-----------------------------------------------------------------------
+    public void test_constant_OLD_IDS_POST_2005() {
+        Map<String, String> ids = ZoneId.OLD_IDS_POST_2005;
+        assertEquals(ids.get("EST"), "-05:00");
+        assertEquals(ids.get("MST"), "-07:00");
+        assertEquals(ids.get("HST"), "-10:00");
+        assertEquals(ids.get("ACT"), "Australia/Darwin");
+        assertEquals(ids.get("AET"), "Australia/Sydney");
+        assertEquals(ids.get("AGT"), "America/Argentina/Buenos_Aires");
+        assertEquals(ids.get("ART"), "Africa/Cairo");
+        assertEquals(ids.get("AST"), "America/Anchorage");
+        assertEquals(ids.get("BET"), "America/Sao_Paulo");
+        assertEquals(ids.get("BST"), "Asia/Dhaka");
+        assertEquals(ids.get("CAT"), "Africa/Harare");
+        assertEquals(ids.get("CNT"), "America/St_Johns");
+        assertEquals(ids.get("CST"), "America/Chicago");
+        assertEquals(ids.get("CTT"), "Asia/Shanghai");
+        assertEquals(ids.get("EAT"), "Africa/Addis_Ababa");
+        assertEquals(ids.get("ECT"), "Europe/Paris");
+        assertEquals(ids.get("IET"), "America/Indiana/Indianapolis");
+        assertEquals(ids.get("IST"), "Asia/Kolkata");
+        assertEquals(ids.get("JST"), "Asia/Tokyo");
+        assertEquals(ids.get("MIT"), "Pacific/Apia");
+        assertEquals(ids.get("NET"), "Asia/Yerevan");
+        assertEquals(ids.get("NST"), "Pacific/Auckland");
+        assertEquals(ids.get("PLT"), "Asia/Karachi");
+        assertEquals(ids.get("PNT"), "America/Phoenix");
+        assertEquals(ids.get("PRT"), "America/Puerto_Rico");
+        assertEquals(ids.get("PST"), "America/Los_Angeles");
+        assertEquals(ids.get("SST"), "Pacific/Guadalcanal");
+        assertEquals(ids.get("VST"), "Asia/Ho_Chi_Minh");
+    }
+
+    @Test(expectedExceptions=UnsupportedOperationException.class)
+    public void test_constant_OLD_IDS_POST_2005_immutable() {
+        Map<String, String> ids = ZoneId.OLD_IDS_POST_2005;
+        ids.clear();
+    }
+
+    //-----------------------------------------------------------------------
+    // system default
+    //-----------------------------------------------------------------------
+    public void test_systemDefault() {
+        ZoneId test = ZoneId.systemDefault();
+        assertEquals(test.getId(), TimeZone.getDefault().getID());
+    }
+
+    @Test(expectedExceptions = DateTimeException.class)
+    public void test_systemDefault_unableToConvert_badFormat() {
+        TimeZone current = TimeZone.getDefault();
+        try {
+            TimeZone.setDefault(new SimpleTimeZone(127, "Something Weird"));
+            ZoneId.systemDefault();
+        } finally {
+            TimeZone.setDefault(current);
+        }
+    }
+
+    @Test(expectedExceptions = ZoneRulesException.class)
+    public void test_systemDefault_unableToConvert_unknownId() {
+        TimeZone current = TimeZone.getDefault();
+        try {
+            TimeZone.setDefault(new SimpleTimeZone(127, "SomethingWeird"));
+            ZoneId.systemDefault();
+        } finally {
+            TimeZone.setDefault(current);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // mapped factory
+    //-----------------------------------------------------------------------
+    public void test_of_string_Map() {
+        Map<String, String> map = new HashMap<String, String>();
+        map.put("LONDON", "Europe/London");
+        map.put("PARIS", "Europe/Paris");
+        ZoneId test = ZoneId.of("LONDON", map);
+        assertEquals(test.getId(), "Europe/London");
+    }
+
+    public void test_of_string_Map_lookThrough() {
+        Map<String, String> map = new HashMap<String, String>();
+        map.put("LONDON", "Europe/London");
+        map.put("PARIS", "Europe/Paris");
+        ZoneId test = ZoneId.of("Europe/Madrid", map);
+        assertEquals(test.getId(), "Europe/Madrid");
+    }
+
+    public void test_of_string_Map_emptyMap() {
+        Map<String, String> map = new HashMap<String, String>();
+        ZoneId test = ZoneId.of("Europe/Madrid", map);
+        assertEquals(test.getId(), "Europe/Madrid");
+    }
+
+    @Test(expectedExceptions=DateTimeException.class)
+    public void test_of_string_Map_badFormat() {
+        Map<String, String> map = new HashMap<String, String>();
+        ZoneId.of("Not kknown", map);
+    }
+
+    @Test(expectedExceptions=ZoneRulesException.class)
+    public void test_of_string_Map_unknown() {
+        Map<String, String> map = new HashMap<String, String>();
+        ZoneId.of("Unknown", map);
+    }
+
+    //-----------------------------------------------------------------------
+    // regular factory
+    //-----------------------------------------------------------------------
+    @DataProvider(name="String_UTC")
+    Object[][] data_of_string_UTC() {
+        return new Object[][] {
+            {""}, {"Z"},
+            {"+00"},{"+0000"},{"+00:00"},{"+000000"},{"+00:00:00"},
+            {"-00"},{"-0000"},{"-00:00"},{"-000000"},{"-00:00:00"},
+        };
+    }
+
+    @Test(dataProvider="String_UTC")
+    public void test_of_string_UTC(String id) {
+        ZoneId test = ZoneId.of("UTC" + id);
+        assertSame(test, ZoneOffset.UTC);
+    }
+
+    @Test(dataProvider="String_UTC")
+    public void test_of_string_GMT(String id) {
+        ZoneId test = ZoneId.of("GMT" + id);
+        assertSame(test, ZoneOffset.UTC);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="String_Fixed")
+    Object[][] data_of_string_Fixed() {
+        return new Object[][] {
+            {"Z", "Z"},
+            {"+0", "Z"},
+            {"+5", "+05:00"},
+            {"+01", "+01:00"},
+            {"+0100", "+01:00"},{"+01:00", "+01:00"},
+            {"+010000", "+01:00"},{"+01:00:00", "+01:00"},
+            {"+12", "+12:00"},
+            {"+1234", "+12:34"},{"+12:34", "+12:34"},
+            {"+123456", "+12:34:56"},{"+12:34:56", "+12:34:56"},
+            {"-02", "-02:00"},
+            {"-5", "-05:00"},
+            {"-0200", "-02:00"},{"-02:00", "-02:00"},
+            {"-020000", "-02:00"},{"-02:00:00", "-02:00"},
+        };
+    }
+
+    @Test(dataProvider="String_Fixed")
+    public void test_of_string_offset(String input, String id) {
+        ZoneId test = ZoneId.of(input);
+        assertEquals(test.getId(), id);
+        assertEquals(test.getText(TextStyle.FULL, Locale.UK), id);
+        assertEquals(test.getRules().isFixedOffset(), true);
+        ZoneOffset offset = ZoneOffset.of(id);
+        assertEquals(test.getRules().getOffset(Instant.ofEpochSecond(0L)), offset);
+        checkOffset(test.getRules(), createLDT(2008, 6, 30), offset, 1);
+    }
+
+    @Test(dataProvider="String_Fixed")
+    public void test_of_string_FixedUTC(String input, String id) {
+        ZoneId test = ZoneId.of("UTC" + input);
+        assertEquals(test.getId(), id);
+        assertEquals(test.getText(TextStyle.FULL, Locale.UK), id);
+        assertEquals(test.getRules().isFixedOffset(), true);
+        ZoneOffset offset = ZoneOffset.of(id);
+        assertEquals(test.getRules().getOffset(Instant.ofEpochSecond(0L)), offset);
+        checkOffset(test.getRules(), createLDT(2008, 6, 30), offset, 1);
+    }
+
+    @Test(dataProvider="String_Fixed")
+    public void test_of_string_FixedGMT(String input, String id) {
+        ZoneId test = ZoneId.of("GMT" + input);
+        assertEquals(test.getId(), id);
+        assertEquals(test.getText(TextStyle.FULL, Locale.UK), id);
+        assertEquals(test.getRules().isFixedOffset(), true);
+        ZoneOffset offset = ZoneOffset.of(id);
+        assertEquals(test.getRules().getOffset(Instant.ofEpochSecond(0L)), offset);
+        checkOffset(test.getRules(), createLDT(2008, 6, 30), offset, 1);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="String_UTC_Invalid")
+    Object[][] data_of_string_UTC_invalid() {
+        return new Object[][] {
+                {"A"}, {"B"}, {"C"}, {"D"}, {"E"}, {"F"}, {"G"}, {"H"}, {"I"}, {"J"}, {"K"}, {"L"}, {"M"},
+                {"N"}, {"O"}, {"P"}, {"Q"}, {"R"}, {"S"}, {"T"}, {"U"}, {"V"}, {"W"}, {"X"}, {"Y"},
+                {"+0:00"}, {"+00:0"}, {"+0:0"},
+                {"+000"}, {"+00000"},
+                {"+0:00:00"}, {"+00:0:00"}, {"+00:00:0"}, {"+0:0:0"}, {"+0:0:00"}, {"+00:0:0"}, {"+0:00:0"},
+                {"+01_00"}, {"+01;00"}, {"+01@00"}, {"+01:AA"},
+                {"+19"}, {"+19:00"}, {"+18:01"}, {"+18:00:01"}, {"+1801"}, {"+180001"},
+                {"-0:00"}, {"-00:0"}, {"-0:0"},
+                {"-000"}, {"-00000"},
+                {"-0:00:00"}, {"-00:0:00"}, {"-00:00:0"}, {"-0:0:0"}, {"-0:0:00"}, {"-00:0:0"}, {"-0:00:0"},
+                {"-19"}, {"-19:00"}, {"-18:01"}, {"-18:00:01"}, {"-1801"}, {"-180001"},
+                {"-01_00"}, {"-01;00"}, {"-01@00"}, {"-01:AA"},
+                {"@01:00"},
+        };
+    }
+
+    @Test(dataProvider="String_UTC_Invalid", expectedExceptions=DateTimeException.class)
+    public void test_of_string_UTC_invalid(String id) {
+        ZoneId.of("UTC" + id);
+    }
+
+    @Test(dataProvider="String_UTC_Invalid", expectedExceptions=DateTimeException.class)
+    public void test_of_string_GMT_invalid(String id) {
+        ZoneId.of("GMT" + id);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="String_Invalid")
+    Object[][] data_of_string_invalid() {
+        // \u00ef is a random unicode character
+        return new Object[][] {
+                {""}, {":"}, {"#"},
+                {"\u00ef"}, {"`"}, {"!"}, {"\""}, {"\u00ef"}, {"$"}, {"^"}, {"&"}, {"*"}, {"("}, {")"}, {"="},
+                {"\\"}, {"|"}, {","}, {"<"}, {">"}, {"?"}, {";"}, {"'"}, {"["}, {"]"}, {"{"}, {"}"},
+                {"\u00ef:A"}, {"`:A"}, {"!:A"}, {"\":A"}, {"\u00ef:A"}, {"$:A"}, {"^:A"}, {"&:A"}, {"*:A"}, {"(:A"}, {"):A"}, {"=:A"}, {"+:A"},
+                {"\\:A"}, {"|:A"}, {",:A"}, {"<:A"}, {">:A"}, {"?:A"}, {";:A"}, {"::A"}, {"':A"}, {"@:A"}, {"~:A"}, {"[:A"}, {"]:A"}, {"{:A"}, {"}:A"},
+                {"A:B#\u00ef"}, {"A:B#`"}, {"A:B#!"}, {"A:B#\""}, {"A:B#\u00ef"}, {"A:B#$"}, {"A:B#^"}, {"A:B#&"}, {"A:B#*"},
+                {"A:B#("}, {"A:B#)"}, {"A:B#="}, {"A:B#+"},
+                {"A:B#\\"}, {"A:B#|"}, {"A:B#,"}, {"A:B#<"}, {"A:B#>"}, {"A:B#?"}, {"A:B#;"}, {"A:B#:"},
+                {"A:B#'"}, {"A:B#@"}, {"A:B#~"}, {"A:B#["}, {"A:B#]"}, {"A:B#{"}, {"A:B#}"},
+        };
+    }
+
+    @Test(dataProvider="String_Invalid", expectedExceptions=DateTimeException.class)
+    public void test_of_string_invalid(String id) {
+        ZoneId.of(id);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_of_string_GMT0() {
+        ZoneId test = ZoneId.of("GMT0");
+        assertEquals(test.getId(), "Z");
+        assertEquals(test.getRules().isFixedOffset(), true);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_of_string_London() {
+        ZoneId test = ZoneId.of("Europe/London");
+        assertEquals(test.getId(), "Europe/London");
+        assertEquals(test.getRules().isFixedOffset(), false);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_of_string_null() {
+        ZoneId.of((String) null);
+    }
+
+    @Test(expectedExceptions=ZoneRulesException.class)
+    public void test_of_string_unknown_simple() {
+        ZoneId.of("Unknown");
+    }
+
+    //-------------------------------------------------------------------------
+    // TODO: test by deserialization
+//    public void test_ofUnchecked_string_invalidNotChecked() {
+//        ZoneRegion test = ZoneRegion.ofLenient("Unknown");
+//        assertEquals(test.getId(), "Unknown");
+//    }
+//
+//    public void test_ofUnchecked_string_invalidNotChecked_unusualCharacters() {
+//        ZoneRegion test = ZoneRegion.ofLenient("QWERTYUIOPASDFGHJKLZXCVBNM~/._+-");
+//        assertEquals(test.getId(), "QWERTYUIOPASDFGHJKLZXCVBNM~/._+-");
+//    }
+
+    //-----------------------------------------------------------------------
+    // from(TemporalAccessor)
+    //-----------------------------------------------------------------------
+    public void test_factory_from_DateTimeAccessor_zoneId() {
+        TemporalAccessor mock = new TemporalAccessor() {
+            @Override
+            public boolean isSupported(TemporalField field) {
+                return false;
+            }
+
+            @Override
+            public long getLong(TemporalField field) {
+                throw new DateTimeException("Mock");
+            }
+
+            @Override
+            public <R> R query(TemporalQuery<R> query) {
+                if (query == Queries.zoneId()) {
+                    return (R) ZONE_PARIS;
+                }
+                return TemporalAccessor.super.query(query);
+            }
+        };
+        assertEquals(ZoneId.from(mock), ZONE_PARIS);
+    }
+
+    public void test_factory_from_DateTimeAccessor_offset() {
+        ZoneOffset offset = ZoneOffset.ofHours(1);
+        assertEquals(ZoneId.from(offset), offset);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class)
+    public void test_factory_from_DateTimeAccessor_invalid_noDerive() {
+        ZoneId.from(LocalTime.of(12, 30));
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void test_factory_from_DateTimeAccessor_null() {
+        ZoneId.from((TemporalAccessor) null);
+    }
+
+    //-----------------------------------------------------------------------
+    // Europe/London
+    //-----------------------------------------------------------------------
+    public void test_London() {
+        ZoneId test = ZoneId.of("Europe/London");
+        assertEquals(test.getId(), "Europe/London");
+        assertEquals(test.getRules().isFixedOffset(), false);
+    }
+
+    public void test_London_getOffset() {
+        ZoneId test = ZoneId.of("Europe/London");
+        assertEquals(test.getRules().getOffset(createInstant(2008, 1, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(0));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 2, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(0));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(0));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 4, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 5, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 6, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 7, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 8, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 9, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 10, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 11, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(0));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 12, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(0));
+    }
+
+    public void test_London_getOffset_toDST() {
+        ZoneId test = ZoneId.of("Europe/London");
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 24, ZoneOffset.UTC)), ZoneOffset.ofHours(0));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 25, ZoneOffset.UTC)), ZoneOffset.ofHours(0));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 26, ZoneOffset.UTC)), ZoneOffset.ofHours(0));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 27, ZoneOffset.UTC)), ZoneOffset.ofHours(0));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 28, ZoneOffset.UTC)), ZoneOffset.ofHours(0));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 29, ZoneOffset.UTC)), ZoneOffset.ofHours(0));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 30, ZoneOffset.UTC)), ZoneOffset.ofHours(0));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 31, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+        // cutover at 01:00Z
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 30, 0, 59, 59, 999999999, ZoneOffset.UTC)), ZoneOffset.ofHours(0));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 30, 1, 0, 0, 0, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+    }
+
+    public void test_London_getOffset_fromDST() {
+        ZoneId test = ZoneId.of("Europe/London");
+        assertEquals(test.getRules().getOffset(createInstant(2008, 10, 24, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 10, 25, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 10, 26, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 10, 27, ZoneOffset.UTC)), ZoneOffset.ofHours(0));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 10, 28, ZoneOffset.UTC)), ZoneOffset.ofHours(0));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 10, 29, ZoneOffset.UTC)), ZoneOffset.ofHours(0));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 10, 30, ZoneOffset.UTC)), ZoneOffset.ofHours(0));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 10, 31, ZoneOffset.UTC)), ZoneOffset.ofHours(0));
+        // cutover at 01:00Z
+        assertEquals(test.getRules().getOffset(createInstant(2008, 10, 26, 0, 59, 59, 999999999, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 10, 26, 1, 0, 0, 0, ZoneOffset.UTC)), ZoneOffset.ofHours(0));
+    }
+
+    public void test_London_getOffsetInfo() {
+        ZoneId test = ZoneId.of("Europe/London");
+        checkOffset(test.getRules(), createLDT(2008, 1, 1), ZoneOffset.ofHours(0), 1);
+        checkOffset(test.getRules(), createLDT(2008, 2, 1), ZoneOffset.ofHours(0), 1);
+        checkOffset(test.getRules(), createLDT(2008, 3, 1), ZoneOffset.ofHours(0), 1);
+        checkOffset(test.getRules(), createLDT(2008, 4, 1), ZoneOffset.ofHours(1), 1);
+        checkOffset(test.getRules(), createLDT(2008, 5, 1), ZoneOffset.ofHours(1), 1);
+        checkOffset(test.getRules(), createLDT(2008, 6, 1), ZoneOffset.ofHours(1), 1);
+        checkOffset(test.getRules(), createLDT(2008, 7, 1), ZoneOffset.ofHours(1), 1);
+        checkOffset(test.getRules(), createLDT(2008, 8, 1), ZoneOffset.ofHours(1), 1);
+        checkOffset(test.getRules(), createLDT(2008, 9, 1), ZoneOffset.ofHours(1), 1);
+        checkOffset(test.getRules(), createLDT(2008, 10, 1), ZoneOffset.ofHours(1), 1);
+        checkOffset(test.getRules(), createLDT(2008, 11, 1), ZoneOffset.ofHours(0), 1);
+        checkOffset(test.getRules(), createLDT(2008, 12, 1), ZoneOffset.ofHours(0), 1);
+    }
+
+    public void test_London_getOffsetInfo_toDST() {
+        ZoneId test = ZoneId.of("Europe/London");
+        checkOffset(test.getRules(), createLDT(2008, 3, 24), ZoneOffset.ofHours(0), 1);
+        checkOffset(test.getRules(), createLDT(2008, 3, 25), ZoneOffset.ofHours(0), 1);
+        checkOffset(test.getRules(), createLDT(2008, 3, 26), ZoneOffset.ofHours(0), 1);
+        checkOffset(test.getRules(), createLDT(2008, 3, 27), ZoneOffset.ofHours(0), 1);
+        checkOffset(test.getRules(), createLDT(2008, 3, 28), ZoneOffset.ofHours(0), 1);
+        checkOffset(test.getRules(), createLDT(2008, 3, 29), ZoneOffset.ofHours(0), 1);
+        checkOffset(test.getRules(), createLDT(2008, 3, 30), ZoneOffset.ofHours(0), 1);
+        checkOffset(test.getRules(), createLDT(2008, 3, 31), ZoneOffset.ofHours(1), 1);
+        // cutover at 01:00Z
+        checkOffset(test.getRules(), LocalDateTime.of(2008, 3, 30, 0, 59, 59, 999999999), ZoneOffset.ofHours(0), 1);
+        checkOffset(test.getRules(), LocalDateTime.of(2008, 3, 30, 1, 30, 0, 0), ZoneOffset.ofHours(0), GAP);
+        checkOffset(test.getRules(), LocalDateTime.of(2008, 3, 30, 2, 0, 0, 0), ZoneOffset.ofHours(1), 1);
+    }
+
+    public void test_London_getOffsetInfo_fromDST() {
+        ZoneId test = ZoneId.of("Europe/London");
+        checkOffset(test.getRules(), createLDT(2008, 10, 24), ZoneOffset.ofHours(1), 1);
+        checkOffset(test.getRules(), createLDT(2008, 10, 25), ZoneOffset.ofHours(1), 1);
+        checkOffset(test.getRules(), createLDT(2008, 10, 26), ZoneOffset.ofHours(1), 1);
+        checkOffset(test.getRules(), createLDT(2008, 10, 27), ZoneOffset.ofHours(0), 1);
+        checkOffset(test.getRules(), createLDT(2008, 10, 28), ZoneOffset.ofHours(0), 1);
+        checkOffset(test.getRules(), createLDT(2008, 10, 29), ZoneOffset.ofHours(0), 1);
+        checkOffset(test.getRules(), createLDT(2008, 10, 30), ZoneOffset.ofHours(0), 1);
+        checkOffset(test.getRules(), createLDT(2008, 10, 31), ZoneOffset.ofHours(0), 1);
+        // cutover at 01:00Z
+        checkOffset(test.getRules(), LocalDateTime.of(2008, 10, 26, 0, 59, 59, 999999999), ZoneOffset.ofHours(1), 1);
+        checkOffset(test.getRules(), LocalDateTime.of(2008, 10, 26, 1, 30, 0, 0), ZoneOffset.ofHours(1), OVERLAP);
+        checkOffset(test.getRules(), LocalDateTime.of(2008, 10, 26, 2, 0, 0, 0), ZoneOffset.ofHours(0), 1);
+    }
+
+    public void test_London_getOffsetInfo_gap() {
+        ZoneId test = ZoneId.of("Europe/London");
+        final LocalDateTime dateTime = LocalDateTime.of(2008, 3, 30, 1, 0, 0, 0);
+        ZoneOffsetTransition trans = checkOffset(test.getRules(), dateTime, ZoneOffset.ofHours(0), GAP);
+        assertEquals(trans.isGap(), true);
+        assertEquals(trans.isOverlap(), false);
+        assertEquals(trans.getOffsetBefore(), ZoneOffset.ofHours(0));
+        assertEquals(trans.getOffsetAfter(), ZoneOffset.ofHours(1));
+        assertEquals(trans.getInstant(), dateTime.toInstant(ZoneOffset.UTC));
+        assertEquals(trans.getDateTimeBefore(), LocalDateTime.of(2008, 3, 30, 1, 0));
+        assertEquals(trans.getDateTimeAfter(), LocalDateTime.of(2008, 3, 30, 2, 0));
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-1)), false);
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(0)), false);
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(1)), false);
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(2)), false);
+        assertEquals(trans.toString(), "Transition[Gap at 2008-03-30T01:00Z to +01:00]");
+
+        assertFalse(trans.equals(null));
+        assertFalse(trans.equals(ZoneOffset.ofHours(0)));
+        assertTrue(trans.equals(trans));
+
+        final ZoneOffsetTransition otherTrans = test.getRules().getTransition(dateTime);
+        assertTrue(trans.equals(otherTrans));
+        assertEquals(trans.hashCode(), otherTrans.hashCode());
+    }
+
+    public void test_London_getOffsetInfo_overlap() {
+        ZoneId test = ZoneId.of("Europe/London");
+        final LocalDateTime dateTime = LocalDateTime.of(2008, 10, 26, 1, 0, 0, 0);
+        ZoneOffsetTransition trans = checkOffset(test.getRules(), dateTime, ZoneOffset.ofHours(1), OVERLAP);
+        assertEquals(trans.isGap(), false);
+        assertEquals(trans.isOverlap(), true);
+        assertEquals(trans.getOffsetBefore(), ZoneOffset.ofHours(1));
+        assertEquals(trans.getOffsetAfter(), ZoneOffset.ofHours(0));
+        assertEquals(trans.getInstant(), dateTime.toInstant(ZoneOffset.UTC));
+        assertEquals(trans.getDateTimeBefore(), LocalDateTime.of(2008, 10, 26, 2, 0));
+        assertEquals(trans.getDateTimeAfter(), LocalDateTime.of(2008, 10, 26, 1, 0));
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-1)), false);
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(0)), true);
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(1)), true);
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(2)), false);
+        assertEquals(trans.toString(), "Transition[Overlap at 2008-10-26T02:00+01:00 to Z]");
+
+        assertFalse(trans.equals(null));
+        assertFalse(trans.equals(ZoneOffset.ofHours(1)));
+        assertTrue(trans.equals(trans));
+
+        final ZoneOffsetTransition otherTrans = test.getRules().getTransition(dateTime);
+        assertTrue(trans.equals(otherTrans));
+        assertEquals(trans.hashCode(), otherTrans.hashCode());
+    }
+
+    //-----------------------------------------------------------------------
+    // Europe/Paris
+    //-----------------------------------------------------------------------
+    public void test_Paris() {
+        ZoneId test = ZoneId.of("Europe/Paris");
+        assertEquals(test.getId(), "Europe/Paris");
+        assertEquals(test.getRules().isFixedOffset(), false);
+    }
+
+    public void test_Paris_getOffset() {
+        ZoneId test = ZoneId.of("Europe/Paris");
+        assertEquals(test.getRules().getOffset(createInstant(2008, 1, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 2, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 4, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(2));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 5, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(2));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 6, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(2));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 7, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(2));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 8, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(2));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 9, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(2));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 10, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(2));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 11, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 12, 1, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+    }
+
+    public void test_Paris_getOffset_toDST() {
+        ZoneId test = ZoneId.of("Europe/Paris");
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 24, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 25, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 26, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 27, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 28, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 29, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 30, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 31, ZoneOffset.UTC)), ZoneOffset.ofHours(2));
+        // cutover at 01:00Z
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 30, 0, 59, 59, 999999999, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 30, 1, 0, 0, 0, ZoneOffset.UTC)), ZoneOffset.ofHours(2));
+    }
+
+    public void test_Paris_getOffset_fromDST() {
+        ZoneId test = ZoneId.of("Europe/Paris");
+        assertEquals(test.getRules().getOffset(createInstant(2008, 10, 24, ZoneOffset.UTC)), ZoneOffset.ofHours(2));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 10, 25, ZoneOffset.UTC)), ZoneOffset.ofHours(2));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 10, 26, ZoneOffset.UTC)), ZoneOffset.ofHours(2));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 10, 27, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 10, 28, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 10, 29, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 10, 30, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 10, 31, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+        // cutover at 01:00Z
+        assertEquals(test.getRules().getOffset(createInstant(2008, 10, 26, 0, 59, 59, 999999999, ZoneOffset.UTC)), ZoneOffset.ofHours(2));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 10, 26, 1, 0, 0, 0, ZoneOffset.UTC)), ZoneOffset.ofHours(1));
+    }
+
+    public void test_Paris_getOffsetInfo() {
+        ZoneId test = ZoneId.of("Europe/Paris");
+        checkOffset(test.getRules(), createLDT(2008, 1, 1), ZoneOffset.ofHours(1), 1);
+        checkOffset(test.getRules(), createLDT(2008, 2, 1), ZoneOffset.ofHours(1), 1);
+        checkOffset(test.getRules(), createLDT(2008, 3, 1), ZoneOffset.ofHours(1), 1);
+        checkOffset(test.getRules(), createLDT(2008, 4, 1), ZoneOffset.ofHours(2), 1);
+        checkOffset(test.getRules(), createLDT(2008, 5, 1), ZoneOffset.ofHours(2), 1);
+        checkOffset(test.getRules(), createLDT(2008, 6, 1), ZoneOffset.ofHours(2), 1);
+        checkOffset(test.getRules(), createLDT(2008, 7, 1), ZoneOffset.ofHours(2), 1);
+        checkOffset(test.getRules(), createLDT(2008, 8, 1), ZoneOffset.ofHours(2), 1);
+        checkOffset(test.getRules(), createLDT(2008, 9, 1), ZoneOffset.ofHours(2), 1);
+        checkOffset(test.getRules(), createLDT(2008, 10, 1), ZoneOffset.ofHours(2), 1);
+        checkOffset(test.getRules(), createLDT(2008, 11, 1), ZoneOffset.ofHours(1), 1);
+        checkOffset(test.getRules(), createLDT(2008, 12, 1), ZoneOffset.ofHours(1), 1);
+    }
+
+    public void test_Paris_getOffsetInfo_toDST() {
+        ZoneId test = ZoneId.of("Europe/Paris");
+        checkOffset(test.getRules(), createLDT(2008, 3, 24), ZoneOffset.ofHours(1), 1);
+        checkOffset(test.getRules(), createLDT(2008, 3, 25), ZoneOffset.ofHours(1), 1);
+        checkOffset(test.getRules(), createLDT(2008, 3, 26), ZoneOffset.ofHours(1), 1);
+        checkOffset(test.getRules(), createLDT(2008, 3, 27), ZoneOffset.ofHours(1), 1);
+        checkOffset(test.getRules(), createLDT(2008, 3, 28), ZoneOffset.ofHours(1), 1);
+        checkOffset(test.getRules(), createLDT(2008, 3, 29), ZoneOffset.ofHours(1), 1);
+        checkOffset(test.getRules(), createLDT(2008, 3, 30), ZoneOffset.ofHours(1), 1);
+        checkOffset(test.getRules(), createLDT(2008, 3, 31), ZoneOffset.ofHours(2), 1);
+        // cutover at 01:00Z which is 02:00+01:00(local Paris time)
+        checkOffset(test.getRules(), LocalDateTime.of(2008, 3, 30, 1, 59, 59, 999999999), ZoneOffset.ofHours(1), 1);
+        checkOffset(test.getRules(), LocalDateTime.of(2008, 3, 30, 2, 30, 0, 0), ZoneOffset.ofHours(1), GAP);
+        checkOffset(test.getRules(), LocalDateTime.of(2008, 3, 30, 3, 0, 0, 0), ZoneOffset.ofHours(2), 1);
+    }
+
+    public void test_Paris_getOffsetInfo_fromDST() {
+        ZoneId test = ZoneId.of("Europe/Paris");
+        checkOffset(test.getRules(), createLDT(2008, 10, 24), ZoneOffset.ofHours(2), 1);
+        checkOffset(test.getRules(), createLDT(2008, 10, 25), ZoneOffset.ofHours(2), 1);
+        checkOffset(test.getRules(), createLDT(2008, 10, 26), ZoneOffset.ofHours(2), 1);
+        checkOffset(test.getRules(), createLDT(2008, 10, 27), ZoneOffset.ofHours(1), 1);
+        checkOffset(test.getRules(), createLDT(2008, 10, 28), ZoneOffset.ofHours(1), 1);
+        checkOffset(test.getRules(), createLDT(2008, 10, 29), ZoneOffset.ofHours(1), 1);
+        checkOffset(test.getRules(), createLDT(2008, 10, 30), ZoneOffset.ofHours(1), 1);
+        checkOffset(test.getRules(), createLDT(2008, 10, 31), ZoneOffset.ofHours(1), 1);
+        // cutover at 01:00Z which is 02:00+01:00(local Paris time)
+        checkOffset(test.getRules(), LocalDateTime.of(2008, 10, 26, 1, 59, 59, 999999999), ZoneOffset.ofHours(2), 1);
+        checkOffset(test.getRules(), LocalDateTime.of(2008, 10, 26, 2, 30, 0, 0), ZoneOffset.ofHours(2), OVERLAP);
+        checkOffset(test.getRules(), LocalDateTime.of(2008, 10, 26, 3, 0, 0, 0), ZoneOffset.ofHours(1), 1);
+    }
+
+    public void test_Paris_getOffsetInfo_gap() {
+        ZoneId test = ZoneId.of("Europe/Paris");
+        final LocalDateTime dateTime = LocalDateTime.of(2008, 3, 30, 2, 0, 0, 0);
+        ZoneOffsetTransition trans = checkOffset(test.getRules(), dateTime, ZoneOffset.ofHours(1), GAP);
+        assertEquals(trans.isGap(), true);
+        assertEquals(trans.isOverlap(), false);
+        assertEquals(trans.getOffsetBefore(), ZoneOffset.ofHours(1));
+        assertEquals(trans.getOffsetAfter(), ZoneOffset.ofHours(2));
+        assertEquals(trans.getInstant(), createInstant(2008, 3, 30, 1, 0, 0, 0, ZoneOffset.UTC));
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(0)), false);
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(1)), false);
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(2)), false);
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(3)), false);
+        assertEquals(trans.toString(), "Transition[Gap at 2008-03-30T02:00+01:00 to +02:00]");
+
+        assertFalse(trans.equals(null));
+        assertFalse(trans.equals(ZoneOffset.ofHours(1)));
+        assertTrue(trans.equals(trans));
+
+        final ZoneOffsetTransition otherDis = test.getRules().getTransition(dateTime);
+        assertTrue(trans.equals(otherDis));
+        assertEquals(trans.hashCode(), otherDis.hashCode());
+    }
+
+    public void test_Paris_getOffsetInfo_overlap() {
+        ZoneId test = ZoneId.of("Europe/Paris");
+        final LocalDateTime dateTime = LocalDateTime.of(2008, 10, 26, 2, 0, 0, 0);
+        ZoneOffsetTransition trans = checkOffset(test.getRules(), dateTime, ZoneOffset.ofHours(2), OVERLAP);
+        assertEquals(trans.isGap(), false);
+        assertEquals(trans.isOverlap(), true);
+        assertEquals(trans.getOffsetBefore(), ZoneOffset.ofHours(2));
+        assertEquals(trans.getOffsetAfter(), ZoneOffset.ofHours(1));
+        assertEquals(trans.getInstant(), createInstant(2008, 10, 26, 1, 0, 0, 0, ZoneOffset.UTC));
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(0)), false);
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(1)), true);
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(2)), true);
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(3)), false);
+        assertEquals(trans.toString(), "Transition[Overlap at 2008-10-26T03:00+02:00 to +01:00]");
+
+        assertFalse(trans.equals(null));
+        assertFalse(trans.equals(ZoneOffset.ofHours(2)));
+        assertTrue(trans.equals(trans));
+
+        final ZoneOffsetTransition otherDis = test.getRules().getTransition(dateTime);
+        assertTrue(trans.equals(otherDis));
+        assertEquals(trans.hashCode(), otherDis.hashCode());
+    }
+
+    //-----------------------------------------------------------------------
+    // America/New_York
+    //-----------------------------------------------------------------------
+    public void test_NewYork() {
+        ZoneId test = ZoneId.of("America/New_York");
+        assertEquals(test.getId(), "America/New_York");
+        assertEquals(test.getRules().isFixedOffset(), false);
+    }
+
+    public void test_NewYork_getOffset() {
+        ZoneId test = ZoneId.of("America/New_York");
+        ZoneOffset offset = ZoneOffset.ofHours(-5);
+        assertEquals(test.getRules().getOffset(createInstant(2008, 1, 1, offset)), ZoneOffset.ofHours(-5));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 2, 1, offset)), ZoneOffset.ofHours(-5));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 1, offset)), ZoneOffset.ofHours(-5));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 4, 1, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 5, 1, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 6, 1, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 7, 1, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 8, 1, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 9, 1, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 10, 1, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 11, 1, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 12, 1, offset)), ZoneOffset.ofHours(-5));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 1, 28, offset)), ZoneOffset.ofHours(-5));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 2, 28, offset)), ZoneOffset.ofHours(-5));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 28, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 4, 28, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 5, 28, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 6, 28, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 7, 28, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 8, 28, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 9, 28, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 10, 28, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 11, 28, offset)), ZoneOffset.ofHours(-5));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 12, 28, offset)), ZoneOffset.ofHours(-5));
+    }
+
+    public void test_NewYork_getOffset_toDST() {
+        ZoneId test = ZoneId.of("America/New_York");
+        ZoneOffset offset = ZoneOffset.ofHours(-5);
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 8, offset)), ZoneOffset.ofHours(-5));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 9, offset)), ZoneOffset.ofHours(-5));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 10, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 11, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 12, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 13, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 14, offset)), ZoneOffset.ofHours(-4));
+        // cutover at 02:00 local
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 9, 1, 59, 59, 999999999, offset)), ZoneOffset.ofHours(-5));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 3, 9, 2, 0, 0, 0, offset)), ZoneOffset.ofHours(-4));
+    }
+
+    public void test_NewYork_getOffset_fromDST() {
+        ZoneId test = ZoneId.of("America/New_York");
+        ZoneOffset offset = ZoneOffset.ofHours(-4);
+        assertEquals(test.getRules().getOffset(createInstant(2008, 11, 1, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 11, 2, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 11, 3, offset)), ZoneOffset.ofHours(-5));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 11, 4, offset)), ZoneOffset.ofHours(-5));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 11, 5, offset)), ZoneOffset.ofHours(-5));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 11, 6, offset)), ZoneOffset.ofHours(-5));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 11, 7, offset)), ZoneOffset.ofHours(-5));
+        // cutover at 02:00 local
+        assertEquals(test.getRules().getOffset(createInstant(2008, 11, 2, 1, 59, 59, 999999999, offset)), ZoneOffset.ofHours(-4));
+        assertEquals(test.getRules().getOffset(createInstant(2008, 11, 2, 2, 0, 0, 0, offset)), ZoneOffset.ofHours(-5));
+    }
+
+    public void test_NewYork_getOffsetInfo() {
+        ZoneId test = ZoneId.of("America/New_York");
+        checkOffset(test.getRules(), createLDT(2008, 1, 1), ZoneOffset.ofHours(-5), 1);
+        checkOffset(test.getRules(), createLDT(2008, 2, 1), ZoneOffset.ofHours(-5), 1);
+        checkOffset(test.getRules(), createLDT(2008, 3, 1), ZoneOffset.ofHours(-5), 1);
+        checkOffset(test.getRules(), createLDT(2008, 4, 1), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test.getRules(), createLDT(2008, 5, 1), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test.getRules(), createLDT(2008, 6, 1), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test.getRules(), createLDT(2008, 7, 1), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test.getRules(), createLDT(2008, 8, 1), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test.getRules(), createLDT(2008, 9, 1), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test.getRules(), createLDT(2008, 10, 1), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test.getRules(), createLDT(2008, 11, 1), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test.getRules(), createLDT(2008, 12, 1), ZoneOffset.ofHours(-5), 1);
+        checkOffset(test.getRules(), createLDT(2008, 1, 28), ZoneOffset.ofHours(-5), 1);
+        checkOffset(test.getRules(), createLDT(2008, 2, 28), ZoneOffset.ofHours(-5), 1);
+        checkOffset(test.getRules(), createLDT(2008, 3, 28), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test.getRules(), createLDT(2008, 4, 28), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test.getRules(), createLDT(2008, 5, 28), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test.getRules(), createLDT(2008, 6, 28), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test.getRules(), createLDT(2008, 7, 28), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test.getRules(), createLDT(2008, 8, 28), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test.getRules(), createLDT(2008, 9, 28), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test.getRules(), createLDT(2008, 10, 28), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test.getRules(), createLDT(2008, 11, 28), ZoneOffset.ofHours(-5), 1);
+        checkOffset(test.getRules(), createLDT(2008, 12, 28), ZoneOffset.ofHours(-5), 1);
+    }
+
+    public void test_NewYork_getOffsetInfo_toDST() {
+        ZoneId test = ZoneId.of("America/New_York");
+        checkOffset(test.getRules(), createLDT(2008, 3, 8), ZoneOffset.ofHours(-5), 1);
+        checkOffset(test.getRules(), createLDT(2008, 3, 9), ZoneOffset.ofHours(-5), 1);
+        checkOffset(test.getRules(), createLDT(2008, 3, 10), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test.getRules(), createLDT(2008, 3, 11), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test.getRules(), createLDT(2008, 3, 12), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test.getRules(), createLDT(2008, 3, 13), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test.getRules(), createLDT(2008, 3, 14), ZoneOffset.ofHours(-4), 1);
+        // cutover at 02:00 local
+        checkOffset(test.getRules(), LocalDateTime.of(2008, 3, 9, 1, 59, 59, 999999999), ZoneOffset.ofHours(-5), 1);
+        checkOffset(test.getRules(), LocalDateTime.of(2008, 3, 9, 2, 30, 0, 0), ZoneOffset.ofHours(-5), GAP);
+        checkOffset(test.getRules(), LocalDateTime.of(2008, 3, 9, 3, 0, 0, 0), ZoneOffset.ofHours(-4), 1);
+    }
+
+    public void test_NewYork_getOffsetInfo_fromDST() {
+        ZoneId test = ZoneId.of("America/New_York");
+        checkOffset(test.getRules(), createLDT(2008, 11, 1), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test.getRules(), createLDT(2008, 11, 2), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test.getRules(), createLDT(2008, 11, 3), ZoneOffset.ofHours(-5), 1);
+        checkOffset(test.getRules(), createLDT(2008, 11, 4), ZoneOffset.ofHours(-5), 1);
+        checkOffset(test.getRules(), createLDT(2008, 11, 5), ZoneOffset.ofHours(-5), 1);
+        checkOffset(test.getRules(), createLDT(2008, 11, 6), ZoneOffset.ofHours(-5), 1);
+        checkOffset(test.getRules(), createLDT(2008, 11, 7), ZoneOffset.ofHours(-5), 1);
+        // cutover at 02:00 local
+        checkOffset(test.getRules(), LocalDateTime.of(2008, 11, 2, 0, 59, 59, 999999999), ZoneOffset.ofHours(-4), 1);
+        checkOffset(test.getRules(), LocalDateTime.of(2008, 11, 2, 1, 30, 0, 0), ZoneOffset.ofHours(-4), OVERLAP);
+        checkOffset(test.getRules(), LocalDateTime.of(2008, 11, 2, 2, 0, 0, 0), ZoneOffset.ofHours(-5), 1);
+    }
+
+    public void test_NewYork_getOffsetInfo_gap() {
+        ZoneId test = ZoneId.of("America/New_York");
+        final LocalDateTime dateTime = LocalDateTime.of(2008, 3, 9, 2, 0, 0, 0);
+        ZoneOffsetTransition trans = checkOffset(test.getRules(), dateTime, ZoneOffset.ofHours(-5), GAP);
+        assertEquals(trans.getOffsetBefore(), ZoneOffset.ofHours(-5));
+        assertEquals(trans.getOffsetAfter(), ZoneOffset.ofHours(-4));
+        assertEquals(trans.getInstant(), createInstant(2008, 3, 9, 2, 0, 0, 0, ZoneOffset.ofHours(-5)));
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-6)), false);
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-5)), false);
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-4)), false);
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-3)), false);
+        assertEquals(trans.toString(), "Transition[Gap at 2008-03-09T02:00-05:00 to -04:00]");
+
+        assertFalse(trans.equals(null));
+        assertFalse(trans.equals(ZoneOffset.ofHours(-5)));
+        assertTrue(trans.equals(trans));
+
+        final ZoneOffsetTransition otherTrans = test.getRules().getTransition(dateTime);
+        assertTrue(trans.equals(otherTrans));
+
+        assertEquals(trans.hashCode(), otherTrans.hashCode());
+    }
+
+    public void test_NewYork_getOffsetInfo_overlap() {
+        ZoneId test = ZoneId.of("America/New_York");
+        final LocalDateTime dateTime = LocalDateTime.of(2008, 11, 2, 1, 0, 0, 0);
+        ZoneOffsetTransition trans = checkOffset(test.getRules(), dateTime, ZoneOffset.ofHours(-4), OVERLAP);
+        assertEquals(trans.getOffsetBefore(), ZoneOffset.ofHours(-4));
+        assertEquals(trans.getOffsetAfter(), ZoneOffset.ofHours(-5));
+        assertEquals(trans.getInstant(), createInstant(2008, 11, 2, 2, 0, 0, 0, ZoneOffset.ofHours(-4)));
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-1)), false);
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-5)), true);
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-4)), true);
+        assertEquals(trans.isValidOffset(ZoneOffset.ofHours(2)), false);
+        assertEquals(trans.toString(), "Transition[Overlap at 2008-11-02T02:00-04:00 to -05:00]");
+
+        assertFalse(trans.equals(null));
+        assertFalse(trans.equals(ZoneOffset.ofHours(-4)));
+        assertTrue(trans.equals(trans));
+
+        final ZoneOffsetTransition otherTrans = test.getRules().getTransition(dateTime);
+        assertTrue(trans.equals(otherTrans));
+
+        assertEquals(trans.hashCode(), otherTrans.hashCode());
+    }
+
+    //-----------------------------------------------------------------------
+    // getXxx() isXxx()
+    //-----------------------------------------------------------------------
+    public void test_get_Tzdb() {
+        ZoneId test = ZoneId.of("Europe/London");
+        assertEquals(test.getId(), "Europe/London");
+        assertEquals(test.getRules().isFixedOffset(), false);
+    }
+
+    public void test_get_TzdbFixed() {
+        ZoneId test = ZoneId.of("+01:30");
+        assertEquals(test.getId(), "+01:30");
+        assertEquals(test.getRules().isFixedOffset(), true);
+    }
+
+    //-----------------------------------------------------------------------
+    // equals() / hashCode()
+    //-----------------------------------------------------------------------
+    public void test_equals() {
+        ZoneId test1 = ZoneId.of("Europe/London");
+        ZoneId test2 = ZoneId.of("Europe/Paris");
+        ZoneId test2b = ZoneId.of("Europe/Paris");
+        assertEquals(test1.equals(test2), false);
+        assertEquals(test2.equals(test1), false);
+
+        assertEquals(test1.equals(test1), true);
+        assertEquals(test2.equals(test2), true);
+        assertEquals(test2.equals(test2b), true);
+
+        assertEquals(test1.hashCode() == test1.hashCode(), true);
+        assertEquals(test2.hashCode() == test2.hashCode(), true);
+        assertEquals(test2.hashCode() == test2b.hashCode(), true);
+    }
+
+    public void test_equals_null() {
+        assertEquals(ZoneId.of("Europe/London").equals(null), false);
+    }
+
+    public void test_equals_notTimeZone() {
+        assertEquals(ZoneId.of("Europe/London").equals("Europe/London"), false);
+    }
+
+    //-----------------------------------------------------------------------
+    // toString()
+    //-----------------------------------------------------------------------
+    @DataProvider(name="ToString")
+    Object[][] data_toString() {
+        return new Object[][] {
+            {"Europe/London", "Europe/London"},
+            {"Europe/Paris", "Europe/Paris"},
+            {"Europe/Berlin", "Europe/Berlin"},
+            {"UTC", "Z"},
+            {"UTC+01:00", "+01:00"},
+        };
+    }
+
+    @Test(dataProvider="ToString")
+    public void test_toString(String id, String expected) {
+        ZoneId test = ZoneId.of(id);
+        assertEquals(test.toString(), expected);
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    private Instant createInstant(int year, int month, int day, ZoneOffset offset) {
+        return LocalDateTime.of(year, month, day, 0, 0).toInstant(offset);
+    }
+
+    private Instant createInstant(int year, int month, int day, int hour, int min, int sec, int nano, ZoneOffset offset) {
+        return LocalDateTime.of(year, month, day, hour, min, sec, nano).toInstant(offset);
+    }
+
+    private ZonedDateTime createZDT(int year, int month, int day, int hour, int min, int sec, int nano, ZoneId zone) {
+        return LocalDateTime.of(year, month, day, hour, min, sec, nano).atZone(zone);
+    }
+
+    private LocalDateTime createLDT(int year, int month, int day) {
+        return LocalDateTime.of(year, month, day, 0, 0);
+    }
+
+    private ZoneOffsetTransition checkOffset(ZoneRules rules, LocalDateTime dateTime, ZoneOffset offset, int type) {
+        List<ZoneOffset> validOffsets = rules.getValidOffsets(dateTime);
+        assertEquals(validOffsets.size(), type);
+        assertEquals(rules.getOffset(dateTime), offset);
+        if (type == 1) {
+            assertEquals(validOffsets.get(0), offset);
+            return null;
+        } else {
+            ZoneOffsetTransition zot = rules.getTransition(dateTime);
+            assertNotNull(zot);
+            assertEquals(zot.isOverlap(), type == 2);
+            assertEquals(zot.isGap(), type == 0);
+            assertEquals(zot.isValidOffset(offset), type == 2);
+            return zot;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/TestZoneOffset.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time;
+
+import static org.testng.Assert.assertSame;
+
+import java.time.ZoneOffset;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test ZoneOffset.
+ */
+@Test
+public class TestZoneOffset extends AbstractTest {
+
+    @Test
+    public void test_immutable() {
+        assertImmutable(ZoneOffset.class);
+    }
+
+    @Test
+    public void test_factory_ofTotalSecondsSame() {
+        assertSame(ZoneOffset.ofTotalSeconds(0), ZoneOffset.UTC);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/TestZonedDateTime.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time;
+
+import java.time.ZonedDateTime;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test ZonedDateTime.
+ */
+@Test
+public class TestZonedDateTime extends AbstractTest {
+
+    @Test
+    public void test_immutable() {
+        assertImmutable(ZonedDateTime.class);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/format/AbstractTestPrinterParser.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.format;
+
+import java.time.format.*;
+
+import java.util.Locale;
+
+import java.time.DateTimeException;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalField;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+/**
+ * Abstract PrinterParser test.
+ */
+@Test
+public class AbstractTestPrinterParser {
+
+    protected StringBuilder buf;
+    protected DateTimeFormatterBuilder builder;
+    protected TemporalAccessor dta;
+    protected Locale locale;
+    protected DateTimeFormatSymbols symbols;
+
+
+    @BeforeMethod(groups={"tck"})
+    public void setUp() {
+        buf = new StringBuilder();
+        builder = new DateTimeFormatterBuilder();
+        dta = ZonedDateTime.of(LocalDateTime.of(2011, 6, 30, 12, 30, 40, 0), ZoneId.of("Europe/Paris"));
+        locale = Locale.ENGLISH;
+        symbols = DateTimeFormatSymbols.STANDARD;
+    }
+
+    protected void setCaseSensitive(boolean caseSensitive) {
+        if (caseSensitive) {
+            builder.parseCaseSensitive();
+        } else {
+            builder.parseCaseInsensitive();
+        }
+    }
+
+    protected void setStrict(boolean strict) {
+        if (strict) {
+            builder.parseStrict();
+        } else {
+            builder.parseLenient();
+        }
+    }
+
+    protected DateTimeFormatter getFormatter() {
+        return builder.toFormatter(locale).withSymbols(symbols);
+    }
+
+    protected DateTimeFormatter getFormatter(char c) {
+        return builder.appendLiteral(c).toFormatter(locale).withSymbols(symbols);
+    }
+
+    protected DateTimeFormatter getFormatter(String s) {
+        return builder.appendLiteral(s).toFormatter(locale).withSymbols(symbols);
+    }
+
+    protected DateTimeFormatter getFormatter(TemporalField field, TextStyle style) {
+        return builder.appendText(field, style).toFormatter(locale).withSymbols(symbols);
+    }
+
+    protected DateTimeFormatter getFormatter(TemporalField field, int minWidth, int maxWidth, SignStyle signStyle) {
+        return builder.appendValue(field, minWidth, maxWidth, signStyle).toFormatter(locale).withSymbols(symbols);
+    }
+
+    protected DateTimeFormatter getFormatter(String pattern, String noOffsetText) {
+        return builder.appendOffset(pattern, noOffsetText).toFormatter(locale).withSymbols(symbols);
+    }
+
+    protected static final TemporalAccessor EMPTY_DTA = new TemporalAccessor() {
+        public boolean isSupported(TemporalField field) {
+            return true;
+        }
+        @Override
+        public long getLong(TemporalField field) {
+            throw new DateTimeException("Mock");
+        }
+    };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/format/MockIOExceptionAppendable.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008,2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.format;
+
+import java.time.format.*;
+
+import java.io.IOException;
+
+/**
+ * Mock Appendable that throws IOException.
+ */
+public class MockIOExceptionAppendable implements Appendable {
+
+    public Appendable append(CharSequence csq) throws IOException {
+        throw new IOException();
+    }
+
+    public Appendable append(char c) throws IOException {
+        throw new IOException();
+    }
+
+    public Appendable append(CharSequence csq, int start, int end)
+            throws IOException {
+        throw new IOException();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/format/TestCharLiteralParser.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.format;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.time.format.DateTimeBuilder;
+import java.text.ParsePosition;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test CharLiteralPrinterParser.
+ */
+@Test(groups={"implementation"})
+public class TestCharLiteralParser extends AbstractTestPrinterParser {
+
+    @DataProvider(name="success")
+    Object[][] data_success() {
+        return new Object[][] {
+            // match
+            {'a', true, "a", 0, 1},
+            {'a', true, "aOTHER", 0, 1},
+            {'a', true, "OTHERaOTHER", 5, 6},
+            {'a', true, "OTHERa", 5, 6},
+
+            // no match
+            {'a', true, "", 0, 0},
+            {'a', true, "a", 1, 1},
+            {'a', true, "A", 0, 0},
+            {'a', true, "b", 0, 0},
+            {'a', true, "OTHERbOTHER", 5, 5},
+            {'a', true, "OTHERb", 5, 5},
+
+            // case insensitive
+            {'a', false, "a", 0, 1},
+            {'a', false, "A", 0, 1},
+        };
+    }
+
+    @Test(dataProvider="success")
+    public void test_parse_success(char c, boolean caseSensitive,
+                                   String text, int pos, int expectedPos) {
+        setCaseSensitive(caseSensitive);
+        ParsePosition ppos = new ParsePosition(pos);
+        DateTimeBuilder result =
+               getFormatter(c).parseToBuilder(text, ppos);
+        if (ppos.getErrorIndex() != -1) {
+            assertEquals(ppos.getIndex(), expectedPos);
+        } else {
+            assertEquals(ppos.getIndex(), expectedPos);
+            assertEquals(result.getCalendricalList().size(), 0);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="error")
+    Object[][] data_error() {
+        return new Object[][] {
+            {'a', "a", -1, IndexOutOfBoundsException.class},
+            {'a', "a", 2, IndexOutOfBoundsException.class},
+        };
+    }
+
+    @Test(dataProvider="error")
+    public void test_parse_error(char c, String text, int pos, Class<?> expected) {
+        try {
+            DateTimeBuilder result =
+               getFormatter(c).parseToBuilder(text, new ParsePosition(pos));
+            assertTrue(false);
+        } catch (RuntimeException ex) {
+            assertTrue(expected.isInstance(ex));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/format/TestCharLiteralPrinter.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.format;
+
+import java.time.format.*;
+
+import static org.testng.Assert.assertEquals;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test CharLiteralPrinterParser.
+ */
+@Test(groups={"implementation"})
+public class TestCharLiteralPrinter extends AbstractTestPrinterParser {
+
+    //-----------------------------------------------------------------------
+    public void test_print_emptyCalendrical() throws Exception {
+        buf.append("EXISTING");
+        getFormatter('a').printTo(EMPTY_DTA, buf);
+        assertEquals(buf.toString(), "EXISTINGa");
+    }
+
+    public void test_print_dateTime() throws Exception {
+        buf.append("EXISTING");
+        getFormatter('a').printTo(dta, buf);
+        assertEquals(buf.toString(), "EXISTINGa");
+    }
+
+    public void test_print_emptyAppendable() throws Exception {
+        getFormatter('a').printTo(dta, buf);
+        assertEquals(buf.toString(), "a");
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_toString() throws Exception {
+        assertEquals(getFormatter('a').toString(), "'a'");
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_toString_apos() throws Exception {
+        assertEquals(getFormatter('\'').toString(), "''");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/format/TestDateTimeFormatSymbols.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.format;
+
+import java.time.format.*;
+
+import static org.testng.Assert.assertSame;
+
+import java.util.Locale;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test DateTimeFormatSymbols.
+ */
+@Test
+public class TestDateTimeFormatSymbols {
+
+    @Test(groups={"implementation"})
+    public void test_of_Locale_cached() {
+        DateTimeFormatSymbols loc1 = DateTimeFormatSymbols.of(Locale.CANADA);
+        DateTimeFormatSymbols loc2 = DateTimeFormatSymbols.of(Locale.CANADA);
+        assertSame(loc1, loc2);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups={"implementation"})
+    public void test_ofDefaultLocale_cached() {
+        DateTimeFormatSymbols loc1 = DateTimeFormatSymbols.ofDefaultLocale();
+        DateTimeFormatSymbols loc2 = DateTimeFormatSymbols.ofDefaultLocale();
+        assertSame(loc1, loc2);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/format/TestDateTimeFormatter.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.format;
+
+import java.time.format.*;
+
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static org.testng.Assert.assertSame;
+
+import java.util.Locale;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+/**
+ * Test DateTimeFormatter.
+ */
+@Test
+public class TestDateTimeFormatter {
+    // TODO these tests are not tck, as they refer to a non-public class
+    // rewrite whole test case to use BASIC_FORMATTER or similar
+
+    @BeforeMethod(groups={"tck"})
+    public void setUp() {
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withLocale_same() throws Exception {
+        DateTimeFormatter base =
+            new DateTimeFormatterBuilder().appendLiteral("ONE")
+                                          .appendValue(DAY_OF_MONTH, 1, 2, SignStyle.NOT_NEGATIVE)
+                                          .toFormatter(Locale.ENGLISH)
+                                          .withSymbols(DateTimeFormatSymbols.STANDARD);
+        DateTimeFormatter test = base.withLocale(Locale.ENGLISH);
+        assertSame(test, base);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/format/TestDateTimeFormatters.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.format;
+
+import java.time.format.*;
+
+import static org.testng.Assert.assertTrue;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Modifier;
+import java.util.Collections;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+/**
+ * Test DateTimeFormatters.
+ */
+@Test
+public class TestDateTimeFormatters {
+
+    @BeforeMethod
+    public void setUp() {
+    }
+
+    @Test(groups={"implementation"})
+    @SuppressWarnings("rawtypes")
+    public void test_constructor() throws Exception {
+        for (Constructor constructor : DateTimeFormatters.class.getDeclaredConstructors()) {
+            assertTrue(Modifier.isPrivate(constructor.getModifiers()));
+            //constructor.setAccessible(true);
+            //constructor.newInstance(Collections.nCopies(constructor.getParameterTypes().length, null).toArray());
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/format/TestDateTimePrintException.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.format;
+
+import java.time.format.*;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertSame;
+
+import java.io.IOException;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test DateTimePrintException.
+ */
+@Test
+public class TestDateTimePrintException {
+
+    @Test(groups={"implementation"})
+    public void test_constructor_StringThrowable_notIOException_same() throws Exception {
+        IllegalArgumentException iaex = new IllegalArgumentException("INNER");
+        DateTimePrintException ex = new DateTimePrintException("TEST", iaex);
+        assertEquals(ex.getMessage(), "TEST");
+        assertSame(ex.getCause(), iaex);
+        ex.rethrowIOException();  // no effect
+    }
+
+    @Test(expectedExceptions=IOException.class, groups={"implementation"})
+    public void test_constructor_StringThrowable_IOException_same() throws Exception {
+        IOException ioex = new IOException("INNER");
+        DateTimePrintException ex = new DateTimePrintException("TEST", ioex);
+        assertEquals(ex.getMessage(), "TEST");
+        assertSame(ex.getCause(), ioex);
+        ex.rethrowIOException();  // rethrows
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/format/TestDateTimeTextProvider.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.format;
+
+import java.time.format.*;
+
+import static java.time.temporal.ChronoField.AMPM_OF_DAY;
+import static java.time.temporal.ChronoField.DAY_OF_WEEK;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static org.testng.Assert.assertEquals;
+
+import java.util.Locale;
+
+import java.time.ZonedDateTime;
+import java.time.temporal.TemporalField;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test SimpleDateTimeTextProvider.
+ */
+@Test(groups={"implementation"})
+public class TestDateTimeTextProvider extends AbstractTestPrinterParser {
+
+    Locale enUS = new Locale("en", "US");
+    Locale ptBR = new Locale("pt", "BR");
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name = "Text")
+    Object[][] data_text() {
+        return new Object[][] {
+            {DAY_OF_WEEK, 1, TextStyle.SHORT, enUS, "Mon"},
+            {DAY_OF_WEEK, 2, TextStyle.SHORT, enUS, "Tue"},
+            {DAY_OF_WEEK, 3, TextStyle.SHORT, enUS, "Wed"},
+            {DAY_OF_WEEK, 4, TextStyle.SHORT, enUS, "Thu"},
+            {DAY_OF_WEEK, 5, TextStyle.SHORT, enUS, "Fri"},
+            {DAY_OF_WEEK, 6, TextStyle.SHORT, enUS, "Sat"},
+            {DAY_OF_WEEK, 7, TextStyle.SHORT, enUS, "Sun"},
+
+            {DAY_OF_WEEK, 1, TextStyle.SHORT, ptBR, "Seg"},
+            {DAY_OF_WEEK, 2, TextStyle.SHORT, ptBR, "Ter"},
+            {DAY_OF_WEEK, 3, TextStyle.SHORT, ptBR, "Qua"},
+            {DAY_OF_WEEK, 4, TextStyle.SHORT, ptBR, "Qui"},
+            {DAY_OF_WEEK, 5, TextStyle.SHORT, ptBR, "Sex"},
+            {DAY_OF_WEEK, 6, TextStyle.SHORT, ptBR, "S\u00E1b"},
+            {DAY_OF_WEEK, 7, TextStyle.SHORT, ptBR, "Dom"},
+
+            {DAY_OF_WEEK, 1, TextStyle.FULL, enUS, "Monday"},
+            {DAY_OF_WEEK, 2, TextStyle.FULL, enUS, "Tuesday"},
+            {DAY_OF_WEEK, 3, TextStyle.FULL, enUS, "Wednesday"},
+            {DAY_OF_WEEK, 4, TextStyle.FULL, enUS, "Thursday"},
+            {DAY_OF_WEEK, 5, TextStyle.FULL, enUS, "Friday"},
+            {DAY_OF_WEEK, 6, TextStyle.FULL, enUS, "Saturday"},
+            {DAY_OF_WEEK, 7, TextStyle.FULL, enUS, "Sunday"},
+
+            {DAY_OF_WEEK, 1, TextStyle.FULL, ptBR, "Segunda-feira"},
+            {DAY_OF_WEEK, 2, TextStyle.FULL, ptBR, "Ter\u00E7a-feira"},
+            {DAY_OF_WEEK, 3, TextStyle.FULL, ptBR, "Quarta-feira"},
+            {DAY_OF_WEEK, 4, TextStyle.FULL, ptBR, "Quinta-feira"},
+            {DAY_OF_WEEK, 5, TextStyle.FULL, ptBR, "Sexta-feira"},
+            {DAY_OF_WEEK, 6, TextStyle.FULL, ptBR, "S\u00E1bado"},
+            {DAY_OF_WEEK, 7, TextStyle.FULL, ptBR, "Domingo"},
+
+            {MONTH_OF_YEAR, 1, TextStyle.SHORT, enUS, "Jan"},
+            {MONTH_OF_YEAR, 2, TextStyle.SHORT, enUS, "Feb"},
+            {MONTH_OF_YEAR, 3, TextStyle.SHORT, enUS, "Mar"},
+            {MONTH_OF_YEAR, 4, TextStyle.SHORT, enUS, "Apr"},
+            {MONTH_OF_YEAR, 5, TextStyle.SHORT, enUS, "May"},
+            {MONTH_OF_YEAR, 6, TextStyle.SHORT, enUS, "Jun"},
+            {MONTH_OF_YEAR, 7, TextStyle.SHORT, enUS, "Jul"},
+            {MONTH_OF_YEAR, 8, TextStyle.SHORT, enUS, "Aug"},
+            {MONTH_OF_YEAR, 9, TextStyle.SHORT, enUS, "Sep"},
+            {MONTH_OF_YEAR, 10, TextStyle.SHORT, enUS, "Oct"},
+            {MONTH_OF_YEAR, 11, TextStyle.SHORT, enUS, "Nov"},
+            {MONTH_OF_YEAR, 12, TextStyle.SHORT, enUS, "Dec"},
+
+            {MONTH_OF_YEAR, 1, TextStyle.SHORT, ptBR, "Jan"},
+            {MONTH_OF_YEAR, 2, TextStyle.SHORT, ptBR, "Fev"},
+            {MONTH_OF_YEAR, 3, TextStyle.SHORT, ptBR, "Mar"},
+            {MONTH_OF_YEAR, 4, TextStyle.SHORT, ptBR, "Abr"},
+            {MONTH_OF_YEAR, 5, TextStyle.SHORT, ptBR, "Mai"},
+            {MONTH_OF_YEAR, 6, TextStyle.SHORT, ptBR, "Jun"},
+            {MONTH_OF_YEAR, 7, TextStyle.SHORT, ptBR, "Jul"},
+            {MONTH_OF_YEAR, 8, TextStyle.SHORT, ptBR, "Ago"},
+            {MONTH_OF_YEAR, 9, TextStyle.SHORT, ptBR, "Set"},
+            {MONTH_OF_YEAR, 10, TextStyle.SHORT, ptBR, "Out"},
+            {MONTH_OF_YEAR, 11, TextStyle.SHORT, ptBR, "Nov"},
+            {MONTH_OF_YEAR, 12, TextStyle.SHORT, ptBR, "Dez"},
+
+            {MONTH_OF_YEAR, 1, TextStyle.FULL, enUS, "January"},
+            {MONTH_OF_YEAR, 2, TextStyle.FULL, enUS, "February"},
+            {MONTH_OF_YEAR, 3, TextStyle.FULL, enUS, "March"},
+            {MONTH_OF_YEAR, 4, TextStyle.FULL, enUS, "April"},
+            {MONTH_OF_YEAR, 5, TextStyle.FULL, enUS, "May"},
+            {MONTH_OF_YEAR, 6, TextStyle.FULL, enUS, "June"},
+            {MONTH_OF_YEAR, 7, TextStyle.FULL, enUS, "July"},
+            {MONTH_OF_YEAR, 8, TextStyle.FULL, enUS, "August"},
+            {MONTH_OF_YEAR, 9, TextStyle.FULL, enUS, "September"},
+            {MONTH_OF_YEAR, 10, TextStyle.FULL, enUS, "October"},
+            {MONTH_OF_YEAR, 11, TextStyle.FULL, enUS, "November"},
+            {MONTH_OF_YEAR, 12, TextStyle.FULL, enUS, "December"},
+
+            {MONTH_OF_YEAR, 1, TextStyle.FULL, ptBR, "Janeiro"},
+            {MONTH_OF_YEAR, 2, TextStyle.FULL, ptBR, "Fevereiro"},
+            {MONTH_OF_YEAR, 3, TextStyle.FULL, ptBR, "Mar\u00E7o"},
+            {MONTH_OF_YEAR, 4, TextStyle.FULL, ptBR, "Abril"},
+            {MONTH_OF_YEAR, 5, TextStyle.FULL, ptBR, "Maio"},
+            {MONTH_OF_YEAR, 6, TextStyle.FULL, ptBR, "Junho"},
+            {MONTH_OF_YEAR, 7, TextStyle.FULL, ptBR, "Julho"},
+            {MONTH_OF_YEAR, 8, TextStyle.FULL, ptBR, "Agosto"},
+            {MONTH_OF_YEAR, 9, TextStyle.FULL, ptBR, "Setembro"},
+            {MONTH_OF_YEAR, 10, TextStyle.FULL, ptBR, "Outubro"},
+            {MONTH_OF_YEAR, 11, TextStyle.FULL, ptBR, "Novembro"},
+            {MONTH_OF_YEAR, 12, TextStyle.FULL, ptBR, "Dezembro"},
+
+            {AMPM_OF_DAY, 0, TextStyle.SHORT, enUS, "AM"},
+            {AMPM_OF_DAY, 1, TextStyle.SHORT, enUS, "PM"},
+
+        };
+    }
+
+    @Test(dataProvider = "Text")
+    public void test_getText(TemporalField field, Number value, TextStyle style, Locale locale, String expected) {
+          DateTimeFormatter fmt = getFormatter(field, style).withLocale(locale);
+          assertEquals(fmt.print(ZonedDateTime.now().with(field, value.longValue())), expected);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/format/TestFractionPrinterParser.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.format;
+
+import java.time.format.*;
+
+import static java.time.temporal.ChronoField.NANO_OF_SECOND;
+import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+
+import java.text.ParsePosition;
+import java.time.DateTimeException;
+import java.time.LocalTime;
+import java.time.format.DateTimeBuilder;
+import java.time.temporal.TemporalField;
+
+import test.java.time.temporal.MockFieldValue;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test FractionPrinterParser.
+ */
+@Test(groups={"implementation"})
+public class TestFractionPrinterParser extends AbstractTestPrinterParser {
+
+    private DateTimeFormatter getFormatter(TemporalField field, int minWidth, int maxWidth, boolean decimalPoint) {
+        return builder.appendFraction(field, minWidth, maxWidth, decimalPoint).toFormatter(locale).withSymbols(symbols);
+    }
+
+    //-----------------------------------------------------------------------
+    // print
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=DateTimeException.class)
+    public void test_print_emptyCalendrical() throws Exception {
+        getFormatter(NANO_OF_SECOND, 0, 9, true).printTo(EMPTY_DTA, buf);
+    }
+
+    public void test_print_append() throws Exception {
+        buf.append("EXISTING");
+        getFormatter(NANO_OF_SECOND, 0, 9, true).printTo(LocalTime.of(12, 30, 40, 3), buf);
+        assertEquals(buf.toString(), "EXISTING.000000003");
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="Nanos")
+    Object[][] provider_nanos() {
+        return new Object[][] {
+            {0, 9, 0,           ""},
+            {0, 9, 2,           ".000000002"},
+            {0, 9, 20,          ".00000002"},
+            {0, 9, 200,         ".0000002"},
+            {0, 9, 2000,        ".000002"},
+            {0, 9, 20000,       ".00002"},
+            {0, 9, 200000,      ".0002"},
+            {0, 9, 2000000,     ".002"},
+            {0, 9, 20000000,    ".02"},
+            {0, 9, 200000000,   ".2"},
+            {0, 9, 1,           ".000000001"},
+            {0, 9, 12,          ".000000012"},
+            {0, 9, 123,         ".000000123"},
+            {0, 9, 1234,        ".000001234"},
+            {0, 9, 12345,       ".000012345"},
+            {0, 9, 123456,      ".000123456"},
+            {0, 9, 1234567,     ".001234567"},
+            {0, 9, 12345678,    ".012345678"},
+            {0, 9, 123456789,   ".123456789"},
+
+            {1, 9, 0,           ".0"},
+            {1, 9, 2,           ".000000002"},
+            {1, 9, 20,          ".00000002"},
+            {1, 9, 200,         ".0000002"},
+            {1, 9, 2000,        ".000002"},
+            {1, 9, 20000,       ".00002"},
+            {1, 9, 200000,      ".0002"},
+            {1, 9, 2000000,     ".002"},
+            {1, 9, 20000000,    ".02"},
+            {1, 9, 200000000,   ".2"},
+
+            {2, 3, 0,           ".00"},
+            {2, 3, 2,           ".000"},
+            {2, 3, 20,          ".000"},
+            {2, 3, 200,         ".000"},
+            {2, 3, 2000,        ".000"},
+            {2, 3, 20000,       ".000"},
+            {2, 3, 200000,      ".000"},
+            {2, 3, 2000000,     ".002"},
+            {2, 3, 20000000,    ".02"},
+            {2, 3, 200000000,   ".20"},
+            {2, 3, 1,           ".000"},
+            {2, 3, 12,          ".000"},
+            {2, 3, 123,         ".000"},
+            {2, 3, 1234,        ".000"},
+            {2, 3, 12345,       ".000"},
+            {2, 3, 123456,      ".000"},
+            {2, 3, 1234567,     ".001"},
+            {2, 3, 12345678,    ".012"},
+            {2, 3, 123456789,   ".123"},
+
+            {6, 6, 0,           ".000000"},
+            {6, 6, 2,           ".000000"},
+            {6, 6, 20,          ".000000"},
+            {6, 6, 200,         ".000000"},
+            {6, 6, 2000,        ".000002"},
+            {6, 6, 20000,       ".000020"},
+            {6, 6, 200000,      ".000200"},
+            {6, 6, 2000000,     ".002000"},
+            {6, 6, 20000000,    ".020000"},
+            {6, 6, 200000000,   ".200000"},
+            {6, 6, 1,           ".000000"},
+            {6, 6, 12,          ".000000"},
+            {6, 6, 123,         ".000000"},
+            {6, 6, 1234,        ".000001"},
+            {6, 6, 12345,       ".000012"},
+            {6, 6, 123456,      ".000123"},
+            {6, 6, 1234567,     ".001234"},
+            {6, 6, 12345678,    ".012345"},
+            {6, 6, 123456789,   ".123456"},
+       };
+    }
+
+    @Test(dataProvider="Nanos")
+    public void test_print_nanos(int minWidth, int maxWidth, int value, String result) throws Exception {
+        getFormatter(NANO_OF_SECOND,  minWidth, maxWidth, true).printTo(new MockFieldValue(NANO_OF_SECOND, value), buf);
+        if (result == null) {
+            fail("Expected exception");
+        }
+        assertEquals(buf.toString(), result);
+    }
+
+    @Test(dataProvider="Nanos")
+    public void test_print_nanos_noDecimalPoint(int minWidth, int maxWidth, int value, String result) throws Exception {
+        getFormatter(NANO_OF_SECOND,  minWidth, maxWidth, false).printTo(new MockFieldValue(NANO_OF_SECOND, value), buf);
+        if (result == null) {
+            fail("Expected exception");
+        }
+        assertEquals(buf.toString(), (result.startsWith(".") ? result.substring(1) : result));
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="Seconds")
+    Object[][] provider_seconds() {
+        return new Object[][] {
+            {0, 9, 0,  ""},
+            {0, 9, 3,  ".05"},
+            {0, 9, 6,  ".1"},
+            {0, 9, 9,  ".15"},
+            {0, 9, 12, ".2"},
+            {0, 9, 15, ".25"},
+            {0, 9, 30, ".5"},
+            {0, 9, 45, ".75"},
+
+            {2, 2, 0,  ".00"},
+            {2, 2, 3,  ".05"},
+            {2, 2, 6,  ".10"},
+            {2, 2, 9,  ".15"},
+            {2, 2, 12, ".20"},
+            {2, 2, 15, ".25"},
+            {2, 2, 30, ".50"},
+            {2, 2, 45, ".75"},
+        };
+    }
+
+    @Test(dataProvider="Seconds")
+    public void test_print_seconds(int minWidth, int maxWidth, int value, String result) throws Exception {
+        getFormatter(SECOND_OF_MINUTE, minWidth, maxWidth, true).printTo(new MockFieldValue(SECOND_OF_MINUTE, value), buf);
+        if (result == null) {
+            fail("Expected exception");
+        }
+        assertEquals(buf.toString(), result);
+    }
+
+    @Test(dataProvider="Seconds")
+    public void test_print_seconds_noDecimalPoint(int minWidth, int maxWidth, int value, String result) throws Exception {
+        getFormatter(SECOND_OF_MINUTE, minWidth, maxWidth, false).printTo(new MockFieldValue(SECOND_OF_MINUTE, value), buf);
+        if (result == null) {
+            fail("Expected exception");
+        }
+        assertEquals(buf.toString(), (result.startsWith(".") ? result.substring(1) : result));
+    }
+
+    //-----------------------------------------------------------------------
+    // parse
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="Nanos")
+    public void test_reverseParse(int minWidth, int maxWidth, int value, String result) throws Exception {
+        ParsePosition pos = new ParsePosition(0);
+        int expectedValue = fixParsedValue(maxWidth, value);
+        DateTimeBuilder dtb = getFormatter(NANO_OF_SECOND, minWidth, maxWidth, true).parseToBuilder(result, pos);
+        assertEquals(pos.getIndex(), result.length());
+        assertParsed(dtb, NANO_OF_SECOND, value == 0 && minWidth == 0 ? null : (long) expectedValue);
+    }
+
+    @Test(dataProvider="Nanos")
+    public void test_reverseParse_noDecimalPoint(int minWidth, int maxWidth, int value, String result) throws Exception {
+        ParsePosition pos = new ParsePosition((result.startsWith(".") ? 1 : 0));
+        DateTimeBuilder dtb = getFormatter(NANO_OF_SECOND, minWidth, maxWidth, false).parseToBuilder(result, pos);
+        assertEquals(pos.getIndex(), result.length());
+        int expectedValue = fixParsedValue(maxWidth, value);
+        assertParsed(dtb, NANO_OF_SECOND, value == 0 && minWidth == 0 ? null : (long) expectedValue);
+    }
+
+    @Test(dataProvider="Nanos")
+    public void test_reverseParse_followedByNonDigit(int minWidth, int maxWidth, int value, String result) throws Exception {
+        ParsePosition pos = new ParsePosition(0);
+        int expectedValue = fixParsedValue(maxWidth, value);
+        DateTimeBuilder dtb = getFormatter(NANO_OF_SECOND, minWidth, maxWidth, true).parseToBuilder(result + " ", pos);
+        assertEquals(pos.getIndex(), result.length());
+        assertParsed(dtb, NANO_OF_SECOND, value == 0 && minWidth == 0 ? null : (long) expectedValue);
+    }
+
+//    @Test(dataProvider="Nanos")
+//    public void test_reverseParse_followedByNonDigit_noDecimalPoint(int minWidth, int maxWidth, int value, String result) throws Exception {
+//        FractionPrinterParser pp = new FractionPrinterParser(NANO_OF_SECOND, minWidth, maxWidth, false);
+//        int newPos = pp.parse(parseContext, result + " ", (result.startsWith(".") ? 1 : 0));
+//        assertEquals(newPos, result.length());
+//        int expectedValue = fixParsedValue(maxWidth, value);
+//        assertParsed(parseContext, NANO_OF_SECOND, value == 0 && minWidth == 0 ? null : (long) expectedValue);
+//    }
+
+    @Test(dataProvider="Nanos")
+    public void test_reverseParse_preceededByNonDigit(int minWidth, int maxWidth, int value, String result) throws Exception {
+        ParsePosition pos = new ParsePosition(1);
+        int expectedValue = fixParsedValue(maxWidth, value);
+        DateTimeBuilder dtb = getFormatter(NANO_OF_SECOND, minWidth, maxWidth, true).parseToBuilder(" " + result, pos);
+        assertEquals(pos.getIndex(), result.length() + 1);
+        assertParsed(dtb, NANO_OF_SECOND, value == 0 && minWidth == 0 ? null : (long) expectedValue);
+    }
+
+    private int fixParsedValue(int maxWidth, int value) {
+        if (maxWidth < 9) {
+            int power = (int) Math.pow(10, (9 - maxWidth));
+            value = (value / power) * power;
+        }
+        return value;
+    }
+
+    @Test(dataProvider="Seconds")
+    public void test_reverseParse_seconds(int minWidth, int maxWidth, int value, String result) throws Exception {
+        ParsePosition pos = new ParsePosition(0);
+        DateTimeBuilder dtb = getFormatter(SECOND_OF_MINUTE, minWidth, maxWidth, true).parseToBuilder(result, pos);
+        assertEquals(pos.getIndex(), result.length());
+        assertParsed(dtb, SECOND_OF_MINUTE, value == 0 && minWidth == 0 ? null : (long) value);
+    }
+
+    private void assertParsed(DateTimeBuilder dtb, TemporalField field, Long value) {
+        if (value == null) {
+            assertEquals(dtb.containsFieldValue(field), false);
+        } else {
+            assertEquals(dtb.getLong(field), (long)value);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="ParseNothing")
+    Object[][] provider_parseNothing() {
+        return new Object[][] {
+            {NANO_OF_SECOND, 3, 6, true, "", 0, 0},
+            {NANO_OF_SECOND, 3, 6, true, "A", 0, 0},
+            {NANO_OF_SECOND, 3, 6, true, ".", 0, 1},
+            {NANO_OF_SECOND, 3, 6, true, ".5", 0, 1},
+            {NANO_OF_SECOND, 3, 6, true, ".51", 0, 1},
+            {NANO_OF_SECOND, 3, 6, true, ".A23456", 0, 1},
+            {NANO_OF_SECOND, 3, 6, true, ".1A3456", 0, 1},
+        };
+    }
+
+    @Test(dataProvider = "ParseNothing")
+    public void test_parse_nothing(TemporalField field, int min, int max, boolean decimalPoint, String text, int pos, int expected) {
+        ParsePosition ppos = new ParsePosition(pos);
+        DateTimeBuilder dtb = getFormatter(field, min, max, decimalPoint).parseToBuilder(text, ppos);
+        assertEquals(ppos.getErrorIndex(), expected);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_toString() throws Exception {
+        assertEquals(getFormatter(NANO_OF_SECOND, 3, 6, true).toString(), "Fraction(NanoOfSecond,3,6,DecimalPoint)");
+    }
+
+    public void test_toString_noDecimalPoint() throws Exception {
+        assertEquals(getFormatter(NANO_OF_SECOND, 3, 6, false).toString(), "Fraction(NanoOfSecond,3,6)");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/format/TestNumberParser.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,547 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.format;
+
+import java.time.format.*;
+
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.DAY_OF_WEEK;
+import static java.time.temporal.ChronoField.DAY_OF_YEAR;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.text.ParsePosition;
+import java.time.format.DateTimeBuilder;
+import java.time.temporal.TemporalField;
+import java.time.format.DateTimeFormatter;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test NumberPrinterParser.
+ */
+@Test(groups={"implementation"})
+public class TestNumberParser extends AbstractTestPrinterParser {
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="error")
+    Object[][] data_error() {
+        return new Object[][] {
+            {DAY_OF_MONTH, 1, 2, SignStyle.NEVER, "12", -1, IndexOutOfBoundsException.class},
+            {DAY_OF_MONTH, 1, 2, SignStyle.NEVER, "12", 3, IndexOutOfBoundsException.class},
+        };
+    }
+
+    @Test(dataProvider="error")
+    public void test_parse_error(TemporalField field, int min, int max, SignStyle style, String text, int pos, Class<?> expected) {
+        try {
+            getFormatter(field, min, max, style).parseToBuilder(text, new ParsePosition(pos));
+            assertTrue(false);
+        } catch (RuntimeException ex) {
+            assertTrue(expected.isInstance(ex));
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="parseData")
+    Object[][] provider_parseData() {
+        return new Object[][] {
+            // normal
+            {1, 2, SignStyle.NEVER, 0, "12", 0, 2, 12L},       // normal
+            {1, 2, SignStyle.NEVER, 0, "Xxx12Xxx", 3, 5, 12L}, // parse in middle
+            {1, 2, SignStyle.NEVER, 0, "99912999", 3, 5, 12L}, // parse in middle
+            {2, 4, SignStyle.NEVER, 0, "12345", 0, 4, 1234L},  // stops at max width
+            {2, 4, SignStyle.NEVER, 0, "12-45", 0, 2, 12L},    // stops at dash
+            {2, 4, SignStyle.NEVER, 0, "123-5", 0, 3, 123L},   // stops at dash
+            {1, 10, SignStyle.NORMAL, 0, "2147483647", 0, 10, Integer.MAX_VALUE},
+            {1, 10, SignStyle.NORMAL, 0, "-2147483648", 0, 11, Integer.MIN_VALUE},
+            {1, 10, SignStyle.NORMAL, 0, "2147483648", 0, 10, 2147483648L},
+            {1, 10, SignStyle.NORMAL, 0, "-2147483649", 0, 11, -2147483649L},
+            {1, 10, SignStyle.NORMAL, 0, "987659876598765", 0, 10, 9876598765L},
+            {1, 19, SignStyle.NORMAL, 0, "999999999999999999", 0, 18, 999999999999999999L},
+            {1, 19, SignStyle.NORMAL, 0, "-999999999999999999", 0, 19, -999999999999999999L},
+            {1, 19, SignStyle.NORMAL, 0, "1000000000000000000", 0, 19, 1000000000000000000L},
+            {1, 19, SignStyle.NORMAL, 0, "-1000000000000000000", 0, 20, -1000000000000000000L},
+            {1, 19, SignStyle.NORMAL, 0, "000000000000000000", 0, 18, 0L},
+            {1, 19, SignStyle.NORMAL, 0, "0000000000000000000", 0, 19, 0L},
+            {1, 19, SignStyle.NORMAL, 0, "9223372036854775807", 0, 19, Long.MAX_VALUE},
+            {1, 19, SignStyle.NORMAL, 0, "-9223372036854775808", 0, 20, Long.MIN_VALUE},
+            {1, 19, SignStyle.NORMAL, 0, "9223372036854775808", 0, 18, 922337203685477580L},  // last digit not parsed
+            {1, 19, SignStyle.NORMAL, 0, "-9223372036854775809", 0, 19, -922337203685477580L}, // last digit not parsed
+            // no match
+            {1, 2, SignStyle.NEVER, 1, "A1", 0, 0, 0},
+            {1, 2, SignStyle.NEVER, 1, " 1", 0, 0, 0},
+            {1, 2, SignStyle.NEVER, 1, "  1", 1, 1, 0},
+            {2, 2, SignStyle.NEVER, 1, "1", 0, 0, 0},
+            {2, 2, SignStyle.NEVER, 1, "Xxx1", 0, 0, 0},
+            {2, 2, SignStyle.NEVER, 1, "1", 1, 1, 0},
+            {2, 2, SignStyle.NEVER, 1, "Xxx1", 4, 4, 0},
+            {2, 2, SignStyle.NEVER, 1, "1-2", 0, 0, 0},
+            {1, 19, SignStyle.NORMAL, 0, "-000000000000000000", 0, 0, 0},
+            {1, 19, SignStyle.NORMAL, 0, "-0000000000000000000", 0, 0, 0},
+            // parse reserving space 1 (adjacent-parsing)
+            {1, 1, SignStyle.NEVER, 1, "12", 0, 1, 1L},
+            {1, 19, SignStyle.NEVER, 1, "12", 0, 1, 1L},
+            {1, 19, SignStyle.NEVER, 1, "12345", 0, 4, 1234L},
+            {1, 19, SignStyle.NEVER, 1, "12345678901", 0, 10, 1234567890L},
+            {1, 19, SignStyle.NEVER, 1, "123456789012345678901234567890", 0, 19, 1234567890123456789L},
+            {1, 19, SignStyle.NEVER, 1, "1", 0, 1, 1L},  // error from next field
+            {2, 2, SignStyle.NEVER, 1, "12", 0, 2, 12L},  // error from next field
+            {2, 19, SignStyle.NEVER, 1, "1", 0, 0, 0},
+            // parse reserving space 2 (adjacent-parsing)
+            {1, 1, SignStyle.NEVER, 2, "123", 0, 1, 1L},
+            {1, 19, SignStyle.NEVER, 2, "123", 0, 1, 1L},
+            {1, 19, SignStyle.NEVER, 2, "12345", 0, 3, 123L},
+            {1, 19, SignStyle.NEVER, 2, "12345678901", 0, 9, 123456789L},
+            {1, 19, SignStyle.NEVER, 2, "123456789012345678901234567890", 0, 19, 1234567890123456789L},
+            {1, 19, SignStyle.NEVER, 2, "1", 0, 1, 1L},  // error from next field
+            {1, 19, SignStyle.NEVER, 2, "12", 0, 1, 1L},  // error from next field
+            {2, 2, SignStyle.NEVER, 2, "12", 0, 2, 12L},  // error from next field
+            {2, 19, SignStyle.NEVER, 2, "1", 0, 0, 0},
+            {2, 19, SignStyle.NEVER, 2, "1AAAAABBBBBCCCCC", 0, 0, 0},
+        };
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="parseData")
+    public void test_parse_fresh(int minWidth, int maxWidth, SignStyle signStyle, int subsequentWidth, String text, int pos, int expectedPos, long expectedValue) {
+        ParsePosition ppos = new ParsePosition(pos);
+        DateTimeFormatter dtf = getFormatter(DAY_OF_MONTH, minWidth, maxWidth, signStyle);
+        if (subsequentWidth > 0) {
+            // hacky, to reserve space
+            dtf = builder.appendValue(DAY_OF_YEAR, subsequentWidth).toFormatter(locale).withSymbols(symbols);
+        }
+        DateTimeBuilder dtb = dtf.parseToBuilder(text, ppos);
+        if (ppos.getErrorIndex() != -1) {
+            assertEquals(ppos.getErrorIndex(), expectedPos);
+        } else {
+            assertTrue(subsequentWidth >= 0);
+            assertEquals(ppos.getIndex(), expectedPos + subsequentWidth);
+            assertEquals(dtb.getLong(DAY_OF_MONTH), expectedValue);
+        }
+    }
+
+    @Test(dataProvider="parseData")
+    public void test_parse_textField(int minWidth, int maxWidth, SignStyle signStyle, int subsequentWidth, String text, int pos, int expectedPos, long expectedValue) {
+        ParsePosition ppos = new ParsePosition(pos);
+        DateTimeFormatter dtf = getFormatter(DAY_OF_WEEK, minWidth, maxWidth, signStyle);
+        if (subsequentWidth > 0) {
+            // hacky, to reserve space
+            dtf = builder.appendValue(DAY_OF_YEAR, subsequentWidth).toFormatter(locale).withSymbols(symbols);
+        }
+        DateTimeBuilder dtb = dtf.parseToBuilder(text, ppos);
+        if (ppos.getErrorIndex() != -1) {
+            assertEquals(ppos.getErrorIndex(), expectedPos);
+        } else {
+            assertTrue(subsequentWidth >= 0);
+            assertEquals(ppos.getIndex(), expectedPos + subsequentWidth);
+            assertEquals(dtb.getLong(DAY_OF_WEEK), expectedValue);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="parseSignsStrict")
+    Object[][] provider_parseSignsStrict() {
+        return new Object[][] {
+            // basics
+            {"0", 1, 2, SignStyle.NEVER, 1, 0},
+            {"1", 1, 2, SignStyle.NEVER, 1, 1},
+            {"2", 1, 2, SignStyle.NEVER, 1, 2},
+            {"3", 1, 2, SignStyle.NEVER, 1, 3},
+            {"4", 1, 2, SignStyle.NEVER, 1, 4},
+            {"5", 1, 2, SignStyle.NEVER, 1, 5},
+            {"6", 1, 2, SignStyle.NEVER, 1, 6},
+            {"7", 1, 2, SignStyle.NEVER, 1, 7},
+            {"8", 1, 2, SignStyle.NEVER, 1, 8},
+            {"9", 1, 2, SignStyle.NEVER, 1, 9},
+            {"10", 1, 2, SignStyle.NEVER, 2, 10},
+            {"100", 1, 2, SignStyle.NEVER, 2, 10},
+            {"100", 1, 3, SignStyle.NEVER, 3, 100},
+
+            // never
+            {"0", 1, 2, SignStyle.NEVER, 1, 0},
+            {"5", 1, 2, SignStyle.NEVER, 1, 5},
+            {"50", 1, 2, SignStyle.NEVER, 2, 50},
+            {"500", 1, 2, SignStyle.NEVER, 2, 50},
+            {"-0", 1, 2, SignStyle.NEVER, 0, null},
+            {"-5", 1, 2, SignStyle.NEVER, 0, null},
+            {"-50", 1, 2, SignStyle.NEVER, 0, null},
+            {"-500", 1, 2, SignStyle.NEVER, 0, null},
+            {"-AAA", 1, 2, SignStyle.NEVER, 0, null},
+            {"+0", 1, 2, SignStyle.NEVER, 0, null},
+            {"+5", 1, 2, SignStyle.NEVER, 0, null},
+            {"+50", 1, 2, SignStyle.NEVER, 0, null},
+            {"+500", 1, 2, SignStyle.NEVER, 0, null},
+            {"+AAA", 1, 2, SignStyle.NEVER, 0, null},
+
+            // not negative
+            {"0", 1, 2, SignStyle.NOT_NEGATIVE, 1, 0},
+            {"5", 1, 2, SignStyle.NOT_NEGATIVE, 1, 5},
+            {"50", 1, 2, SignStyle.NOT_NEGATIVE, 2, 50},
+            {"500", 1, 2, SignStyle.NOT_NEGATIVE, 2, 50},
+            {"-0", 1, 2, SignStyle.NOT_NEGATIVE, 0, null},
+            {"-5", 1, 2, SignStyle.NOT_NEGATIVE, 0, null},
+            {"-50", 1, 2, SignStyle.NOT_NEGATIVE, 0, null},
+            {"-500", 1, 2, SignStyle.NOT_NEGATIVE, 0, null},
+            {"-AAA", 1, 2, SignStyle.NOT_NEGATIVE, 0, null},
+            {"+0", 1, 2, SignStyle.NOT_NEGATIVE, 0, null},
+            {"+5", 1, 2, SignStyle.NOT_NEGATIVE, 0, null},
+            {"+50", 1, 2, SignStyle.NOT_NEGATIVE, 0, null},
+            {"+500", 1, 2, SignStyle.NOT_NEGATIVE, 0, null},
+            {"+AAA", 1, 2, SignStyle.NOT_NEGATIVE, 0, null},
+
+            // normal
+            {"0", 1, 2, SignStyle.NORMAL, 1, 0},
+            {"5", 1, 2, SignStyle.NORMAL, 1, 5},
+            {"50", 1, 2, SignStyle.NORMAL, 2, 50},
+            {"500", 1, 2, SignStyle.NORMAL, 2, 50},
+            {"-0", 1, 2, SignStyle.NORMAL, 0, null},
+            {"-5", 1, 2, SignStyle.NORMAL, 2, -5},
+            {"-50", 1, 2, SignStyle.NORMAL, 3, -50},
+            {"-500", 1, 2, SignStyle.NORMAL, 3, -50},
+            {"-AAA", 1, 2, SignStyle.NORMAL, 1, null},
+            {"+0", 1, 2, SignStyle.NORMAL, 0, null},
+            {"+5", 1, 2, SignStyle.NORMAL, 0, null},
+            {"+50", 1, 2, SignStyle.NORMAL, 0, null},
+            {"+500", 1, 2, SignStyle.NORMAL, 0, null},
+            {"+AAA", 1, 2, SignStyle.NORMAL, 0, null},
+
+            // always
+            {"0", 1, 2, SignStyle.ALWAYS, 0, null},
+            {"5", 1, 2, SignStyle.ALWAYS, 0, null},
+            {"50", 1, 2, SignStyle.ALWAYS, 0, null},
+            {"500", 1, 2, SignStyle.ALWAYS, 0, null},
+            {"-0", 1, 2, SignStyle.ALWAYS, 0, null},
+            {"-5", 1, 2, SignStyle.ALWAYS, 2, -5},
+            {"-50", 1, 2, SignStyle.ALWAYS, 3, -50},
+            {"-500", 1, 2, SignStyle.ALWAYS, 3, -50},
+            {"-AAA", 1, 2, SignStyle.ALWAYS, 1, null},
+            {"+0", 1, 2, SignStyle.ALWAYS, 2, 0},
+            {"+5", 1, 2, SignStyle.ALWAYS, 2, 5},
+            {"+50", 1, 2, SignStyle.ALWAYS, 3, 50},
+            {"+500", 1, 2, SignStyle.ALWAYS, 3, 50},
+            {"+AAA", 1, 2, SignStyle.ALWAYS, 1, null},
+
+            // exceeds pad
+            {"0", 1, 2, SignStyle.EXCEEDS_PAD, 1, 0},
+            {"5", 1, 2, SignStyle.EXCEEDS_PAD, 1, 5},
+            {"50", 1, 2, SignStyle.EXCEEDS_PAD, 0, null},
+            {"500", 1, 2, SignStyle.EXCEEDS_PAD, 0, null},
+            {"-0", 1, 2, SignStyle.EXCEEDS_PAD, 0, null},
+            {"-5", 1, 2, SignStyle.EXCEEDS_PAD, 2, -5},
+            {"-50", 1, 2, SignStyle.EXCEEDS_PAD, 3, -50},
+            {"-500", 1, 2, SignStyle.EXCEEDS_PAD, 3, -50},
+            {"-AAA", 1, 2, SignStyle.EXCEEDS_PAD, 1, null},
+            {"+0", 1, 2, SignStyle.EXCEEDS_PAD, 0, null},
+            {"+5", 1, 2, SignStyle.EXCEEDS_PAD, 0, null},
+            {"+50", 1, 2, SignStyle.EXCEEDS_PAD, 3, 50},
+            {"+500", 1, 2, SignStyle.EXCEEDS_PAD, 3, 50},
+            {"+AAA", 1, 2, SignStyle.EXCEEDS_PAD, 1, null},
+       };
+    }
+
+    @Test(dataProvider="parseSignsStrict")
+    public void test_parseSignsStrict(String input, int min, int max, SignStyle style, int parseLen, Integer parseVal) throws Exception {
+        ParsePosition pos = new ParsePosition(0);
+        DateTimeBuilder dtb = getFormatter(DAY_OF_MONTH, min, max, style).parseToBuilder(input, pos);
+        if (pos.getErrorIndex() != -1) {
+            assertEquals(pos.getErrorIndex(), parseLen);
+        } else {
+            assertEquals(pos.getIndex(), parseLen);
+            assertEquals(dtb.getLong(DAY_OF_MONTH), (long)parseVal);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="parseSignsLenient")
+    Object[][] provider_parseSignsLenient() {
+        return new Object[][] {
+            // never
+            {"0", 1, 2, SignStyle.NEVER, 1, 0},
+            {"5", 1, 2, SignStyle.NEVER, 1, 5},
+            {"50", 1, 2, SignStyle.NEVER, 2, 50},
+            {"500", 1, 2, SignStyle.NEVER, 2, 50},
+            {"-0", 1, 2, SignStyle.NEVER, 2, 0},
+            {"-5", 1, 2, SignStyle.NEVER, 2, -5},
+            {"-50", 1, 2, SignStyle.NEVER, 3, -50},
+            {"-500", 1, 2, SignStyle.NEVER, 3, -50},
+            {"-AAA", 1, 2, SignStyle.NEVER, 1, null},
+            {"+0", 1, 2, SignStyle.NEVER, 2, 0},
+            {"+5", 1, 2, SignStyle.NEVER, 2, 5},
+            {"+50", 1, 2, SignStyle.NEVER, 3, 50},
+            {"+500", 1, 2, SignStyle.NEVER, 3, 50},
+            {"+AAA", 1, 2, SignStyle.NEVER, 1, null},
+            {"50", 2, 2, SignStyle.NEVER, 2, 50},
+            {"-50", 2, 2, SignStyle.NEVER, 0, null},
+            {"+50", 2, 2, SignStyle.NEVER, 0, null},
+
+            // not negative
+            {"0", 1, 2, SignStyle.NOT_NEGATIVE, 1, 0},
+            {"5", 1, 2, SignStyle.NOT_NEGATIVE, 1, 5},
+            {"50", 1, 2, SignStyle.NOT_NEGATIVE, 2, 50},
+            {"500", 1, 2, SignStyle.NOT_NEGATIVE, 2, 50},
+            {"-0", 1, 2, SignStyle.NOT_NEGATIVE, 2, 0},
+            {"-5", 1, 2, SignStyle.NOT_NEGATIVE, 2, -5},
+            {"-50", 1, 2, SignStyle.NOT_NEGATIVE, 3, -50},
+            {"-500", 1, 2, SignStyle.NOT_NEGATIVE, 3, -50},
+            {"-AAA", 1, 2, SignStyle.NOT_NEGATIVE, 1, null},
+            {"+0", 1, 2, SignStyle.NOT_NEGATIVE, 2, 0},
+            {"+5", 1, 2, SignStyle.NOT_NEGATIVE, 2, 5},
+            {"+50", 1, 2, SignStyle.NOT_NEGATIVE, 3, 50},
+            {"+500", 1, 2, SignStyle.NOT_NEGATIVE, 3, 50},
+            {"+AAA", 1, 2, SignStyle.NOT_NEGATIVE, 1, null},
+            {"50", 2, 2, SignStyle.NOT_NEGATIVE, 2, 50},
+            {"-50", 2, 2, SignStyle.NOT_NEGATIVE, 0, null},
+            {"+50", 2, 2, SignStyle.NOT_NEGATIVE, 0, null},
+
+            // normal
+            {"0", 1, 2, SignStyle.NORMAL, 1, 0},
+            {"5", 1, 2, SignStyle.NORMAL, 1, 5},
+            {"50", 1, 2, SignStyle.NORMAL, 2, 50},
+            {"500", 1, 2, SignStyle.NORMAL, 2, 50},
+            {"-0", 1, 2, SignStyle.NORMAL, 2, 0},
+            {"-5", 1, 2, SignStyle.NORMAL, 2, -5},
+            {"-50", 1, 2, SignStyle.NORMAL, 3, -50},
+            {"-500", 1, 2, SignStyle.NORMAL, 3, -50},
+            {"-AAA", 1, 2, SignStyle.NORMAL, 1, null},
+            {"+0", 1, 2, SignStyle.NORMAL, 2, 0},
+            {"+5", 1, 2, SignStyle.NORMAL, 2, 5},
+            {"+50", 1, 2, SignStyle.NORMAL, 3, 50},
+            {"+500", 1, 2, SignStyle.NORMAL, 3, 50},
+            {"+AAA", 1, 2, SignStyle.NORMAL, 1, null},
+            {"50", 2, 2, SignStyle.NORMAL, 2, 50},
+            {"-50", 2, 2, SignStyle.NORMAL, 3, -50},
+            {"+50", 2, 2, SignStyle.NORMAL, 3, 50},
+
+            // always
+            {"0", 1, 2, SignStyle.ALWAYS, 1, 0},
+            {"5", 1, 2, SignStyle.ALWAYS, 1, 5},
+            {"50", 1, 2, SignStyle.ALWAYS, 2, 50},
+            {"500", 1, 2, SignStyle.ALWAYS, 2, 50},
+            {"-0", 1, 2, SignStyle.ALWAYS, 2, 0},
+            {"-5", 1, 2, SignStyle.ALWAYS, 2, -5},
+            {"-50", 1, 2, SignStyle.ALWAYS, 3, -50},
+            {"-500", 1, 2, SignStyle.ALWAYS, 3, -50},
+            {"-AAA", 1, 2, SignStyle.ALWAYS, 1, null},
+            {"+0", 1, 2, SignStyle.ALWAYS, 2, 0},
+            {"+5", 1, 2, SignStyle.ALWAYS, 2, 5},
+            {"+50", 1, 2, SignStyle.ALWAYS, 3, 50},
+            {"+500", 1, 2, SignStyle.ALWAYS, 3, 50},
+            {"+AAA", 1, 2, SignStyle.ALWAYS, 1, null},
+
+            // exceeds pad
+            {"0", 1, 2, SignStyle.EXCEEDS_PAD, 1, 0},
+            {"5", 1, 2, SignStyle.EXCEEDS_PAD, 1, 5},
+            {"50", 1, 2, SignStyle.EXCEEDS_PAD, 2, 50},
+            {"500", 1, 2, SignStyle.EXCEEDS_PAD, 2, 50},
+            {"-0", 1, 2, SignStyle.EXCEEDS_PAD, 2, 0},
+            {"-5", 1, 2, SignStyle.EXCEEDS_PAD, 2, -5},
+            {"-50", 1, 2, SignStyle.EXCEEDS_PAD, 3, -50},
+            {"-500", 1, 2, SignStyle.EXCEEDS_PAD, 3, -50},
+            {"-AAA", 1, 2, SignStyle.EXCEEDS_PAD, 1, null},
+            {"+0", 1, 2, SignStyle.EXCEEDS_PAD, 2, 0},
+            {"+5", 1, 2, SignStyle.EXCEEDS_PAD, 2, 5},
+            {"+50", 1, 2, SignStyle.EXCEEDS_PAD, 3, 50},
+            {"+500", 1, 2, SignStyle.EXCEEDS_PAD, 3, 50},
+            {"+AAA", 1, 2, SignStyle.EXCEEDS_PAD, 1, null},
+       };
+    }
+
+    @Test(dataProvider="parseSignsLenient")
+    public void test_parseSignsLenient(String input, int min, int max, SignStyle style, int parseLen, Integer parseVal) throws Exception {
+        setStrict(false);
+        ParsePosition pos = new ParsePosition(0);
+        DateTimeBuilder dtb = getFormatter(DAY_OF_MONTH, min, max, style).parseToBuilder(input, pos);
+        if (pos.getErrorIndex() != -1) {
+            assertEquals(pos.getErrorIndex(), parseLen);
+        } else {
+            assertEquals(pos.getIndex(), parseLen);
+            assertEquals(dtb.getLong(DAY_OF_MONTH), (long)parseVal);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="parseDigitsLenient")
+    Object[][] provider_parseDigitsLenient() {
+        return new Object[][] {
+                // never
+                {"5", 1, 2, SignStyle.NEVER, 1, 5},
+                {"5", 2, 2, SignStyle.NEVER, 1, 5},
+                {"54", 1, 3, SignStyle.NEVER, 2, 54},
+                {"54", 2, 3, SignStyle.NEVER, 2, 54},
+                {"54", 3, 3, SignStyle.NEVER, 2, 54},
+                {"543", 1, 3, SignStyle.NEVER, 3, 543},
+                {"543", 2, 3, SignStyle.NEVER, 3, 543},
+                {"543", 3, 3, SignStyle.NEVER, 3, 543},
+                {"5432", 1, 3, SignStyle.NEVER, 3, 543},
+                {"5432", 2, 3, SignStyle.NEVER, 3, 543},
+                {"5432", 3, 3, SignStyle.NEVER, 3, 543},
+                {"5AAA", 2, 3, SignStyle.NEVER, 1, 5},
+
+                // not negative
+                {"5", 1, 2, SignStyle.NOT_NEGATIVE, 1, 5},
+                {"5", 2, 2, SignStyle.NOT_NEGATIVE, 1, 5},
+                {"54", 1, 3, SignStyle.NOT_NEGATIVE, 2, 54},
+                {"54", 2, 3, SignStyle.NOT_NEGATIVE, 2, 54},
+                {"54", 3, 3, SignStyle.NOT_NEGATIVE, 2, 54},
+                {"543", 1, 3, SignStyle.NOT_NEGATIVE, 3, 543},
+                {"543", 2, 3, SignStyle.NOT_NEGATIVE, 3, 543},
+                {"543", 3, 3, SignStyle.NOT_NEGATIVE, 3, 543},
+                {"5432", 1, 3, SignStyle.NOT_NEGATIVE, 3, 543},
+                {"5432", 2, 3, SignStyle.NOT_NEGATIVE, 3, 543},
+                {"5432", 3, 3, SignStyle.NOT_NEGATIVE, 3, 543},
+                {"5AAA", 2, 3, SignStyle.NOT_NEGATIVE, 1, 5},
+
+                // normal
+                {"5", 1, 2, SignStyle.NORMAL, 1, 5},
+                {"5", 2, 2, SignStyle.NORMAL, 1, 5},
+                {"54", 1, 3, SignStyle.NORMAL, 2, 54},
+                {"54", 2, 3, SignStyle.NORMAL, 2, 54},
+                {"54", 3, 3, SignStyle.NORMAL, 2, 54},
+                {"543", 1, 3, SignStyle.NORMAL, 3, 543},
+                {"543", 2, 3, SignStyle.NORMAL, 3, 543},
+                {"543", 3, 3, SignStyle.NORMAL, 3, 543},
+                {"5432", 1, 3, SignStyle.NORMAL, 3, 543},
+                {"5432", 2, 3, SignStyle.NORMAL, 3, 543},
+                {"5432", 3, 3, SignStyle.NORMAL, 3, 543},
+                {"5AAA", 2, 3, SignStyle.NORMAL, 1, 5},
+
+                // always
+                {"5", 1, 2, SignStyle.ALWAYS, 1, 5},
+                {"5", 2, 2, SignStyle.ALWAYS, 1, 5},
+                {"54", 1, 3, SignStyle.ALWAYS, 2, 54},
+                {"54", 2, 3, SignStyle.ALWAYS, 2, 54},
+                {"54", 3, 3, SignStyle.ALWAYS, 2, 54},
+                {"543", 1, 3, SignStyle.ALWAYS, 3, 543},
+                {"543", 2, 3, SignStyle.ALWAYS, 3, 543},
+                {"543", 3, 3, SignStyle.ALWAYS, 3, 543},
+                {"5432", 1, 3, SignStyle.ALWAYS, 3, 543},
+                {"5432", 2, 3, SignStyle.ALWAYS, 3, 543},
+                {"5432", 3, 3, SignStyle.ALWAYS, 3, 543},
+                {"5AAA", 2, 3, SignStyle.ALWAYS, 1, 5},
+
+                // exceeds pad
+                {"5", 1, 2, SignStyle.EXCEEDS_PAD, 1, 5},
+                {"5", 2, 2, SignStyle.EXCEEDS_PAD, 1, 5},
+                {"54", 1, 3, SignStyle.EXCEEDS_PAD, 2, 54},
+                {"54", 2, 3, SignStyle.EXCEEDS_PAD, 2, 54},
+                {"54", 3, 3, SignStyle.EXCEEDS_PAD, 2, 54},
+                {"543", 1, 3, SignStyle.EXCEEDS_PAD, 3, 543},
+                {"543", 2, 3, SignStyle.EXCEEDS_PAD, 3, 543},
+                {"543", 3, 3, SignStyle.EXCEEDS_PAD, 3, 543},
+                {"5432", 1, 3, SignStyle.EXCEEDS_PAD, 3, 543},
+                {"5432", 2, 3, SignStyle.EXCEEDS_PAD, 3, 543},
+                {"5432", 3, 3, SignStyle.EXCEEDS_PAD, 3, 543},
+                {"5AAA", 2, 3, SignStyle.EXCEEDS_PAD, 1, 5},
+        };
+    }
+
+    @Test(dataProvider="parseDigitsLenient")
+    public void test_parseDigitsLenient(String input, int min, int max, SignStyle style, int parseLen, Integer parseVal) throws Exception {
+        setStrict(false);
+        ParsePosition pos = new ParsePosition(0);
+        DateTimeBuilder dtb = getFormatter(DAY_OF_MONTH, min, max, style).parseToBuilder(input, pos);
+        if (pos.getErrorIndex() != -1) {
+            assertEquals(pos.getErrorIndex(), parseLen);
+        } else {
+            assertEquals(pos.getIndex(), parseLen);
+            assertEquals(dtb.getLong(DAY_OF_MONTH), (long)parseVal);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="parseDigitsAdjacentLenient")
+    Object[][] provider_parseDigitsAdjacentLenient() {
+        return new Object[][] {
+                // never
+                {"5", 1, null, null},
+                {"54", 1, null, null},
+
+                {"543", 3, 5, 43},
+                {"543A", 3, 5, 43},
+
+                {"5432", 4, 54, 32},
+                {"5432A", 4, 54, 32},
+
+                {"54321", 4, 54, 32},
+                {"54321A", 4, 54, 32},
+        };
+    }
+
+    @Test(dataProvider="parseDigitsAdjacentLenient")
+    public void test_parseDigitsAdjacentLenient(String input, int parseLen, Integer parseMonth, Integer parsedDay) throws Exception {
+        setStrict(false);
+        ParsePosition pos = new ParsePosition(0);
+        DateTimeFormatter f = builder
+                .appendValue(MONTH_OF_YEAR, 1, 2, SignStyle.NORMAL)
+                .appendValue(DAY_OF_MONTH, 2).toFormatter(locale).withSymbols(symbols);
+        DateTimeBuilder dtb = f.parseToBuilder(input, pos);
+        if (pos.getErrorIndex() != -1) {
+            assertEquals(pos.getErrorIndex(), parseLen);
+        } else {
+            assertEquals(pos.getIndex(), parseLen);
+            assertEquals(dtb.getLong(MONTH_OF_YEAR), (long) parseMonth);
+            assertEquals(dtb.getLong(DAY_OF_MONTH), (long) parsedDay);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/format/TestNumberPrinter.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.format;
+
+import java.time.format.*;
+
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.HOUR_OF_DAY;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import test.java.time.temporal.MockFieldValue;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test SimpleNumberPrinterParser.
+ */
+@Test
+public class TestNumberPrinter extends AbstractTestPrinterParser {
+
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=DateTimeException.class)
+    public void test_print_emptyCalendrical() throws Exception {
+        getFormatter(DAY_OF_MONTH, 1, 2, SignStyle.NEVER).printTo(EMPTY_DTA, buf);
+    }
+
+    public void test_print_append() throws Exception {
+        buf.append("EXISTING");
+        getFormatter(DAY_OF_MONTH, 1, 2, SignStyle.NEVER).printTo(LocalDate.of(2012, 1, 3), buf);
+        assertEquals(buf.toString(), "EXISTING3");
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="Pad")
+    Object[][] provider_pad() {
+        return new Object[][] {
+            {1, 1, -10, null},
+            {1, 1, -9, "9"},
+            {1, 1, -1, "1"},
+            {1, 1, 0, "0"},
+            {1, 1, 3, "3"},
+            {1, 1, 9, "9"},
+            {1, 1, 10, null},
+
+            {1, 2, -100, null},
+            {1, 2, -99, "99"},
+            {1, 2, -10, "10"},
+            {1, 2, -9, "9"},
+            {1, 2, -1, "1"},
+            {1, 2, 0, "0"},
+            {1, 2, 3, "3"},
+            {1, 2, 9, "9"},
+            {1, 2, 10, "10"},
+            {1, 2, 99, "99"},
+            {1, 2, 100, null},
+
+            {2, 2, -100, null},
+            {2, 2, -99, "99"},
+            {2, 2, -10, "10"},
+            {2, 2, -9, "09"},
+            {2, 2, -1, "01"},
+            {2, 2, 0, "00"},
+            {2, 2, 3, "03"},
+            {2, 2, 9, "09"},
+            {2, 2, 10, "10"},
+            {2, 2, 99, "99"},
+            {2, 2, 100, null},
+
+            {1, 3, -1000, null},
+            {1, 3, -999, "999"},
+            {1, 3, -100, "100"},
+            {1, 3, -99, "99"},
+            {1, 3, -10, "10"},
+            {1, 3, -9, "9"},
+            {1, 3, -1, "1"},
+            {1, 3, 0, "0"},
+            {1, 3, 3, "3"},
+            {1, 3, 9, "9"},
+            {1, 3, 10, "10"},
+            {1, 3, 99, "99"},
+            {1, 3, 100, "100"},
+            {1, 3, 999, "999"},
+            {1, 3, 1000, null},
+
+            {2, 3, -1000, null},
+            {2, 3, -999, "999"},
+            {2, 3, -100, "100"},
+            {2, 3, -99, "99"},
+            {2, 3, -10, "10"},
+            {2, 3, -9, "09"},
+            {2, 3, -1, "01"},
+            {2, 3, 0, "00"},
+            {2, 3, 3, "03"},
+            {2, 3, 9, "09"},
+            {2, 3, 10, "10"},
+            {2, 3, 99, "99"},
+            {2, 3, 100, "100"},
+            {2, 3, 999, "999"},
+            {2, 3, 1000, null},
+
+            {3, 3, -1000, null},
+            {3, 3, -999, "999"},
+            {3, 3, -100, "100"},
+            {3, 3, -99, "099"},
+            {3, 3, -10, "010"},
+            {3, 3, -9, "009"},
+            {3, 3, -1, "001"},
+            {3, 3, 0, "000"},
+            {3, 3, 3, "003"},
+            {3, 3, 9, "009"},
+            {3, 3, 10, "010"},
+            {3, 3, 99, "099"},
+            {3, 3, 100, "100"},
+            {3, 3, 999, "999"},
+            {3, 3, 1000, null},
+
+            {1, 10, Integer.MAX_VALUE - 1, "2147483646"},
+            {1, 10, Integer.MAX_VALUE, "2147483647"},
+            {1, 10, Integer.MIN_VALUE + 1, "2147483647"},
+            {1, 10, Integer.MIN_VALUE, "2147483648"},
+       };
+    }
+
+    @Test(dataProvider="Pad")
+    public void test_pad_NOT_NEGATIVE(int minPad, int maxPad, long value, String result) throws Exception {
+        try {
+            getFormatter(DAY_OF_MONTH, minPad, maxPad, SignStyle.NOT_NEGATIVE).printTo(new MockFieldValue(DAY_OF_MONTH, value), buf);
+            if (result == null || value < 0) {
+                fail("Expected exception");
+            }
+            assertEquals(buf.toString(), result);
+        } catch (DateTimePrintException ex) {
+            if (result == null || value < 0) {
+                assertEquals(ex.getMessage().contains(DAY_OF_MONTH.getName()), true);
+            } else {
+                throw ex;
+            }
+        }
+    }
+
+    @Test(dataProvider="Pad")
+    public void test_pad_NEVER(int minPad, int maxPad, long value, String result) throws Exception {
+        try {
+            getFormatter(DAY_OF_MONTH, minPad, maxPad, SignStyle.NEVER).printTo(new MockFieldValue(DAY_OF_MONTH, value), buf);
+            if (result == null) {
+                fail("Expected exception");
+            }
+            assertEquals(buf.toString(), result);
+        } catch (DateTimePrintException ex) {
+            if (result != null) {
+                throw ex;
+            }
+            assertEquals(ex.getMessage().contains(DAY_OF_MONTH.getName()), true);
+        }
+    }
+
+    @Test(dataProvider="Pad")
+    public void test_pad_NORMAL(int minPad, int maxPad, long value, String result) throws Exception {
+        try {
+            getFormatter(DAY_OF_MONTH, minPad, maxPad, SignStyle.NORMAL).printTo(new MockFieldValue(DAY_OF_MONTH, value), buf);
+            if (result == null) {
+                fail("Expected exception");
+            }
+            assertEquals(buf.toString(), (value < 0 ? "-" + result : result));
+        } catch (DateTimePrintException ex) {
+            if (result != null) {
+                throw ex;
+            }
+            assertEquals(ex.getMessage().contains(DAY_OF_MONTH.getName()), true);
+        }
+    }
+
+    @Test(dataProvider="Pad")
+    public void test_pad_ALWAYS(int minPad, int maxPad, long value, String result) throws Exception {
+        try {
+            getFormatter(DAY_OF_MONTH, minPad, maxPad, SignStyle.ALWAYS).printTo(new MockFieldValue(DAY_OF_MONTH, value), buf);
+            if (result == null) {
+                fail("Expected exception");
+            }
+            assertEquals(buf.toString(), (value < 0 ? "-" + result : "+" + result));
+        } catch (DateTimePrintException ex) {
+            if (result != null) {
+                throw ex;
+            }
+            assertEquals(ex.getMessage().contains(DAY_OF_MONTH.getName()), true);
+        }
+    }
+
+    @Test(dataProvider="Pad")
+    public void test_pad_EXCEEDS_PAD(int minPad, int maxPad, long value, String result) throws Exception {
+        try {
+            getFormatter(DAY_OF_MONTH, minPad, maxPad, SignStyle.EXCEEDS_PAD).printTo(new MockFieldValue(DAY_OF_MONTH, value), buf);
+            if (result == null) {
+                fail("Expected exception");
+                return;  // unreachable
+            }
+            if (result.length() > minPad || value < 0) {
+                result = (value < 0 ? "-" + result : "+" + result);
+            }
+            assertEquals(buf.toString(), result);
+        } catch (DateTimePrintException ex) {
+            if (result != null) {
+                throw ex;
+            }
+            assertEquals(ex.getMessage().contains(DAY_OF_MONTH.getName()), true);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_toString1() throws Exception {
+        assertEquals(getFormatter(HOUR_OF_DAY, 1, 19, SignStyle.NORMAL).toString(), "Value(HourOfDay)");
+    }
+
+    public void test_toString2() throws Exception {
+        assertEquals(getFormatter(HOUR_OF_DAY, 2, 2, SignStyle.NOT_NEGATIVE).toString(), "Value(HourOfDay,2)");
+    }
+
+    public void test_toString3() throws Exception {
+        assertEquals(getFormatter(HOUR_OF_DAY, 1, 2, SignStyle.NOT_NEGATIVE).toString(), "Value(HourOfDay,1,2,NOT_NEGATIVE)");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/format/TestPadParserDecorator.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.format;
+
+import java.time.format.*;
+
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static org.testng.Assert.assertEquals;
+
+import java.text.ParsePosition;
+import java.time.format.DateTimeBuilder;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test PadPrinterParserDecorator.
+ */
+@Test(groups={"implementation"})
+public class TestPadParserDecorator extends AbstractTestPrinterParser {
+
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=IndexOutOfBoundsException.class)
+    public void test_parse_negativePosition() throws Exception {
+        builder.padNext(3, '-').appendLiteral('Z');
+        getFormatter().parseToBuilder("--Z", new ParsePosition(-1));
+    }
+
+    @Test(expectedExceptions=IndexOutOfBoundsException.class)
+    public void test_parse_offEndPosition() throws Exception {
+        builder.padNext(3, '-').appendLiteral('Z');
+        getFormatter().parseToBuilder("--Z", new ParsePosition(4));
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_parse() throws Exception {
+        ParsePosition pos = new ParsePosition(0);
+        builder.padNext(3, '-').appendValue(MONTH_OF_YEAR, 1, 3, SignStyle.NEVER);
+        DateTimeBuilder dtb = getFormatter().parseToBuilder("--2", pos);
+        assertEquals(pos.getIndex(), 3);
+        assertEquals(dtb.getFieldValueMap().size(), 1);
+        assertEquals(dtb.getLong(MONTH_OF_YEAR), 2L);
+    }
+
+    public void test_parse_noReadBeyond() throws Exception {
+        ParsePosition pos = new ParsePosition(0);
+        builder.padNext(3, '-').appendValue(MONTH_OF_YEAR, 1, 3, SignStyle.NEVER);
+        DateTimeBuilder dtb = getFormatter().parseToBuilder("--22", pos);
+        assertEquals(pos.getIndex(), 3);
+        assertEquals(dtb.getFieldValueMap().size(), 1);
+        assertEquals(dtb.getLong(MONTH_OF_YEAR), 2L);
+    }
+
+    public void test_parse_textLessThanPadWidth() throws Exception {
+        ParsePosition pos = new ParsePosition(0);
+        builder.padNext(3, '-').appendValue(MONTH_OF_YEAR, 1, 3, SignStyle.NEVER);
+        DateTimeBuilder dtb = getFormatter().parseToBuilder("-1", pos);
+        assertEquals(pos.getErrorIndex(), 0);
+    }
+
+    public void test_parse_decoratedErrorPassedBack() throws Exception {
+        ParsePosition pos = new ParsePosition(0);
+        builder.padNext(3, '-').appendValue(MONTH_OF_YEAR, 1, 3, SignStyle.NEVER);
+        DateTimeBuilder dtb = getFormatter().parseToBuilder("--A", pos);
+        assertEquals(pos.getErrorIndex(), 2);
+    }
+
+    public void test_parse_decoratedDidNotParseToPadWidth() throws Exception {
+        ParsePosition pos = new ParsePosition(0);
+        builder.padNext(3, '-').appendValue(MONTH_OF_YEAR, 1, 3, SignStyle.NEVER);
+        DateTimeBuilder dtb = getFormatter().parseToBuilder("-1X", pos);
+        assertEquals(pos.getErrorIndex(), 0);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_parse_decoratedStartsWithPad() throws Exception {
+        ParsePosition pos = new ParsePosition(0);
+        builder.padNext(8, '-').appendLiteral("-HELLO-");
+        DateTimeBuilder dtb = getFormatter().parseToBuilder("--HELLO-", pos);
+        assertEquals(pos.getIndex(), 8);
+        assertEquals(dtb.getFieldValueMap().size(), 0);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/format/TestPadPrinterDecorator.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.format;
+
+import java.time.format.*;
+
+import static org.testng.Assert.assertEquals;
+
+import java.time.LocalDate;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test PadPrinterDecorator.
+ */
+@Test(groups={"implementation"})
+public class TestPadPrinterDecorator extends AbstractTestPrinterParser {
+
+    //-----------------------------------------------------------------------
+    public void test_print_emptyCalendrical() throws Exception {
+        builder.padNext(3, '-').appendLiteral('Z');
+        getFormatter().printTo(EMPTY_DTA, buf);
+        assertEquals(buf.toString(), "--Z");
+    }
+
+    public void test_print_fullDateTime() throws Exception {
+        builder.padNext(3, '-').appendLiteral('Z');
+        getFormatter().printTo(LocalDate.of(2008, 12, 3), buf);
+        assertEquals(buf.toString(), "--Z");
+    }
+
+    public void test_print_append() throws Exception {
+        buf.append("EXISTING");
+        builder.padNext(3, '-').appendLiteral('Z');
+        getFormatter().printTo(EMPTY_DTA, buf);
+        assertEquals(buf.toString(), "EXISTING--Z");
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_print_noPadRequiredSingle() throws Exception {
+        builder.padNext(1, '-').appendLiteral('Z');
+        getFormatter().printTo(EMPTY_DTA, buf);
+        assertEquals(buf.toString(), "Z");
+    }
+
+    public void test_print_padRequiredSingle() throws Exception {
+        builder.padNext(5, '-').appendLiteral('Z');
+        getFormatter().printTo(EMPTY_DTA, buf);
+        assertEquals(buf.toString(), "----Z");
+    }
+
+    public void test_print_noPadRequiredMultiple() throws Exception {
+        builder.padNext(4, '-').appendLiteral("WXYZ");
+        getFormatter().printTo(EMPTY_DTA, buf);
+        assertEquals(buf.toString(), "WXYZ");
+    }
+
+    public void test_print_padRequiredMultiple() throws Exception {
+        builder.padNext(5, '-').appendLiteral("WXYZ");
+        getFormatter().printTo(EMPTY_DTA, buf);
+        assertEquals(buf.toString(), "-WXYZ");
+    }
+
+    @Test(expectedExceptions=DateTimePrintException.class)
+    public void test_print_overPad() throws Exception {
+        builder.padNext(3, '-').appendLiteral("WXYZ");
+        getFormatter().printTo(EMPTY_DTA, buf);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_toString1() throws Exception {
+        builder.padNext(5, ' ').appendLiteral('Y');
+        assertEquals(getFormatter().toString(), "Pad('Y',5)");
+    }
+
+    public void test_toString2() throws Exception {
+        builder.padNext(5, '-').appendLiteral('Y');
+        assertEquals(getFormatter().toString(), "Pad('Y',5,'-')");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/format/TestReducedParser.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2010-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.format;
+
+import java.time.format.*;
+
+import static java.time.temporal.ChronoField.DAY_OF_YEAR;
+import static java.time.temporal.ChronoField.YEAR;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.text.ParsePosition;
+import java.time.format.DateTimeBuilder;
+import java.time.temporal.TemporalField;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test ReducedPrinterParser.
+ */
+@Test(groups={"implementation"})
+public class TestReducedParser extends AbstractTestPrinterParser {
+
+    private DateTimeFormatter getFormatter0(TemporalField field, int width, int baseValue) {
+        return builder.appendValueReduced(field, width, baseValue).toFormatter(locale).withSymbols(symbols);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="error")
+    Object[][] data_error() {
+        return new Object[][] {
+            {YEAR, 2, 2010, "12", -1, IndexOutOfBoundsException.class},
+            {YEAR, 2, 2010, "12", 3, IndexOutOfBoundsException.class},
+        };
+    }
+
+    @Test(dataProvider="error")
+    public void test_parse_error(TemporalField field, int width, int baseValue, String text, int pos, Class<?> expected) {
+        try {
+            getFormatter0(field, width, baseValue).parseToBuilder(text, new ParsePosition(pos));
+        } catch (RuntimeException ex) {
+            assertTrue(expected.isInstance(ex));
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_parse_fieldRangeIgnored() throws Exception {
+        ParsePosition pos = new ParsePosition(0);
+        DateTimeBuilder dtb = getFormatter0(DAY_OF_YEAR, 3, 10).parseToBuilder("456", pos);
+        assertEquals(pos.getIndex(), 3);
+        assertParsed(dtb, DAY_OF_YEAR, 456L);  // parsed dayOfYear=456
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="Parse")
+    Object[][] provider_parse() {
+        return new Object[][] {
+             // negative zero
+            {YEAR, 1, 2010, "-0", 0, 0, null},
+
+            // general
+            {YEAR, 2, 2010, "Xxx12Xxx", 3, 5, 2012},
+            {YEAR, 2, 2010, "12345", 0, 2, 2012},
+            {YEAR, 2, 2010, "12-45", 0, 2, 2012},
+
+            // insufficient digits
+            {YEAR, 2, 2010, "0", 0, 0, null},
+            {YEAR, 2, 2010, "1", 0, 0, null},
+            {YEAR, 2, 2010, "1", 1, 1, null},
+            {YEAR, 2, 2010, "1-2", 0, 0, null},
+            {YEAR, 2, 2010, "9", 0, 0, null},
+
+            // other junk
+            {YEAR, 2, 2010, "A0", 0, 0, null},
+            {YEAR, 2, 2010, "0A", 0, 0, null},
+            {YEAR, 2, 2010, "  1", 0, 0, null},
+            {YEAR, 2, 2010, "-1", 0, 0, null},
+            {YEAR, 2, 2010, "-10", 0, 0, null},
+
+            // parse OK 1
+            {YEAR, 1, 2010, "0", 0, 1, 2010},
+            {YEAR, 1, 2010, "9", 0, 1, 2019},
+            {YEAR, 1, 2010, "10", 0, 1, 2011},
+
+            {YEAR, 1, 2005, "0", 0, 1, 2010},
+            {YEAR, 1, 2005, "4", 0, 1, 2014},
+            {YEAR, 1, 2005, "5", 0, 1, 2005},
+            {YEAR, 1, 2005, "9", 0, 1, 2009},
+            {YEAR, 1, 2005, "10", 0, 1, 2011},
+
+            // parse OK 2
+            {YEAR, 2, 2010, "00", 0, 2, 2100},
+            {YEAR, 2, 2010, "09", 0, 2, 2109},
+            {YEAR, 2, 2010, "10", 0, 2, 2010},
+            {YEAR, 2, 2010, "99", 0, 2, 2099},
+            {YEAR, 2, 2010, "100", 0, 2, 2010},
+
+            // parse OK 2
+            {YEAR, 2, -2005, "05", 0, 2, -2005},
+            {YEAR, 2, -2005, "00", 0, 2, -2000},
+            {YEAR, 2, -2005, "99", 0, 2, -1999},
+            {YEAR, 2, -2005, "06", 0, 2, -1906},
+            {YEAR, 2, -2005, "100", 0, 2, -1910},
+       };
+    }
+
+    @Test(dataProvider="Parse")
+    public void test_parse(TemporalField field, int width, int baseValue, String input, int pos, int parseLen, Integer parseVal) {
+        ParsePosition ppos = new ParsePosition(pos);
+        DateTimeBuilder dtb = getFormatter0(field, width, baseValue).parseToBuilder(input, ppos);
+        if (ppos.getErrorIndex() != -1) {
+            assertEquals(ppos.getErrorIndex(), parseLen);
+        } else {
+            assertEquals(ppos.getIndex(), parseLen);
+            assertParsed(dtb, YEAR, parseVal != null ? (long) parseVal : null);
+        }
+    }
+
+    @Test(dataProvider="Parse")
+    public void test_parseLenient(TemporalField field, int width, int baseValue, String input, int pos, int parseLen, Integer parseVal) {
+        setStrict(false);
+        ParsePosition ppos = new ParsePosition(pos);
+        DateTimeBuilder dtb = getFormatter0(field, width, baseValue).parseToBuilder(input, ppos);
+        if (ppos.getErrorIndex() != -1) {
+            assertEquals(ppos.getErrorIndex(), parseLen);
+        } else {
+            assertEquals(ppos.getIndex(), parseLen);
+            assertParsed(dtb, YEAR, parseVal != null ? (long) parseVal : null);
+        }
+    }
+
+    private void assertParsed(DateTimeBuilder dtb, TemporalField field, Long value) {
+        if (value == null) {
+            assertEquals(dtb, null);
+        } else {
+            assertEquals(dtb.getLong(field), (long)value);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/format/TestReducedPrinter.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2010-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.format;
+
+import java.time.format.*;
+
+import static java.time.temporal.ChronoField.YEAR;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.temporal.TemporalField;
+import test.java.time.temporal.MockFieldValue;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test ReducedPrinterParser.
+ */
+@Test(groups={"implementation"})
+public class TestReducedPrinter extends AbstractTestPrinterParser {
+
+    private DateTimeFormatter getFormatter0(TemporalField field, int width, int baseValue) {
+        return builder.appendValueReduced(field, width, baseValue).toFormatter(locale).withSymbols(symbols);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=DateTimeException.class)
+    public void test_print_emptyCalendrical() throws Exception {
+        getFormatter0(YEAR, 2, 2010).printTo(EMPTY_DTA, buf);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_print_append() throws Exception {
+        buf.append("EXISTING");
+        getFormatter0(YEAR, 2, 2010).printTo(LocalDate.of(2012, 1, 1), buf);
+        assertEquals(buf.toString(), "EXISTING12");
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="Pivot")
+    Object[][] provider_pivot() {
+        return new Object[][] {
+            {1, 2010, 2010, "0"},
+            {1, 2010, 2011, "1"},
+            {1, 2010, 2012, "2"},
+            {1, 2010, 2013, "3"},
+            {1, 2010, 2014, "4"},
+            {1, 2010, 2015, "5"},
+            {1, 2010, 2016, "6"},
+            {1, 2010, 2017, "7"},
+            {1, 2010, 2018, "8"},
+            {1, 2010, 2019, "9"},
+            {1, 2010, 2009, "9"},
+            {1, 2010, 2020, "0"},
+
+            {2, 2010, 2010, "10"},
+            {2, 2010, 2011, "11"},
+            {2, 2010, 2021, "21"},
+            {2, 2010, 2099, "99"},
+            {2, 2010, 2100, "00"},
+            {2, 2010, 2109, "09"},
+            {2, 2010, 2009, "09"},
+            {2, 2010, 2110, "10"},
+
+            {2, 2005, 2005, "05"},
+            {2, 2005, 2099, "99"},
+            {2, 2005, 2100, "00"},
+            {2, 2005, 2104, "04"},
+            {2, 2005, 2004, "04"},
+            {2, 2005, 2105, "05"},
+
+            {3, 2005, 2005, "005"},
+            {3, 2005, 2099, "099"},
+            {3, 2005, 2100, "100"},
+            {3, 2005, 2999, "999"},
+            {3, 2005, 3000, "000"},
+            {3, 2005, 3004, "004"},
+            {3, 2005, 2004, "004"},
+            {3, 2005, 3005, "005"},
+
+            {9, 2005, 2005, "000002005"},
+            {9, 2005, 2099, "000002099"},
+            {9, 2005, 2100, "000002100"},
+            {9, 2005, 999999999, "999999999"},
+            {9, 2005, 1000000000, "000000000"},
+            {9, 2005, 1000002004, "000002004"},
+            {9, 2005, 2004, "000002004"},
+            {9, 2005, 1000002005, "000002005"},
+
+            {2, -2005, -2005, "05"},
+            {2, -2005, -2000, "00"},
+            {2, -2005, -1999, "99"},
+            {2, -2005, -1904, "04"},
+            {2, -2005, -2006, "06"},
+            {2, -2005, -1905, "05"},
+       };
+    }
+
+    @Test(dataProvider="Pivot")
+    public void test_pivot(int width, int baseValue, int value, String result) throws Exception {
+        try {
+            getFormatter0(YEAR, width, baseValue).printTo(new MockFieldValue(YEAR, value), buf);
+            if (result == null) {
+                fail("Expected exception");
+            }
+            assertEquals(buf.toString(), result);
+        } catch (DateTimePrintException ex) {
+            if (result == null || value < 0) {
+                assertEquals(ex.getMessage().contains(YEAR.getName()), true);
+            } else {
+                throw ex;
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_toString() throws Exception {
+        assertEquals(getFormatter0(YEAR, 2, 2005).toString(), "ReducedValue(Year,2,2005)");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/format/TestSettingsParser.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.format;
+
+import java.time.format.*;
+
+import static org.testng.Assert.assertEquals;
+
+import java.text.ParsePosition;
+import java.time.ZoneOffset;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test SettingsParser.
+ */
+@Test(groups={"implementation"})
+public class TestSettingsParser extends AbstractTestPrinterParser {
+
+    //-----------------------------------------------------------------------
+    public void test_print_sensitive() throws Exception {
+        setCaseSensitive(true);
+        getFormatter().printTo(dta, buf);
+        assertEquals(buf.toString(), "");
+    }
+
+    public void test_print_strict() throws Exception {
+        setStrict(true);
+        getFormatter().printTo(dta, buf);
+        assertEquals(buf.toString(), "");
+    }
+
+    /*
+    public void test_print_nulls() throws Exception {
+        setCaseSensitive(true);
+        getFormatter().printTo(null, null);
+    }
+    */
+
+    //-----------------------------------------------------------------------
+    public void test_parse_changeStyle_sensitive() throws Exception {
+        setCaseSensitive(true);
+        ParsePosition pos = new ParsePosition(0);
+        getFormatter().parseToBuilder("a", pos);
+        assertEquals(pos.getIndex(), 0);
+    }
+
+    public void test_parse_changeStyle_insensitive() throws Exception {
+        setCaseSensitive(false);
+        ParsePosition pos = new ParsePosition(0);
+        getFormatter().parseToBuilder("a", pos);
+        assertEquals(pos.getIndex(), 0);
+    }
+
+    public void test_parse_changeStyle_strict() throws Exception {
+        setStrict(true);
+        ParsePosition pos = new ParsePosition(0);
+        getFormatter().parseToBuilder("a", pos);
+        assertEquals(pos.getIndex(), 0);
+    }
+
+    public void test_parse_changeStyle_lenient() throws Exception {
+        setStrict(false);
+        ParsePosition pos = new ParsePosition(0);
+        getFormatter().parseToBuilder("a", pos);
+        assertEquals(pos.getIndex(), 0);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_toString_sensitive() throws Exception {
+        setCaseSensitive(true);
+        assertEquals(getFormatter().toString(), "ParseCaseSensitive(true)");
+    }
+
+    public void test_toString_insensitive() throws Exception {
+        setCaseSensitive(false);
+        assertEquals(getFormatter().toString(), "ParseCaseSensitive(false)");
+    }
+
+    public void test_toString_strict() throws Exception {
+        setStrict(true);
+        assertEquals(getFormatter().toString(), "ParseStrict(true)");
+    }
+
+    public void test_toString_lenient() throws Exception {
+        setStrict(false);
+        assertEquals(getFormatter().toString(), "ParseStrict(false)");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/format/TestStringLiteralParser.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.format;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.time.format.DateTimeBuilder;
+import java.text.ParsePosition;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test StringLiteralPrinterParser.
+ */
+@Test(groups={"implementation"})
+public class TestStringLiteralParser extends AbstractTestPrinterParser {
+
+    @DataProvider(name="success")
+    Object[][] data_success() {
+        return new Object[][] {
+            // match
+            {"hello", true, "hello", 0, 5},
+            {"hello", true, "helloOTHER", 0, 5},
+            {"hello", true, "OTHERhelloOTHER", 5, 10},
+            {"hello", true, "OTHERhello", 5, 10},
+
+            // no match
+            {"hello", true, "", 0, 0},
+            {"hello", true, "a", 1, 1},
+            {"hello", true, "HELLO", 0, 0},
+            {"hello", true, "hlloo", 0, 0},
+            {"hello", true, "OTHERhllooOTHER", 5, 5},
+            {"hello", true, "OTHERhlloo", 5, 5},
+            {"hello", true, "h", 0, 0},
+            {"hello", true, "OTHERh", 5, 5},
+
+            // case insensitive
+            {"hello", false, "hello", 0, 5},
+            {"hello", false, "HELLO", 0, 5},
+            {"hello", false, "HelLo", 0, 5},
+            {"hello", false, "HelLO", 0, 5},
+        };
+    }
+
+    @Test(dataProvider="success")
+    public void test_parse_success(String s, boolean caseSensitive, String text, int pos, int expectedPos) {
+        setCaseSensitive(caseSensitive);
+        ParsePosition ppos = new ParsePosition(pos);
+        DateTimeBuilder result =
+               getFormatter(s).parseToBuilder(text, ppos);
+        if (ppos.getErrorIndex() != -1) {
+            assertEquals(ppos.getIndex(), expectedPos);
+        } else {
+            assertEquals(ppos.getIndex(), expectedPos);
+            assertEquals(result.getCalendricalList().size(), 0);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="error")
+    Object[][] data_error() {
+        return new Object[][] {
+            {"hello", "hello", -1, IndexOutOfBoundsException.class},
+            {"hello", "hello", 6, IndexOutOfBoundsException.class},
+        };
+    }
+
+    @Test(dataProvider="error")
+    public void test_parse_error(String s, String text, int pos, Class<?> expected) {
+        try {
+            DateTimeBuilder result =
+               getFormatter(s).parseToBuilder(text, new ParsePosition(pos));
+            assertTrue(false);
+        } catch (RuntimeException ex) {
+            assertTrue(expected.isInstance(ex));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/format/TestStringLiteralPrinter.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.format;
+
+import java.time.format.*;
+
+import static org.testng.Assert.assertEquals;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test StringLiteralPrinterParser.
+ */
+@Test(groups={"implementation"})
+public class TestStringLiteralPrinter extends AbstractTestPrinterParser {
+
+    //-----------------------------------------------------------------------
+    public void test_print_emptyCalendrical() throws Exception {
+        buf.append("EXISTING");
+        getFormatter("hello").printTo(EMPTY_DTA, buf);
+        assertEquals(buf.toString(), "EXISTINGhello");
+    }
+
+    public void test_print_dateTime() throws Exception {
+        buf.append("EXISTING");
+        getFormatter("hello").printTo(dta, buf);
+        assertEquals(buf.toString(), "EXISTINGhello");
+    }
+
+
+
+
+    public void test_print_emptyAppendable() throws Exception {
+        getFormatter("hello").printTo(dta, buf);
+        assertEquals(buf.toString(), "hello");
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_toString() throws Exception {
+        assertEquals(getFormatter("hello").toString(), "'hello'");
+    }
+
+    public void test_toString_apos() throws Exception {
+        assertEquals(getFormatter("o'clock").toString(), "'o''clock'");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/format/TestTextParser.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.format;
+
+import java.time.format.*;
+
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.DAY_OF_WEEK;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.text.ParsePosition;
+import java.util.Locale;
+import java.time.format.DateTimeBuilder;
+import java.time.temporal.TemporalField;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test TextPrinterParser.
+ */
+@Test(groups={"implementation"})
+public class TestTextParser extends AbstractTestPrinterParser {
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="error")
+    Object[][] data_error() {
+        return new Object[][] {
+            {DAY_OF_WEEK, TextStyle.FULL, "Monday", -1, IndexOutOfBoundsException.class},
+            {DAY_OF_WEEK, TextStyle.FULL, "Monday", 7, IndexOutOfBoundsException.class},
+        };
+    }
+
+    @Test(dataProvider="error")
+    public void test_parse_error(TemporalField field, TextStyle style, String text, int pos, Class<?> expected) {
+        try {
+            getFormatter(field, style).parseToBuilder(text, new ParsePosition(pos));
+        } catch (RuntimeException ex) {
+            assertTrue(expected.isInstance(ex));
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_parse_midStr() throws Exception {
+        ParsePosition pos = new ParsePosition(3);
+        assertEquals(getFormatter(DAY_OF_WEEK, TextStyle.FULL)
+                     .parseToBuilder("XxxMondayXxx", pos)
+                     .getLong(DAY_OF_WEEK), 1L);
+        assertEquals(pos.getIndex(), 9);
+    }
+
+    public void test_parse_remainderIgnored() throws Exception {
+        ParsePosition pos = new ParsePosition(0);
+        assertEquals(getFormatter(DAY_OF_WEEK, TextStyle.SHORT)
+                     .parseToBuilder("Wednesday", pos)
+                     .getLong(DAY_OF_WEEK), 3L);
+        assertEquals(pos.getIndex(), 3);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_parse_noMatch1() throws Exception {
+        ParsePosition pos = new ParsePosition(0);
+        DateTimeBuilder dtb =
+            getFormatter(DAY_OF_WEEK, TextStyle.FULL).parseToBuilder("Munday", pos);
+        assertEquals(pos.getErrorIndex(), 0);
+    }
+
+    public void test_parse_noMatch2() throws Exception {
+        ParsePosition pos = new ParsePosition(3);
+        DateTimeBuilder dtb =
+            getFormatter(DAY_OF_WEEK, TextStyle.FULL).parseToBuilder("Monday", pos);
+        assertEquals(pos.getErrorIndex(), 3);
+    }
+
+    public void test_parse_noMatch_atEnd() throws Exception {
+        ParsePosition pos = new ParsePosition(6);
+        DateTimeBuilder dtb =
+            getFormatter(DAY_OF_WEEK, TextStyle.FULL).parseToBuilder("Monday", pos);
+        assertEquals(pos.getErrorIndex(), 6);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="parseText")
+    Object[][] provider_text() {
+        return new Object[][] {
+            {DAY_OF_WEEK, TextStyle.FULL, 1, "Monday"},
+            {DAY_OF_WEEK, TextStyle.FULL, 2, "Tuesday"},
+            {DAY_OF_WEEK, TextStyle.FULL, 3, "Wednesday"},
+            {DAY_OF_WEEK, TextStyle.FULL, 4, "Thursday"},
+            {DAY_OF_WEEK, TextStyle.FULL, 5, "Friday"},
+            {DAY_OF_WEEK, TextStyle.FULL, 6, "Saturday"},
+            {DAY_OF_WEEK, TextStyle.FULL, 7, "Sunday"},
+
+            {DAY_OF_WEEK, TextStyle.SHORT, 1, "Mon"},
+            {DAY_OF_WEEK, TextStyle.SHORT, 2, "Tue"},
+            {DAY_OF_WEEK, TextStyle.SHORT, 3, "Wed"},
+            {DAY_OF_WEEK, TextStyle.SHORT, 4, "Thu"},
+            {DAY_OF_WEEK, TextStyle.SHORT, 5, "Fri"},
+            {DAY_OF_WEEK, TextStyle.SHORT, 6, "Sat"},
+            {DAY_OF_WEEK, TextStyle.SHORT, 7, "Sun"},
+
+            {MONTH_OF_YEAR, TextStyle.FULL, 1, "January"},
+            {MONTH_OF_YEAR, TextStyle.FULL, 12, "December"},
+
+            {MONTH_OF_YEAR, TextStyle.SHORT, 1, "Jan"},
+            {MONTH_OF_YEAR, TextStyle.SHORT, 12, "Dec"},
+       };
+    }
+
+    @DataProvider(name="parseNumber")
+    Object[][] provider_number() {
+        return new Object[][] {
+            {DAY_OF_MONTH, TextStyle.FULL, 1, "1"},
+            {DAY_OF_MONTH, TextStyle.FULL, 2, "2"},
+            {DAY_OF_MONTH, TextStyle.FULL, 30, "30"},
+            {DAY_OF_MONTH, TextStyle.FULL, 31, "31"},
+
+            {DAY_OF_MONTH, TextStyle.SHORT, 1, "1"},
+            {DAY_OF_MONTH, TextStyle.SHORT, 2, "2"},
+            {DAY_OF_MONTH, TextStyle.SHORT, 30, "30"},
+            {DAY_OF_MONTH, TextStyle.SHORT, 31, "31"},
+       };
+    }
+
+    @Test(dataProvider="parseText")
+    public void test_parseText(TemporalField field, TextStyle style, int value, String input) throws Exception {
+        ParsePosition pos = new ParsePosition(0);
+        assertEquals(getFormatter(field, style).parseToBuilder(input, pos).getLong(field), (long) value);
+        assertEquals(pos.getIndex(), input.length());
+    }
+
+    @Test(dataProvider="parseNumber")
+    public void test_parseNumber(TemporalField field, TextStyle style, int value, String input) throws Exception {
+        ParsePosition pos = new ParsePosition(0);
+        assertEquals(getFormatter(field, style).parseToBuilder(input, pos).getLong(field), (long) value);
+        assertEquals(pos.getIndex(), input.length());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="parseText")
+    public void test_parse_strict_caseSensitive_parseUpper(TemporalField field, TextStyle style, int value, String input) throws Exception {
+        setCaseSensitive(true);
+        ParsePosition pos = new ParsePosition(0);
+        getFormatter(field, style).parseToBuilder(input.toUpperCase(), pos);
+        assertEquals(pos.getErrorIndex(), 0);
+    }
+
+    @Test(dataProvider="parseText")
+    public void test_parse_strict_caseInsensitive_parseUpper(TemporalField field, TextStyle style, int value, String input) throws Exception {
+        setCaseSensitive(false);
+        ParsePosition pos = new ParsePosition(0);
+        assertEquals(getFormatter(field, style).parseToBuilder(input.toUpperCase(), pos).getLong(field), (long) value);
+        assertEquals(pos.getIndex(), input.length());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(dataProvider="parseText")
+    public void test_parse_strict_caseSensitive_parseLower(TemporalField field, TextStyle style, int value, String input) throws Exception {
+        setCaseSensitive(true);
+        ParsePosition pos = new ParsePosition(0);
+        getFormatter(field, style).parseToBuilder(input.toLowerCase(), pos);
+        assertEquals(pos.getErrorIndex(), 0);
+    }
+
+    @Test(dataProvider="parseText")
+    public void test_parse_strict_caseInsensitive_parseLower(TemporalField field, TextStyle style, int value, String input) throws Exception {
+        setCaseSensitive(false);
+        ParsePosition pos = new ParsePosition(0);
+        assertEquals(getFormatter(field, style).parseToBuilder(input.toLowerCase(), pos).getLong(field), (long) value);
+        assertEquals(pos.getIndex(), input.length());
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    public void test_parse_full_strict_full_match() throws Exception {
+        setStrict(true);
+        ParsePosition pos = new ParsePosition(0);
+        assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.FULL).parseToBuilder("January", pos).getLong(MONTH_OF_YEAR), 1L);
+        assertEquals(pos.getIndex(), 7);
+    }
+
+    public void test_parse_full_strict_short_noMatch() throws Exception {
+        setStrict(true);
+        ParsePosition pos = new ParsePosition(0);
+        getFormatter(MONTH_OF_YEAR, TextStyle.FULL).parseToBuilder("Janua", pos);
+        assertEquals(pos.getErrorIndex(), 0);
+    }
+
+    public void test_parse_full_strict_number_noMatch() throws Exception {
+        setStrict(true);
+        ParsePosition pos = new ParsePosition(0);
+        getFormatter(MONTH_OF_YEAR, TextStyle.FULL).parseToBuilder("1", pos);
+        assertEquals(pos.getErrorIndex(), 0);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_parse_short_strict_full_match() throws Exception {
+        setStrict(true);
+        ParsePosition pos = new ParsePosition(0);
+        assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).parseToBuilder("January", pos).getLong(MONTH_OF_YEAR), 1L);
+        assertEquals(pos.getIndex(), 3);
+    }
+
+    public void test_parse_short_strict_short_match() throws Exception {
+        setStrict(true);
+        ParsePosition pos = new ParsePosition(0);
+        assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).parseToBuilder("Janua", pos).getLong(MONTH_OF_YEAR), 1L);
+        assertEquals(pos.getIndex(), 3);
+    }
+
+    public void test_parse_short_strict_number_noMatch() throws Exception {
+        setStrict(true);
+        ParsePosition pos = new ParsePosition(0);
+        getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).parseToBuilder("1", pos);
+        assertEquals(pos.getErrorIndex(), 0);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_parse_french_short_strict_full_noMatch() throws Exception {
+        setStrict(true);
+        ParsePosition pos = new ParsePosition(0);
+        getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).withLocale(Locale.FRENCH)
+                                                    .parseToBuilder("janvier", pos);
+        assertEquals(pos.getErrorIndex(), 0);
+    }
+
+    public void test_parse_french_short_strict_short_match() throws Exception {
+        setStrict(true);
+        ParsePosition pos = new ParsePosition(0);
+        assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).withLocale(Locale.FRENCH)
+                                                                 .parseToBuilder("janv.", pos)
+                                                                 .getLong(MONTH_OF_YEAR),
+                     1L);
+        assertEquals(pos.getIndex(), 5);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_parse_full_lenient_full_match() throws Exception {
+        setStrict(false);
+        ParsePosition pos = new ParsePosition(0);
+        assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.FULL).parseToBuilder("January.", pos).getLong(MONTH_OF_YEAR), 1L);
+        assertEquals(pos.getIndex(), 7);
+    }
+
+    public void test_parse_full_lenient_short_match() throws Exception {
+        setStrict(false);
+        ParsePosition pos = new ParsePosition(0);
+        assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.FULL).parseToBuilder("Janua", pos).getLong(MONTH_OF_YEAR), 1L);
+        assertEquals(pos.getIndex(), 3);
+    }
+
+    public void test_parse_full_lenient_number_match() throws Exception {
+        setStrict(false);
+        ParsePosition pos = new ParsePosition(0);
+        assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.FULL).parseToBuilder("1", pos).getLong(MONTH_OF_YEAR), 1L);
+        assertEquals(pos.getIndex(), 1);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_parse_short_lenient_full_match() throws Exception {
+        setStrict(false);
+        ParsePosition pos = new ParsePosition(0);
+        assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).parseToBuilder("January", pos).getLong(MONTH_OF_YEAR), 1L);
+        assertEquals(pos.getIndex(), 7);
+    }
+
+    public void test_parse_short_lenient_short_match() throws Exception {
+        setStrict(false);
+        ParsePosition pos = new ParsePosition(0);
+        assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).parseToBuilder("Janua", pos).getLong(MONTH_OF_YEAR), 1L);
+        assertEquals(pos.getIndex(), 3);
+    }
+
+    public void test_parse_short_lenient_number_match() throws Exception {
+        setStrict(false);
+        ParsePosition pos = new ParsePosition(0);
+        assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).parseToBuilder("1", pos).getLong(MONTH_OF_YEAR), 1L);
+        assertEquals(pos.getIndex(), 1);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/format/TestTextPrinter.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.format;
+
+import java.time.format.*;
+
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.DAY_OF_WEEK;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static org.testng.Assert.assertEquals;
+
+import java.util.Locale;
+
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.temporal.TemporalField;
+import test.java.time.temporal.MockFieldValue;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test TextPrinterParser.
+ */
+@Test(groups={"implementation"})
+public class TestTextPrinter extends AbstractTestPrinterParser {
+
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=DateTimeException.class)
+    public void test_print_emptyCalendrical() throws Exception {
+        getFormatter(DAY_OF_WEEK, TextStyle.FULL).printTo(EMPTY_DTA, buf);
+    }
+
+    public void test_print_append() throws Exception {
+        buf.append("EXISTING");
+        getFormatter(DAY_OF_WEEK, TextStyle.FULL).printTo(LocalDate.of(2012, 4, 18), buf);
+        assertEquals(buf.toString(), "EXISTINGWednesday");
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="print")
+    Object[][] provider_dow() {
+        return new Object[][] {
+            {DAY_OF_WEEK, TextStyle.FULL, 1, "Monday"},
+            {DAY_OF_WEEK, TextStyle.FULL, 2, "Tuesday"},
+            {DAY_OF_WEEK, TextStyle.FULL, 3, "Wednesday"},
+            {DAY_OF_WEEK, TextStyle.FULL, 4, "Thursday"},
+            {DAY_OF_WEEK, TextStyle.FULL, 5, "Friday"},
+            {DAY_OF_WEEK, TextStyle.FULL, 6, "Saturday"},
+            {DAY_OF_WEEK, TextStyle.FULL, 7, "Sunday"},
+
+            {DAY_OF_WEEK, TextStyle.SHORT, 1, "Mon"},
+            {DAY_OF_WEEK, TextStyle.SHORT, 2, "Tue"},
+            {DAY_OF_WEEK, TextStyle.SHORT, 3, "Wed"},
+            {DAY_OF_WEEK, TextStyle.SHORT, 4, "Thu"},
+            {DAY_OF_WEEK, TextStyle.SHORT, 5, "Fri"},
+            {DAY_OF_WEEK, TextStyle.SHORT, 6, "Sat"},
+            {DAY_OF_WEEK, TextStyle.SHORT, 7, "Sun"},
+
+            {DAY_OF_WEEK, TextStyle.NARROW, 1, "M"},
+            {DAY_OF_WEEK, TextStyle.NARROW, 2, "T"},
+            {DAY_OF_WEEK, TextStyle.NARROW, 3, "W"},
+            {DAY_OF_WEEK, TextStyle.NARROW, 4, "T"},
+            {DAY_OF_WEEK, TextStyle.NARROW, 5, "F"},
+            {DAY_OF_WEEK, TextStyle.NARROW, 6, "S"},
+            {DAY_OF_WEEK, TextStyle.NARROW, 7, "S"},
+
+            {DAY_OF_MONTH, TextStyle.FULL, 1, "1"},
+            {DAY_OF_MONTH, TextStyle.FULL, 2, "2"},
+            {DAY_OF_MONTH, TextStyle.FULL, 3, "3"},
+            {DAY_OF_MONTH, TextStyle.FULL, 28, "28"},
+            {DAY_OF_MONTH, TextStyle.FULL, 29, "29"},
+            {DAY_OF_MONTH, TextStyle.FULL, 30, "30"},
+            {DAY_OF_MONTH, TextStyle.FULL, 31, "31"},
+
+            {DAY_OF_MONTH, TextStyle.SHORT, 1, "1"},
+            {DAY_OF_MONTH, TextStyle.SHORT, 2, "2"},
+            {DAY_OF_MONTH, TextStyle.SHORT, 3, "3"},
+            {DAY_OF_MONTH, TextStyle.SHORT, 28, "28"},
+            {DAY_OF_MONTH, TextStyle.SHORT, 29, "29"},
+            {DAY_OF_MONTH, TextStyle.SHORT, 30, "30"},
+            {DAY_OF_MONTH, TextStyle.SHORT, 31, "31"},
+
+            {MONTH_OF_YEAR, TextStyle.FULL, 1, "January"},
+            {MONTH_OF_YEAR, TextStyle.FULL, 2, "February"},
+            {MONTH_OF_YEAR, TextStyle.FULL, 3, "March"},
+            {MONTH_OF_YEAR, TextStyle.FULL, 4, "April"},
+            {MONTH_OF_YEAR, TextStyle.FULL, 5, "May"},
+            {MONTH_OF_YEAR, TextStyle.FULL, 6, "June"},
+            {MONTH_OF_YEAR, TextStyle.FULL, 7, "July"},
+            {MONTH_OF_YEAR, TextStyle.FULL, 8, "August"},
+            {MONTH_OF_YEAR, TextStyle.FULL, 9, "September"},
+            {MONTH_OF_YEAR, TextStyle.FULL, 10, "October"},
+            {MONTH_OF_YEAR, TextStyle.FULL, 11, "November"},
+            {MONTH_OF_YEAR, TextStyle.FULL, 12, "December"},
+
+            {MONTH_OF_YEAR, TextStyle.SHORT, 1, "Jan"},
+            {MONTH_OF_YEAR, TextStyle.SHORT, 2, "Feb"},
+            {MONTH_OF_YEAR, TextStyle.SHORT, 3, "Mar"},
+            {MONTH_OF_YEAR, TextStyle.SHORT, 4, "Apr"},
+            {MONTH_OF_YEAR, TextStyle.SHORT, 5, "May"},
+            {MONTH_OF_YEAR, TextStyle.SHORT, 6, "Jun"},
+            {MONTH_OF_YEAR, TextStyle.SHORT, 7, "Jul"},
+            {MONTH_OF_YEAR, TextStyle.SHORT, 8, "Aug"},
+            {MONTH_OF_YEAR, TextStyle.SHORT, 9, "Sep"},
+            {MONTH_OF_YEAR, TextStyle.SHORT, 10, "Oct"},
+            {MONTH_OF_YEAR, TextStyle.SHORT, 11, "Nov"},
+            {MONTH_OF_YEAR, TextStyle.SHORT, 12, "Dec"},
+       };
+    }
+
+    @Test(dataProvider="print")
+    public void test_print(TemporalField field, TextStyle style, int value, String expected) throws Exception {
+        getFormatter(field, style).printTo(new MockFieldValue(field, value), buf);
+        assertEquals(buf.toString(), expected);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_print_french_long() throws Exception {
+        getFormatter(MONTH_OF_YEAR, TextStyle.FULL).withLocale(Locale.FRENCH).printTo(LocalDate.of(2012, 1, 1), buf);
+        assertEquals(buf.toString(), "janvier");
+    }
+
+    public void test_print_french_short() throws Exception {
+        getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).withLocale(Locale.FRENCH).printTo(LocalDate.of(2012, 1, 1), buf);
+        assertEquals(buf.toString(), "janv.");
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_toString1() throws Exception {
+        assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.FULL).toString(), "Text(MonthOfYear)");
+    }
+
+    public void test_toString2() throws Exception {
+        assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).toString(), "Text(MonthOfYear,SHORT)");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/format/TestZoneIdParser.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.format;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Set;
+
+import java.text.ParsePosition;
+import java.time.ZoneId;
+import java.time.format.DateTimeBuilder;
+import java.time.format.DateTimeFormatter;
+import java.time.format.TextStyle;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.temporal.Queries;
+import java.time.zone.ZoneRulesProvider;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test ZonePrinterParser.
+ */
+@Test(groups={"implementation"})
+public class TestZoneIdParser extends AbstractTestPrinterParser {
+
+    private static final String AMERICA_DENVER = "America/Denver";
+    private static final ZoneId TIME_ZONE_DENVER = ZoneId.of(AMERICA_DENVER);
+
+    private DateTimeFormatter getFormatter0(TextStyle style) {
+        if (style == null)
+            return builder.appendZoneId().toFormatter(locale).withSymbols(symbols);
+        return builder.appendZoneText(style).toFormatter(locale).withSymbols(symbols);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="error")
+    Object[][] data_error() {
+        return new Object[][] {
+            {null, "hello", -1, IndexOutOfBoundsException.class},
+            {null, "hello", 6, IndexOutOfBoundsException.class},
+        };
+    }
+
+    @Test(dataProvider="error")
+    public void test_parse_error(TextStyle style, String text, int pos, Class<?> expected) {
+        try {
+            getFormatter0(style).parseToBuilder(text, new ParsePosition(pos));
+            assertTrue(false);
+        } catch (RuntimeException ex) {
+            assertTrue(expected.isInstance(ex));
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_parse_exactMatch_Denver() throws Exception {
+        ParsePosition pos = new ParsePosition(0);
+        DateTimeBuilder dtb = getFormatter0(null).parseToBuilder(AMERICA_DENVER, pos);
+        assertEquals(pos.getIndex(), AMERICA_DENVER.length());
+        assertParsed(dtb, TIME_ZONE_DENVER);
+    }
+
+    public void test_parse_startStringMatch_Denver() throws Exception {
+        ParsePosition pos = new ParsePosition(0);
+        DateTimeBuilder dtb = getFormatter0(null).parseToBuilder(AMERICA_DENVER + "OTHER", pos);
+        assertEquals(pos.getIndex(), AMERICA_DENVER.length());
+        assertParsed(dtb, TIME_ZONE_DENVER);
+    }
+
+    public void test_parse_midStringMatch_Denver() throws Exception {
+        ParsePosition pos = new ParsePosition(5);
+        DateTimeBuilder dtb = getFormatter0(null).parseToBuilder("OTHER" + AMERICA_DENVER + "OTHER", pos);
+        assertEquals(pos.getIndex(), 5 + AMERICA_DENVER.length());
+        assertParsed(dtb, TIME_ZONE_DENVER);
+    }
+
+    public void test_parse_endStringMatch_Denver() throws Exception {
+        ParsePosition pos = new ParsePosition(5);
+        DateTimeBuilder dtb = getFormatter0(null).parseToBuilder("OTHER" + AMERICA_DENVER, pos);
+        assertEquals(pos.getIndex(), 5 + AMERICA_DENVER.length());
+        assertParsed(dtb, TIME_ZONE_DENVER);
+    }
+
+    public void test_parse_partialMatch() throws Exception {
+        ParsePosition pos = new ParsePosition(5);
+        DateTimeBuilder dtb = getFormatter0(null).parseToBuilder("OTHERAmerica/Bogusville", pos);
+        assertEquals(pos.getErrorIndex(), 5);  // TBD: -6 ?
+        assertEquals(dtb, null);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="zones")
+    Object[][] populateTestData() {
+        Set<String> ids = ZoneRulesProvider.getAvailableZoneIds();
+        Object[][] rtnval = new Object[ids.size()][];
+        int i = 0;
+        for (String id : ids) {
+            rtnval[i++] = new Object[] { id, ZoneId.of(id) };
+        }
+        return rtnval;
+    }
+
+    @Test(dataProvider="zones")
+    public void test_parse_exactMatch(String parse, ZoneId expected) throws Exception {
+        ParsePosition pos = new ParsePosition(0);
+        DateTimeBuilder dtb = getFormatter0(null).parseToBuilder(parse, pos);
+        assertEquals(pos.getIndex(), parse.length());
+        assertParsed(dtb, expected);
+    }
+
+    @Test(dataProvider="zones")
+    public void test_parse_startMatch(String parse, ZoneId expected) throws Exception {
+        String append = " OTHER";
+        parse += append;
+        ParsePosition pos = new ParsePosition(0);
+        DateTimeBuilder dtb = getFormatter0(null).parseToBuilder(parse, pos);
+        assertEquals(pos.getIndex(), parse.length() - append.length());
+        assertParsed(dtb, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_parse_caseInsensitive() throws Exception {
+        DateTimeFormatter fmt = new DateTimeFormatterBuilder().appendZoneId().toFormatter();
+        DateTimeFormatter fmtCI = new DateTimeFormatterBuilder().parseCaseInsensitive()
+                                                                .appendZoneId()
+                                                                .toFormatter();
+        for (String zidStr : ZoneRulesProvider.getAvailableZoneIds()) {
+            ZoneId zid = ZoneId.of(zidStr);
+            assertEquals(fmt.parse(zidStr, Queries.zoneId()), zid);
+            assertEquals(fmtCI.parse(zidStr.toLowerCase(), Queries.zoneId()), zid);
+            assertEquals(fmtCI.parse(zidStr.toUpperCase(), Queries.zoneId()), zid);
+            ParsePosition pos = new ParsePosition(5);
+            assertEquals(fmtCI.parseToBuilder("OTHER" + zidStr.toLowerCase() + "OTHER", pos)
+                              .query(Queries.zoneId()), zid);
+            assertEquals(pos.getIndex(), zidStr.length() + 5);
+            pos = new ParsePosition(5);
+            assertEquals(fmtCI.parseToBuilder("OTHER" + zidStr.toUpperCase() + "OTHER", pos)
+                              .query(Queries.zoneId()), zid);
+            assertEquals(pos.getIndex(), zidStr.length() + 5);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /*
+    public void test_parse_endStringMatch_utc() throws Exception {
+        ParsePosition pos = new ParsePosition(5);
+        DateTimeBuilder dtb = getFormatter0(null).parseToBuilder("OTHERUTC", pos);
+        assertEquals(pos.getIndex(), 8);
+        assertParsed(dtb, ZoneOffset.UTC);
+    }
+
+    public void test_parse_endStringMatch_utc_plus1() throws Exception {
+        ParsePosition pos = new ParsePosition(5);
+        DateTimeBuilder dtb = getFormatter0(null).parseToBuilder("OTHERUTC+01:00", pos);
+        assertEquals(pos.getIndex(), 14);
+        assertParsed(dtb, ZoneId.of("UTC+01:00"));
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_parse_midStringMatch_utc() throws Exception {
+        ParsePosition pos = new ParsePosition(5);
+        DateTimeBuilder dtb = getFormatter0(null).parseToBuilder("OTHERUTCOTHER", pos);
+        assertEquals(pos.getIndex(), 8);
+        assertParsed(dtb, ZoneOffset.UTC);
+    }
+
+    public void test_parse_midStringMatch_utc_plus1() throws Exception {
+        ParsePosition pos = new ParsePosition(5);
+        DateTimeBuilder dtb = getFormatter0(null).parseToBuilder("OTHERUTC+01:00OTHER", pos);
+        assertEquals(pos.getIndex(), 14);
+        assertParsed(dtb, ZoneId.of("UTC+01:00"));
+    }
+    */
+    //-----------------------------------------------------------------------
+    public void test_toString_id() {
+        assertEquals(getFormatter0(null).toString(), "ZoneId()");
+    }
+
+    public void test_toString_text() {
+        assertEquals(getFormatter0(TextStyle.FULL).toString(), "ZoneText(FULL)");
+    }
+
+    private void assertParsed(DateTimeBuilder dtb, ZoneId expectedZone) {
+        assertEquals(dtb.query(ZoneId::from), expectedZone);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/format/TestZoneOffsetParser.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,444 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.format;
+
+import static java.time.temporal.ChronoField.OFFSET_SECONDS;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.text.ParsePosition;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeBuilder;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test ZoneOffsetPrinterParser.
+ */
+@Test(groups={"implementation"})
+public class TestZoneOffsetParser extends AbstractTestPrinterParser {
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="error")
+    Object[][] data_error() {
+        return new Object[][] {
+            {"+HH:MM:ss", "Z", "hello", -1, IndexOutOfBoundsException.class},
+            {"+HH:MM:ss", "Z", "hello", 6, IndexOutOfBoundsException.class},
+        };
+    }
+
+    @Test(dataProvider="error")
+    public void test_parse_error(String pattern, String noOffsetText, String text, int pos, Class<?> expected) {
+        try {
+            getFormatter(pattern, noOffsetText).parseToBuilder(text, new ParsePosition(pos));
+        } catch (RuntimeException ex) {
+            assertTrue(expected.isInstance(ex));
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_parse_exactMatch_UTC() throws Exception {
+        ParsePosition pos = new ParsePosition(0);
+        DateTimeBuilder dtb = getFormatter("+HH:MM:ss", "Z").parseToBuilder("Z", pos);
+        assertEquals(pos.getIndex(), 1);
+        assertParsed(dtb, ZoneOffset.UTC);
+    }
+
+    public void test_parse_startStringMatch_UTC() throws Exception {
+        ParsePosition pos = new ParsePosition(0);
+        DateTimeBuilder dtb = getFormatter("+HH:MM:ss", "Z").parseToBuilder("ZOTHER", pos);
+        assertEquals(pos.getIndex(), 1);
+        assertParsed(dtb, ZoneOffset.UTC);
+    }
+
+    public void test_parse_midStringMatch_UTC() throws Exception {
+        ParsePosition pos = new ParsePosition(5);
+        DateTimeBuilder dtb = getFormatter("+HH:MM:ss", "Z").parseToBuilder("OTHERZOTHER", pos);
+        assertEquals(pos.getIndex(), 6);
+        assertParsed(dtb, ZoneOffset.UTC);
+    }
+
+    public void test_parse_endStringMatch_UTC() throws Exception {
+        ParsePosition pos = new ParsePosition(5);
+        DateTimeBuilder dtb = getFormatter("+HH:MM:ss", "Z").parseToBuilder("OTHERZ", pos);
+        assertEquals(pos.getIndex(), 6);
+        assertParsed(dtb, ZoneOffset.UTC);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_parse_exactMatch_UTC_EmptyUTC() throws Exception {
+        ParsePosition pos = new ParsePosition(0);
+        DateTimeBuilder dtb = getFormatter("+HH:MM:ss", "").parseToBuilder("", pos);
+        assertEquals(pos.getIndex(), 0);
+        assertParsed(dtb, ZoneOffset.UTC);
+    }
+
+    public void test_parse_startStringMatch_UTC_EmptyUTC() throws Exception {
+        ParsePosition pos = new ParsePosition(0);
+        DateTimeBuilder dtb = getFormatter("+HH:MM:ss", "").parseToBuilder("OTHER", pos);
+        assertEquals(pos.getIndex(), 0);
+        assertParsed(dtb, ZoneOffset.UTC);
+    }
+
+    public void test_parse_midStringMatch_UTC_EmptyUTC() throws Exception {
+        ParsePosition pos = new ParsePosition(5);
+        DateTimeBuilder dtb = getFormatter("+HH:MM:ss", "").parseToBuilder("OTHEROTHER", pos);
+        assertEquals(pos.getIndex(), 5);
+        assertParsed(dtb, ZoneOffset.UTC);
+    }
+
+    public void test_parse_endStringMatch_UTC_EmptyUTC() throws Exception {
+        ParsePosition pos = new ParsePosition(5);
+        DateTimeBuilder dtb = getFormatter("+HH:MM:ss", "").parseToBuilder("OTHER", pos);
+        assertEquals(pos.getIndex(), 5);
+        assertParsed(dtb, ZoneOffset.UTC);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="offsets")
+    Object[][] provider_offsets() {
+        return new Object[][] {
+            {"+HH", "+00", ZoneOffset.UTC},
+            {"+HH", "-00", ZoneOffset.UTC},
+            {"+HH", "+01", ZoneOffset.ofHours(1)},
+            {"+HH", "-01", ZoneOffset.ofHours(-1)},
+
+            {"+HHMM", "+0000", ZoneOffset.UTC},
+            {"+HHMM", "-0000", ZoneOffset.UTC},
+            {"+HHMM", "+0102", ZoneOffset.ofHoursMinutes(1, 2)},
+            {"+HHMM", "-0102", ZoneOffset.ofHoursMinutes(-1, -2)},
+
+            {"+HH:MM", "+00:00", ZoneOffset.UTC},
+            {"+HH:MM", "-00:00", ZoneOffset.UTC},
+            {"+HH:MM", "+01:02", ZoneOffset.ofHoursMinutes(1, 2)},
+            {"+HH:MM", "-01:02", ZoneOffset.ofHoursMinutes(-1, -2)},
+
+            {"+HHMMss", "+0000", ZoneOffset.UTC},
+            {"+HHMMss", "-0000", ZoneOffset.UTC},
+            {"+HHMMss", "+0100", ZoneOffset.ofHoursMinutesSeconds(1, 0, 0)},
+            {"+HHMMss", "+0159", ZoneOffset.ofHoursMinutesSeconds(1, 59, 0)},
+            {"+HHMMss", "+0200", ZoneOffset.ofHoursMinutesSeconds(2, 0, 0)},
+            {"+HHMMss", "+1800", ZoneOffset.ofHoursMinutesSeconds(18, 0, 0)},
+            {"+HHMMss", "+010215", ZoneOffset.ofHoursMinutesSeconds(1, 2, 15)},
+            {"+HHMMss", "-0100", ZoneOffset.ofHoursMinutesSeconds(-1, 0, 0)},
+            {"+HHMMss", "-0200", ZoneOffset.ofHoursMinutesSeconds(-2, 0, 0)},
+            {"+HHMMss", "-1800", ZoneOffset.ofHoursMinutesSeconds(-18, 0, 0)},
+
+            {"+HHMMss", "+000000", ZoneOffset.UTC},
+            {"+HHMMss", "-000000", ZoneOffset.UTC},
+            {"+HHMMss", "+010000", ZoneOffset.ofHoursMinutesSeconds(1, 0, 0)},
+            {"+HHMMss", "+010203", ZoneOffset.ofHoursMinutesSeconds(1, 2, 3)},
+            {"+HHMMss", "+015959", ZoneOffset.ofHoursMinutesSeconds(1, 59, 59)},
+            {"+HHMMss", "+020000", ZoneOffset.ofHoursMinutesSeconds(2, 0, 0)},
+            {"+HHMMss", "+180000", ZoneOffset.ofHoursMinutesSeconds(18, 0, 0)},
+            {"+HHMMss", "-010000", ZoneOffset.ofHoursMinutesSeconds(-1, 0, 0)},
+            {"+HHMMss", "-020000", ZoneOffset.ofHoursMinutesSeconds(-2, 0, 0)},
+            {"+HHMMss", "-180000", ZoneOffset.ofHoursMinutesSeconds(-18, 0, 0)},
+
+            {"+HH:MM:ss", "+00:00", ZoneOffset.UTC},
+            {"+HH:MM:ss", "-00:00", ZoneOffset.UTC},
+            {"+HH:MM:ss", "+01:00", ZoneOffset.ofHoursMinutesSeconds(1, 0, 0)},
+            {"+HH:MM:ss", "+01:02", ZoneOffset.ofHoursMinutesSeconds(1, 2, 0)},
+            {"+HH:MM:ss", "+01:59", ZoneOffset.ofHoursMinutesSeconds(1, 59, 0)},
+            {"+HH:MM:ss", "+02:00", ZoneOffset.ofHoursMinutesSeconds(2, 0, 0)},
+            {"+HH:MM:ss", "+18:00", ZoneOffset.ofHoursMinutesSeconds(18, 0, 0)},
+            {"+HH:MM:ss", "+01:02:15", ZoneOffset.ofHoursMinutesSeconds(1, 2, 15)},
+            {"+HH:MM:ss", "-01:00", ZoneOffset.ofHoursMinutesSeconds(-1, 0, 0)},
+            {"+HH:MM:ss", "-02:00", ZoneOffset.ofHoursMinutesSeconds(-2, 0, 0)},
+            {"+HH:MM:ss", "-18:00", ZoneOffset.ofHoursMinutesSeconds(-18, 0, 0)},
+
+            {"+HH:MM:ss", "+00:00:00", ZoneOffset.UTC},
+            {"+HH:MM:ss", "-00:00:00", ZoneOffset.UTC},
+            {"+HH:MM:ss", "+01:00:00", ZoneOffset.ofHoursMinutesSeconds(1, 0, 0)},
+            {"+HH:MM:ss", "+01:02:03", ZoneOffset.ofHoursMinutesSeconds(1, 2, 3)},
+            {"+HH:MM:ss", "+01:59:59", ZoneOffset.ofHoursMinutesSeconds(1, 59, 59)},
+            {"+HH:MM:ss", "+02:00:00", ZoneOffset.ofHoursMinutesSeconds(2, 0, 0)},
+            {"+HH:MM:ss", "+18:00:00", ZoneOffset.ofHoursMinutesSeconds(18, 0, 0)},
+            {"+HH:MM:ss", "-01:00:00", ZoneOffset.ofHoursMinutesSeconds(-1, 0, 0)},
+            {"+HH:MM:ss", "-02:00:00", ZoneOffset.ofHoursMinutesSeconds(-2, 0, 0)},
+            {"+HH:MM:ss", "-18:00:00", ZoneOffset.ofHoursMinutesSeconds(-18, 0, 0)},
+
+            {"+HHMMSS", "+000000", ZoneOffset.UTC},
+            {"+HHMMSS", "-000000", ZoneOffset.UTC},
+            {"+HHMMSS", "+010203", ZoneOffset.ofHoursMinutesSeconds(1, 2, 3)},
+            {"+HHMMSS", "-010203", ZoneOffset.ofHoursMinutesSeconds(-1, -2, -3)},
+
+            {"+HH:MM:SS", "+00:00:00", ZoneOffset.UTC},
+            {"+HH:MM:SS", "-00:00:00", ZoneOffset.UTC},
+            {"+HH:MM:SS", "+01:02:03", ZoneOffset.ofHoursMinutesSeconds(1, 2, 3)},
+            {"+HH:MM:SS", "-01:02:03", ZoneOffset.ofHoursMinutesSeconds(-1, -2, -3)},
+        };
+    }
+
+    @Test(dataProvider="offsets")
+    public void test_parse_exactMatch(String pattern, String parse, ZoneOffset expected) throws Exception {
+        ParsePosition pos = new ParsePosition(0);
+        DateTimeBuilder dtb = getFormatter(pattern, "Z").parseToBuilder(parse, pos);
+        assertEquals(pos.getIndex(), parse.length());
+        assertParsed(dtb, expected);
+    }
+
+    @Test(dataProvider="offsets")
+    public void test_parse_startStringMatch(String pattern, String parse, ZoneOffset expected) throws Exception {
+        ParsePosition pos = new ParsePosition(0);
+        DateTimeBuilder dtb = getFormatter(pattern, "Z").parseToBuilder(parse + ":OTHER", pos);
+        assertEquals(pos.getIndex(), parse.length());
+        assertParsed(dtb, expected);
+    }
+
+    @Test(dataProvider="offsets")
+    public void test_parse_midStringMatch(String pattern, String parse, ZoneOffset expected) throws Exception {
+        ParsePosition pos = new ParsePosition(5);
+        DateTimeBuilder dtb = getFormatter(pattern, "Z").parseToBuilder("OTHER" + parse + ":OTHER", pos);
+        assertEquals(pos.getIndex(), parse.length() + 5);
+        assertParsed(dtb, expected);
+    }
+
+    @Test(dataProvider="offsets")
+    public void test_parse_endStringMatch(String pattern, String parse, ZoneOffset expected) throws Exception {
+        ParsePosition pos = new ParsePosition(5);
+        DateTimeBuilder dtb = getFormatter(pattern, "Z").parseToBuilder("OTHER" + parse, pos);
+        assertEquals(pos.getIndex(), parse.length() + 5);
+        assertParsed(dtb, expected);
+    }
+
+    @Test(dataProvider="offsets")
+    public void test_parse_exactMatch_EmptyUTC(String pattern, String parse, ZoneOffset expected) throws Exception {
+        ParsePosition pos = new ParsePosition(0);
+        DateTimeBuilder dtb = getFormatter(pattern, "").parseToBuilder(parse, pos);
+        assertEquals(pos.getIndex(), parse.length());
+        assertParsed(dtb, expected);
+    }
+
+    @Test(dataProvider="offsets")
+    public void test_parse_startStringMatch_EmptyUTC(String pattern, String parse, ZoneOffset expected) throws Exception {
+        ParsePosition pos = new ParsePosition(0);
+        DateTimeBuilder dtb = getFormatter(pattern, "").parseToBuilder(parse + ":OTHER", pos);
+        assertEquals(pos.getIndex(), parse.length());
+        assertParsed(dtb, expected);
+    }
+
+    @Test(dataProvider="offsets")
+    public void test_parse_midStringMatch_EmptyUTC(String pattern, String parse, ZoneOffset expected) throws Exception {
+        ParsePosition pos = new ParsePosition(5);
+        DateTimeBuilder dtb = getFormatter(pattern, "").parseToBuilder("OTHER" + parse + ":OTHER", pos);
+        assertEquals(pos.getIndex(), parse.length() + 5);
+        assertParsed(dtb, expected);
+    }
+
+    @Test(dataProvider="offsets")
+    public void test_parse_endStringMatch_EmptyUTC(String pattern, String parse, ZoneOffset expected) throws Exception {
+        ParsePosition pos = new ParsePosition(5);
+        DateTimeBuilder dtb = getFormatter(pattern, "").parseToBuilder("OTHER" + parse, pos);
+        assertEquals(pos.getIndex(), parse.length() + 5);
+        assertParsed(dtb, expected);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="bigOffsets")
+    Object[][] provider_bigOffsets() {
+        return new Object[][] {
+            {"+HH", "+59", 59 * 3600},
+            {"+HH", "-19", -(19 * 3600)},
+
+            {"+HHMM", "+1801", 18 * 3600 + 1 * 60},
+            {"+HHMM", "-1801", -(18 * 3600 + 1 * 60)},
+
+            {"+HH:MM", "+18:01", 18 * 3600 + 1 * 60},
+            {"+HH:MM", "-18:01", -(18 * 3600 + 1 * 60)},
+
+            {"+HHMMss", "+180103", 18 * 3600 + 1 * 60 + 3},
+            {"+HHMMss", "-180103", -(18 * 3600 + 1 * 60 + 3)},
+
+            {"+HH:MM:ss", "+18:01:03", 18 * 3600 + 1 * 60 + 3},
+            {"+HH:MM:ss", "-18:01:03", -(18 * 3600 + 1 * 60 + 3)},
+
+            {"+HHMMSS", "+180103", 18 * 3600 + 1 * 60 + 3},
+            {"+HHMMSS", "-180103", -(18 * 3600 + 1 * 60 + 3)},
+
+            {"+HH:MM:SS", "+18:01:03", 18 * 3600 + 1 * 60 + 3},
+            {"+HH:MM:SS", "-18:01:03", -(18 * 3600 + 1 * 60 + 3)},
+        };
+    }
+
+    @Test(dataProvider="bigOffsets")
+    public void test_parse_bigOffsets(String pattern, String parse, long offsetSecs) throws Exception {
+        ParsePosition pos = new ParsePosition(0);
+        DateTimeBuilder dtb = getFormatter(pattern, "").parseToBuilder(parse, pos);
+        assertEquals(pos.getIndex(), parse.length());
+        assertEquals(dtb.getLong(OFFSET_SECONDS), offsetSecs);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="badOffsets")
+    Object[][] provider_badOffsets() {
+        return new Object[][] {
+            {"+HH", "+1", 0},
+            {"+HH", "-1", 0},
+            {"+HH", "01", 0},
+            {"+HH", "01", 0},
+            {"+HH", "+AA", 0},
+
+            {"+HHMM", "+1", 0},
+            {"+HHMM", "+01", 0},
+            {"+HHMM", "+001", 0},
+            {"+HHMM", "0102", 0},
+            {"+HHMM", "+01:02", 0},
+            {"+HHMM", "+AAAA", 0},
+
+            {"+HH:MM", "+1", 0},
+            {"+HH:MM", "+01", 0},
+            {"+HH:MM", "+0:01", 0},
+            {"+HH:MM", "+00:1", 0},
+            {"+HH:MM", "+0:1", 0},
+            {"+HH:MM", "+:", 0},
+            {"+HH:MM", "01:02", 0},
+            {"+HH:MM", "+0102", 0},
+            {"+HH:MM", "+AA:AA", 0},
+
+            {"+HHMMss", "+1", 0},
+            {"+HHMMss", "+01", 0},
+            {"+HHMMss", "+001", 0},
+            {"+HHMMss", "0102", 0},
+            {"+HHMMss", "+01:02", 0},
+            {"+HHMMss", "+AAAA", 0},
+
+            {"+HH:MM:ss", "+1", 0},
+            {"+HH:MM:ss", "+01", 0},
+            {"+HH:MM:ss", "+0:01", 0},
+            {"+HH:MM:ss", "+00:1", 0},
+            {"+HH:MM:ss", "+0:1", 0},
+            {"+HH:MM:ss", "+:", 0},
+            {"+HH:MM:ss", "01:02", 0},
+            {"+HH:MM:ss", "+0102", 0},
+            {"+HH:MM:ss", "+AA:AA", 0},
+
+            {"+HHMMSS", "+1", 0},
+            {"+HHMMSS", "+01", 0},
+            {"+HHMMSS", "+001", 0},
+            {"+HHMMSS", "0102", 0},
+            {"+HHMMSS", "+01:02", 0},
+            {"+HHMMSS", "+AAAA", 0},
+
+            {"+HH:MM:SS", "+1", 0},
+            {"+HH:MM:SS", "+01", 0},
+            {"+HH:MM:SS", "+0:01", 0},
+            {"+HH:MM:SS", "+00:1", 0},
+            {"+HH:MM:SS", "+0:1", 0},
+            {"+HH:MM:SS", "+:", 0},
+            {"+HH:MM:SS", "01:02", 0},
+            {"+HH:MM:SS", "+0102", 0},
+            {"+HH:MM:SS", "+AA:AA", 0},
+        };
+    }
+
+    @Test(dataProvider="badOffsets")
+    public void test_parse_invalid(String pattern, String parse, int expectedPosition) throws Exception {
+        ParsePosition pos = new ParsePosition(0);
+        DateTimeBuilder dtb = getFormatter(pattern, "Z").parseToBuilder(parse, pos);
+        assertEquals(pos.getErrorIndex(), expectedPosition);
+    }
+
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    //-----------------------------------------------------------------------
+    public void test_parse_caseSensitiveUTC_matchedCase() throws Exception {
+        setCaseSensitive(true);
+        ParsePosition pos = new ParsePosition(0);
+        DateTimeBuilder dtb = getFormatter("+HH:MM:ss", "Z").parseToBuilder("Z", pos);
+        assertEquals(pos.getIndex(), 1);
+        assertParsed(dtb, ZoneOffset.UTC);
+    }
+
+    public void test_parse_caseSensitiveUTC_unmatchedCase() throws Exception {
+        setCaseSensitive(true);
+        ParsePosition pos = new ParsePosition(0);
+        DateTimeBuilder dtb = getFormatter("+HH:MM:ss", "Z").parseToBuilder("z", pos);
+        assertEquals(pos.getErrorIndex(), 0);
+        assertEquals(dtb, null);
+    }
+
+    public void test_parse_caseInsensitiveUTC_matchedCase() throws Exception {
+        setCaseSensitive(false);
+        ParsePosition pos = new ParsePosition(0);
+        DateTimeBuilder dtb = getFormatter("+HH:MM:ss", "Z").parseToBuilder("Z", pos);
+        assertEquals(pos.getIndex(), 1);
+        assertParsed(dtb, ZoneOffset.UTC);
+    }
+
+    public void test_parse_caseInsensitiveUTC_unmatchedCase() throws Exception {
+        setCaseSensitive(false);
+        ParsePosition pos = new ParsePosition(0);
+        DateTimeBuilder dtb = getFormatter("+HH:MM:ss", "Z").parseToBuilder("z", pos);
+        assertEquals(pos.getIndex(), 1);
+        assertParsed(dtb, ZoneOffset.UTC);
+    }
+
+    private void assertParsed(DateTimeBuilder dtb, ZoneOffset expectedOffset) {
+        if (expectedOffset == null) {
+            assertEquals(dtb, null);
+        } else {
+            assertEquals(dtb.getFieldValueMap().size(), 1);
+            assertEquals(dtb.getLong(OFFSET_SECONDS), (long) expectedOffset.getTotalSeconds());
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/format/TestZoneOffsetPrinter.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.format;
+
+import static java.time.temporal.ChronoField.OFFSET_SECONDS;
+import static org.testng.Assert.assertEquals;
+
+import java.time.DateTimeException;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeBuilder;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test ZoneOffsetPrinterParser.
+ */
+@Test(groups={"implementation"})
+public class TestZoneOffsetPrinter extends AbstractTestPrinterParser {
+
+    private static final ZoneOffset OFFSET_0130 = ZoneOffset.of("+01:30");
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name="offsets")
+    Object[][] provider_offsets() {
+        return new Object[][] {
+            {"+HH", "NO-OFFSET", ZoneOffset.UTC},
+            {"+HH", "+01", ZoneOffset.ofHours(1)},
+            {"+HH", "-01", ZoneOffset.ofHours(-1)},
+
+            {"+HHMM", "NO-OFFSET", ZoneOffset.UTC},
+            {"+HHMM", "+0102", ZoneOffset.ofHoursMinutes(1, 2)},
+            {"+HHMM", "-0102", ZoneOffset.ofHoursMinutes(-1, -2)},
+
+            {"+HH:MM", "NO-OFFSET", ZoneOffset.UTC},
+            {"+HH:MM", "+01:02", ZoneOffset.ofHoursMinutes(1, 2)},
+            {"+HH:MM", "-01:02", ZoneOffset.ofHoursMinutes(-1, -2)},
+
+            {"+HHMMss", "NO-OFFSET", ZoneOffset.UTC},
+            {"+HHMMss", "+0100", ZoneOffset.ofHoursMinutesSeconds(1, 0, 0)},
+            {"+HHMMss", "+0102", ZoneOffset.ofHoursMinutesSeconds(1, 2, 0)},
+            {"+HHMMss", "+0159", ZoneOffset.ofHoursMinutesSeconds(1, 59, 0)},
+            {"+HHMMss", "+0200", ZoneOffset.ofHoursMinutesSeconds(2, 0, 0)},
+            {"+HHMMss", "+1800", ZoneOffset.ofHoursMinutesSeconds(18, 0, 0)},
+            {"+HHMMss", "+010215", ZoneOffset.ofHoursMinutesSeconds(1, 2, 15)},
+            {"+HHMMss", "-0100", ZoneOffset.ofHoursMinutesSeconds(-1, 0, 0)},
+            {"+HHMMss", "-0200", ZoneOffset.ofHoursMinutesSeconds(-2, 0, 0)},
+            {"+HHMMss", "-1800", ZoneOffset.ofHoursMinutesSeconds(-18, 0, 0)},
+
+            {"+HHMMss", "NO-OFFSET", ZoneOffset.UTC},
+            {"+HHMMss", "+0100", ZoneOffset.ofHoursMinutesSeconds(1, 0, 0)},
+            {"+HHMMss", "+010203", ZoneOffset.ofHoursMinutesSeconds(1, 2, 3)},
+            {"+HHMMss", "+015959", ZoneOffset.ofHoursMinutesSeconds(1, 59, 59)},
+            {"+HHMMss", "+0200", ZoneOffset.ofHoursMinutesSeconds(2, 0, 0)},
+            {"+HHMMss", "+1800", ZoneOffset.ofHoursMinutesSeconds(18, 0, 0)},
+            {"+HHMMss", "-0100", ZoneOffset.ofHoursMinutesSeconds(-1, 0, 0)},
+            {"+HHMMss", "-0200", ZoneOffset.ofHoursMinutesSeconds(-2, 0, 0)},
+            {"+HHMMss", "-1800", ZoneOffset.ofHoursMinutesSeconds(-18, 0, 0)},
+
+            {"+HH:MM:ss", "NO-OFFSET", ZoneOffset.UTC},
+            {"+HH:MM:ss", "+01:00", ZoneOffset.ofHoursMinutesSeconds(1, 0, 0)},
+            {"+HH:MM:ss", "+01:02", ZoneOffset.ofHoursMinutesSeconds(1, 2, 0)},
+            {"+HH:MM:ss", "+01:59", ZoneOffset.ofHoursMinutesSeconds(1, 59, 0)},
+            {"+HH:MM:ss", "+02:00", ZoneOffset.ofHoursMinutesSeconds(2, 0, 0)},
+            {"+HH:MM:ss", "+18:00", ZoneOffset.ofHoursMinutesSeconds(18, 0, 0)},
+            {"+HH:MM:ss", "+01:02:15", ZoneOffset.ofHoursMinutesSeconds(1, 2, 15)},
+            {"+HH:MM:ss", "-01:00", ZoneOffset.ofHoursMinutesSeconds(-1, 0, 0)},
+            {"+HH:MM:ss", "-02:00", ZoneOffset.ofHoursMinutesSeconds(-2, 0, 0)},
+            {"+HH:MM:ss", "-18:00", ZoneOffset.ofHoursMinutesSeconds(-18, 0, 0)},
+
+            {"+HH:MM:ss", "NO-OFFSET", ZoneOffset.UTC},
+            {"+HH:MM:ss", "+01:00", ZoneOffset.ofHoursMinutesSeconds(1, 0, 0)},
+            {"+HH:MM:ss", "+01:02:03", ZoneOffset.ofHoursMinutesSeconds(1, 2, 3)},
+            {"+HH:MM:ss", "+01:59:59", ZoneOffset.ofHoursMinutesSeconds(1, 59, 59)},
+            {"+HH:MM:ss", "+02:00", ZoneOffset.ofHoursMinutesSeconds(2, 0, 0)},
+            {"+HH:MM:ss", "+18:00", ZoneOffset.ofHoursMinutesSeconds(18, 0, 0)},
+            {"+HH:MM:ss", "-01:00", ZoneOffset.ofHoursMinutesSeconds(-1, 0, 0)},
+            {"+HH:MM:ss", "-02:00", ZoneOffset.ofHoursMinutesSeconds(-2, 0, 0)},
+            {"+HH:MM:ss", "-18:00", ZoneOffset.ofHoursMinutesSeconds(-18, 0, 0)},
+
+            {"+HHMMSS", "NO-OFFSET", ZoneOffset.UTC},
+            {"+HHMMSS", "+010203", ZoneOffset.ofHoursMinutesSeconds(1, 2, 3)},
+            {"+HHMMSS", "-010203", ZoneOffset.ofHoursMinutesSeconds(-1, -2, -3)},
+            {"+HHMMSS", "+010200", ZoneOffset.ofHoursMinutesSeconds(1, 2, 0)},
+            {"+HHMMSS", "-010200", ZoneOffset.ofHoursMinutesSeconds(-1, -2, 0)},
+
+            {"+HH:MM:SS", "NO-OFFSET", ZoneOffset.UTC},
+            {"+HH:MM:SS", "+01:02:03", ZoneOffset.ofHoursMinutesSeconds(1, 2, 3)},
+            {"+HH:MM:SS", "-01:02:03", ZoneOffset.ofHoursMinutesSeconds(-1, -2, -3)},
+            {"+HH:MM:SS", "+01:02:00", ZoneOffset.ofHoursMinutesSeconds(1, 2, 0)},
+            {"+HH:MM:SS", "-01:02:00", ZoneOffset.ofHoursMinutesSeconds(-1, -2, 0)},
+        };
+    }
+
+    @Test(dataProvider="offsets")
+    public void test_print(String pattern, String expected, ZoneOffset offset) throws Exception {
+        buf.append("EXISTING");
+        getFormatter(pattern, "NO-OFFSET").printTo(new DateTimeBuilder(OFFSET_SECONDS, offset.getTotalSeconds()), buf);
+        assertEquals(buf.toString(), "EXISTING" + expected);
+    }
+
+    @Test(dataProvider="offsets")
+    public void test_toString(String pattern, String expected, ZoneOffset offset) throws Exception {
+        assertEquals(getFormatter(pattern, "NO-OFFSET").toString(), "Offset('NO-OFFSET'," + pattern + ")");
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=DateTimeException.class)
+    public void test_print_emptyCalendrical() throws Exception {
+        getFormatter("+HH:MM:ss", "Z").printTo(EMPTY_DTA, buf);
+    }
+
+    public void test_print_emptyAppendable() throws Exception {
+        getFormatter("+HH:MM:ss", "Z").printTo(new DateTimeBuilder(OFFSET_SECONDS, OFFSET_0130.getTotalSeconds()), buf);
+        assertEquals(buf.toString(), "+01:30");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/format/TestZoneTextPrinterParser.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package test.java.time.format;
+
+import java.util.Date;
+import java.util.Locale;
+import java.util.Random;
+import java.util.Set;
+import java.util.TimeZone;
+
+import java.time.ZonedDateTime;
+import java.time.ZoneId;
+import java.time.temporal.ChronoField;
+import java.time.format.DateTimeFormatSymbols;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.TextStyle;
+import java.time.zone.ZoneRulesProvider;
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.assertEquals;
+
+/**
+ * Test ZoneTextPrinterParser
+ */
+@Test(groups={"implementation"})
+public class TestZoneTextPrinterParser extends AbstractTestPrinterParser {
+
+    protected static DateTimeFormatter getFormatter(Locale locale, TextStyle style) {
+        return new DateTimeFormatterBuilder().appendZoneText(style)
+                                             .toFormatter(locale)
+                                             .withSymbols(DateTimeFormatSymbols.of(locale));
+    }
+
+    public void test_printText() {
+        Random r = new Random();
+        int N = 50;
+        Locale[] locales = Locale.getAvailableLocales();
+        Set<String> zids = ZoneRulesProvider.getAvailableZoneIds();
+        ZonedDateTime zdt = ZonedDateTime.now();
+
+        //System.out.printf("locale==%d, timezone=%d%n", locales.length, zids.size());
+        while (N-- > 0) {
+            zdt = zdt.withDayOfYear(r.nextInt(365) + 1)
+                     .with(ChronoField.SECOND_OF_DAY, r.nextInt(86400));
+            for (String zid : zids) {
+                zdt = zdt.withZoneSameLocal(ZoneId.of(zid));
+                TimeZone tz = TimeZone.getTimeZone(zid);
+                boolean isDST = tz.inDaylightTime(new Date(zdt.toInstant().toEpochMilli()));
+                for (Locale locale : locales) {
+                    printText(locale, zdt, TextStyle.FULL,
+                              tz.getDisplayName(isDST, TimeZone.LONG, locale));
+                    printText(locale, zdt, TextStyle.SHORT,
+                              tz.getDisplayName(isDST, TimeZone.SHORT, locale));
+                }
+            }
+        }
+    }
+
+    private void printText(Locale locale, ZonedDateTime zdt, TextStyle style, String expected) {
+        String result = getFormatter(locale, style).print(zdt);
+        if (!result.equals(expected)) {
+            if (result.equals("FooLocation") || // from rules provider test if same vm
+                result.startsWith("Etc/GMT") || result.equals("ROC")) {  // TBD: match jdk behavior?
+                return;
+            }
+            System.out.println("----------------");
+            System.out.printf("tdz[%s]%n", zdt.toString());
+            System.out.printf("[%-4s, %5s] :[%s]%n", locale.toString(), style.toString(),result);
+            System.out.printf("%4s, %5s  :[%s]%n", "", "", expected);
+        }
+        assertEquals(result, expected);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/temporal/MockFieldNoValue.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.temporal;
+
+import java.time.format.DateTimeBuilder;
+import java.time.temporal.*;
+
+import static java.time.temporal.ChronoUnit.MONTHS;
+import static java.time.temporal.ChronoUnit.WEEKS;
+
+import java.time.DateTimeException;
+
+/**
+ * Mock TemporalField that returns null.
+ */
+public enum MockFieldNoValue implements TemporalField {
+
+    INSTANCE;
+
+    @Override
+    public String getName() {
+        return null;
+    }
+
+    @Override
+    public TemporalUnit getBaseUnit() {
+        return WEEKS;
+    }
+
+    @Override
+    public TemporalUnit getRangeUnit() {
+        return MONTHS;
+    }
+
+    @Override
+    public ValueRange range() {
+        return ValueRange.of(1, 20);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public boolean doIsSupported(TemporalAccessor temporal) {
+        return true;
+    }
+
+    @Override
+    public ValueRange doRange(TemporalAccessor temporal) {
+        return ValueRange.of(1, 20);
+    }
+
+    @Override
+    public long doGet(TemporalAccessor temporal) {
+        throw new DateTimeException("Mock");
+    }
+
+    @Override
+    public <R extends Temporal> R doWith(R temporal, long newValue) {
+        throw new DateTimeException("Mock");
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public boolean resolve(DateTimeBuilder dateTimeBuilder, long value) {
+        return false;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/temporal/MockFieldValue.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.temporal;
+
+import java.time.temporal.*;
+
+import java.time.DateTimeException;
+import java.time.temporal.TemporalAccessor;
+
+/**
+ * Mock simple date-time with one field-value.
+ */
+public final class MockFieldValue implements TemporalAccessor {
+
+    private final TemporalField field;
+    private final long value;
+
+    public MockFieldValue(TemporalField field, long value) {
+        this.field = field;
+        this.value = value;
+    }
+
+    @Override
+    public boolean isSupported(TemporalField field) {
+        return field != null && field.equals(this.field);
+    }
+
+    @Override
+    public ValueRange range(TemporalField field) {
+        if (field instanceof ChronoField) {
+            if (isSupported(field)) {
+                return field.range();
+            }
+            throw new DateTimeException("Unsupported field: " + field.getName());
+        }
+        return field.doRange(this);
+    }
+
+    @Override
+    public long getLong(TemporalField field) {
+        if (this.field.equals(field)) {
+            return value;
+        }
+        throw new DateTimeException("Unsupported field: " + field);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/temporal/TestChronoUnit.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.temporal;
+
+import static java.time.Month.AUGUST;
+import static java.time.Month.FEBRUARY;
+import static java.time.Month.JULY;
+import static java.time.Month.JUNE;
+import static java.time.Month.MARCH;
+import static java.time.Month.OCTOBER;
+import static java.time.Month.SEPTEMBER;
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.MONTHS;
+import static java.time.temporal.ChronoUnit.WEEKS;
+import static java.time.temporal.ChronoUnit.YEARS;
+import static org.testng.Assert.assertEquals;
+
+import java.time.LocalDate;
+import java.time.Month;
+import java.time.ZoneOffset;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test.
+ */
+@Test
+public class TestChronoUnit {
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name = "yearsBetween")
+    Object[][] data_yearsBetween() {
+        return new Object[][] {
+            {date(1939, SEPTEMBER, 2), date(1939, SEPTEMBER, 1), 0},
+            {date(1939, SEPTEMBER, 2), date(1939, SEPTEMBER, 2), 0},
+            {date(1939, SEPTEMBER, 2), date(1939, SEPTEMBER, 3), 0},
+
+            {date(1939, SEPTEMBER, 2), date(1940, SEPTEMBER, 1), 0},
+            {date(1939, SEPTEMBER, 2), date(1940, SEPTEMBER, 2), 1},
+            {date(1939, SEPTEMBER, 2), date(1940, SEPTEMBER, 3), 1},
+
+            {date(1939, SEPTEMBER, 2), date(1938, SEPTEMBER, 1), -1},
+            {date(1939, SEPTEMBER, 2), date(1938, SEPTEMBER, 2), -1},
+            {date(1939, SEPTEMBER, 2), date(1938, SEPTEMBER, 3), 0},
+
+            {date(1939, SEPTEMBER, 2), date(1945, SEPTEMBER, 3), 6},
+            {date(1939, SEPTEMBER, 2), date(1945, OCTOBER, 3), 6},
+            {date(1939, SEPTEMBER, 2), date(1945, AUGUST, 3), 5},
+        };
+    }
+
+    @Test(dataProvider = "yearsBetween")
+    public void test_yearsBetween(LocalDate start, LocalDate end, long expected) {
+        assertEquals(YEARS.between(start, end).getAmount(), expected);
+        assertEquals(YEARS.between(start, end).getUnit(), YEARS);
+    }
+
+    @Test(dataProvider = "yearsBetween")
+    public void test_yearsBetweenReversed(LocalDate start, LocalDate end, long expected) {
+        assertEquals(YEARS.between(end, start).getAmount(), -expected);
+        assertEquals(YEARS.between(end, start).getUnit(), YEARS);
+    }
+
+    @Test(dataProvider = "yearsBetween")
+    public void test_yearsBetween_LocalDateTimeSameTime(LocalDate start, LocalDate end, long expected) {
+        assertEquals(YEARS.between(start.atTime(12, 30), end.atTime(12, 30)).getAmount(), expected);
+    }
+
+    @Test(dataProvider = "yearsBetween")
+    public void test_yearsBetween_LocalDateTimeLaterTime(LocalDate start, LocalDate end, long expected) {
+        assertEquals(YEARS.between(start.atTime(12, 30), end.atTime(12, 31)).getAmount(), expected);
+    }
+
+    @Test(dataProvider = "yearsBetween")
+    public void test_yearsBetween_ZonedDateSameOffset(LocalDate start, LocalDate end, long expected) {
+        assertEquals(YEARS.between(start.atStartOfDay(ZoneOffset.ofHours(2)), end.atStartOfDay(ZoneOffset.ofHours(2))).getAmount(), expected);
+    }
+
+    @Test(dataProvider = "yearsBetween")
+    public void test_yearsBetween_ZonedDateLaterOffset(LocalDate start, LocalDate end, long expected) {
+        // +01:00 is later than +02:00
+        assertEquals(YEARS.between(start.atStartOfDay(ZoneOffset.ofHours(2)), end.atStartOfDay(ZoneOffset.ofHours(1))).getAmount(), expected);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name = "monthsBetween")
+    Object[][] data_monthsBetween() {
+        return new Object[][] {
+            {date(2012, JULY, 2), date(2012, JULY, 1), 0},
+            {date(2012, JULY, 2), date(2012, JULY, 2), 0},
+            {date(2012, JULY, 2), date(2012, JULY, 3), 0},
+
+            {date(2012, JULY, 2), date(2012, AUGUST, 1), 0},
+            {date(2012, JULY, 2), date(2012, AUGUST, 2), 1},
+            {date(2012, JULY, 2), date(2012, AUGUST, 3), 1},
+
+            {date(2012, JULY, 2), date(2012, SEPTEMBER, 1), 1},
+            {date(2012, JULY, 2), date(2012, SEPTEMBER, 2), 2},
+            {date(2012, JULY, 2), date(2012, SEPTEMBER, 3), 2},
+
+            {date(2012, JULY, 2), date(2012, JUNE, 1), -1},
+            {date(2012, JULY, 2), date(2012, JUNE, 2), -1},
+            {date(2012, JULY, 2), date(2012, JUNE, 3), 0},
+
+            {date(2012, FEBRUARY, 27), date(2012, MARCH, 26), 0},
+            {date(2012, FEBRUARY, 27), date(2012, MARCH, 27), 1},
+            {date(2012, FEBRUARY, 27), date(2012, MARCH, 28), 1},
+
+            {date(2012, FEBRUARY, 28), date(2012, MARCH, 27), 0},
+            {date(2012, FEBRUARY, 28), date(2012, MARCH, 28), 1},
+            {date(2012, FEBRUARY, 28), date(2012, MARCH, 29), 1},
+
+            {date(2012, FEBRUARY, 29), date(2012, MARCH, 28), 0},
+            {date(2012, FEBRUARY, 29), date(2012, MARCH, 29), 1},
+            {date(2012, FEBRUARY, 29), date(2012, MARCH, 30), 1},
+        };
+    }
+
+    @Test(dataProvider = "monthsBetween")
+    public void test_monthsBetween(LocalDate start, LocalDate end, long expected) {
+        assertEquals(MONTHS.between(start, end).getAmount(), expected);
+        assertEquals(MONTHS.between(start, end).getUnit(), MONTHS);
+    }
+
+    @Test(dataProvider = "monthsBetween")
+    public void test_monthsBetweenReversed(LocalDate start, LocalDate end, long expected) {
+        assertEquals(MONTHS.between(end, start).getAmount(), -expected);
+        assertEquals(MONTHS.between(end, start).getUnit(), MONTHS);
+    }
+
+    @Test(dataProvider = "monthsBetween")
+    public void test_monthsBetween_LocalDateTimeSameTime(LocalDate start, LocalDate end, long expected) {
+        assertEquals(MONTHS.between(start.atTime(12, 30), end.atTime(12, 30)).getAmount(), expected);
+    }
+
+    @Test(dataProvider = "monthsBetween")
+    public void test_monthsBetween_LocalDateTimeLaterTime(LocalDate start, LocalDate end, long expected) {
+        assertEquals(MONTHS.between(start.atTime(12, 30), end.atTime(12, 31)).getAmount(), expected);
+    }
+
+    @Test(dataProvider = "monthsBetween")
+    public void test_monthsBetween_ZonedDateSameOffset(LocalDate start, LocalDate end, long expected) {
+        assertEquals(MONTHS.between(start.atStartOfDay(ZoneOffset.ofHours(2)), end.atStartOfDay(ZoneOffset.ofHours(2))).getAmount(), expected);
+    }
+
+    @Test(dataProvider = "monthsBetween")
+    public void test_monthsBetween_ZonedDateLaterOffset(LocalDate start, LocalDate end, long expected) {
+        // +01:00 is later than +02:00
+        assertEquals(MONTHS.between(start.atStartOfDay(ZoneOffset.ofHours(2)), end.atStartOfDay(ZoneOffset.ofHours(1))).getAmount(), expected);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name = "weeksBetween")
+    Object[][] data_weeksBetween() {
+        return new Object[][] {
+            {date(2012, JULY, 2), date(2012, JUNE, 25), -1},
+            {date(2012, JULY, 2), date(2012, JUNE, 26), 0},
+            {date(2012, JULY, 2), date(2012, JULY, 2), 0},
+            {date(2012, JULY, 2), date(2012, JULY, 8), 0},
+            {date(2012, JULY, 2), date(2012, JULY, 9), 1},
+
+            {date(2012, FEBRUARY, 28), date(2012, FEBRUARY, 21), -1},
+            {date(2012, FEBRUARY, 28), date(2012, FEBRUARY, 22), 0},
+            {date(2012, FEBRUARY, 28), date(2012, FEBRUARY, 28), 0},
+            {date(2012, FEBRUARY, 28), date(2012, FEBRUARY, 29), 0},
+            {date(2012, FEBRUARY, 28), date(2012, MARCH, 1), 0},
+            {date(2012, FEBRUARY, 28), date(2012, MARCH, 5), 0},
+            {date(2012, FEBRUARY, 28), date(2012, MARCH, 6), 1},
+
+            {date(2012, FEBRUARY, 29), date(2012, FEBRUARY, 22), -1},
+            {date(2012, FEBRUARY, 29), date(2012, FEBRUARY, 23), 0},
+            {date(2012, FEBRUARY, 29), date(2012, FEBRUARY, 28), 0},
+            {date(2012, FEBRUARY, 29), date(2012, FEBRUARY, 29), 0},
+            {date(2012, FEBRUARY, 29), date(2012, MARCH, 1), 0},
+            {date(2012, FEBRUARY, 29), date(2012, MARCH, 6), 0},
+            {date(2012, FEBRUARY, 29), date(2012, MARCH, 7), 1},
+        };
+    }
+
+    @Test(dataProvider = "weeksBetween")
+    public void test_weeksBetween(LocalDate start, LocalDate end, long expected) {
+        assertEquals(WEEKS.between(start, end).getAmount(), expected);
+        assertEquals(WEEKS.between(start, end).getUnit(), WEEKS);
+    }
+
+    @Test(dataProvider = "weeksBetween")
+    public void test_weeksBetweenReversed(LocalDate start, LocalDate end, long expected) {
+        assertEquals(WEEKS.between(end, start).getAmount(), -expected);
+        assertEquals(WEEKS.between(end, start).getUnit(), WEEKS);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name = "daysBetween")
+    Object[][] data_daysBetween() {
+        return new Object[][] {
+            {date(2012, JULY, 2), date(2012, JULY, 1), -1},
+            {date(2012, JULY, 2), date(2012, JULY, 2), 0},
+            {date(2012, JULY, 2), date(2012, JULY, 3), 1},
+
+            {date(2012, FEBRUARY, 28), date(2012, FEBRUARY, 27), -1},
+            {date(2012, FEBRUARY, 28), date(2012, FEBRUARY, 28), 0},
+            {date(2012, FEBRUARY, 28), date(2012, FEBRUARY, 29), 1},
+            {date(2012, FEBRUARY, 28), date(2012, MARCH, 1), 2},
+
+            {date(2012, FEBRUARY, 29), date(2012, FEBRUARY, 27), -2},
+            {date(2012, FEBRUARY, 29), date(2012, FEBRUARY, 28), -1},
+            {date(2012, FEBRUARY, 29), date(2012, FEBRUARY, 29), 0},
+            {date(2012, FEBRUARY, 29), date(2012, MARCH, 1), 1},
+
+            {date(2012, MARCH, 1), date(2012, FEBRUARY, 27), -3},
+            {date(2012, MARCH, 1), date(2012, FEBRUARY, 28), -2},
+            {date(2012, MARCH, 1), date(2012, FEBRUARY, 29), -1},
+            {date(2012, MARCH, 1), date(2012, MARCH, 1), 0},
+            {date(2012, MARCH, 1), date(2012, MARCH, 2), 1},
+
+            {date(2012, MARCH, 1), date(2013, FEBRUARY, 28), 364},
+            {date(2012, MARCH, 1), date(2013, MARCH, 1), 365},
+
+            {date(2011, MARCH, 1), date(2012, FEBRUARY, 28), 364},
+            {date(2011, MARCH, 1), date(2012, FEBRUARY, 29), 365},
+            {date(2011, MARCH, 1), date(2012, MARCH, 1), 366},
+        };
+    }
+
+    @Test(dataProvider = "daysBetween")
+    public void test_daysBetween(LocalDate start, LocalDate end, long expected) {
+        assertEquals(DAYS.between(start, end).getAmount(), expected);
+        assertEquals(DAYS.between(start, end).getUnit(), DAYS);
+    }
+
+    @Test(dataProvider = "daysBetween")
+    public void test_daysBetweenReversed(LocalDate start, LocalDate end, long expected) {
+        assertEquals(DAYS.between(end, start).getAmount(), -expected);
+        assertEquals(DAYS.between(end, start).getUnit(), DAYS);
+    }
+
+    @Test(dataProvider = "daysBetween")
+    public void test_daysBetween_LocalDateTimeSameTime(LocalDate start, LocalDate end, long expected) {
+        assertEquals(DAYS.between(start.atTime(12, 30), end.atTime(12, 30)).getAmount(), expected);
+    }
+
+    @Test(dataProvider = "daysBetween")
+    public void test_daysBetween_LocalDateTimeLaterTime(LocalDate start, LocalDate end, long expected) {
+        assertEquals(DAYS.between(start.atTime(12, 30), end.atTime(12, 31)).getAmount(), expected);
+    }
+
+    @Test(dataProvider = "daysBetween")
+    public void test_daysBetween_ZonedDateSameOffset(LocalDate start, LocalDate end, long expected) {
+        assertEquals(DAYS.between(start.atStartOfDay(ZoneOffset.ofHours(2)), end.atStartOfDay(ZoneOffset.ofHours(2))).getAmount(), expected);
+    }
+
+    @Test(dataProvider = "daysBetween")
+    public void test_daysBetween_ZonedDateLaterOffset(LocalDate start, LocalDate end, long expected) {
+        // +01:00 is later than +02:00
+        assertEquals(DAYS.between(start.atStartOfDay(ZoneOffset.ofHours(2)), end.atStartOfDay(ZoneOffset.ofHours(1))).getAmount(), expected);
+    }
+
+    //-----------------------------------------------------------------------
+    private static LocalDate date(int year, Month month, int dom) {
+        return LocalDate.of(year, month, dom);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/temporal/TestDateTimeAdjusters.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.temporal;
+
+import java.time.temporal.*;
+
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Modifier;
+import java.util.Collections;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test Adjusters.
+ */
+@Test(groups={"implementation"})
+public class TestDateTimeAdjusters {
+
+    @SuppressWarnings("rawtypes")
+    public void test_constructor() throws Exception {
+        for (Constructor constructor : Adjusters.class.getDeclaredConstructors()) {
+            assertTrue(Modifier.isPrivate(constructor.getModifiers()));
+            constructor.setAccessible(true);
+            constructor.newInstance(Collections.nCopies(constructor.getParameterTypes().length, null).toArray());
+        }
+    }
+
+    public void factory_firstDayOfMonthSame() {
+        assertSame(Adjusters.firstDayOfMonth(), Adjusters.firstDayOfMonth());
+    }
+
+    public void factory_lastDayOfMonthSame() {
+        assertSame(Adjusters.lastDayOfMonth(), Adjusters.lastDayOfMonth());
+    }
+
+    public void factory_firstDayOfNextMonthSame() {
+        assertSame(Adjusters.firstDayOfNextMonth(), Adjusters.firstDayOfNextMonth());
+    }
+
+    public void factory_firstDayOfYearSame() {
+        assertSame(Adjusters.firstDayOfYear(), Adjusters.firstDayOfYear());
+    }
+
+    public void factory_lastDayOfYearSame() {
+        assertSame(Adjusters.lastDayOfYear(), Adjusters.lastDayOfYear());
+    }
+
+    public void factory_firstDayOfNextYearSame() {
+        assertSame(Adjusters.firstDayOfNextYear(), Adjusters.firstDayOfNextYear());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/temporal/TestDateTimeBuilderCombinations.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.temporal;
+
+import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH;
+import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR;
+import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH;
+import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR;
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.DAY_OF_WEEK;
+import static java.time.temporal.ChronoField.DAY_OF_YEAR;
+import static java.time.temporal.ChronoField.EPOCH_DAY;
+import static java.time.temporal.ChronoField.EPOCH_MONTH;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.YEAR;
+import static org.testng.Assert.assertEquals;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeBuilder;
+import java.time.temporal.TemporalField;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test.
+ */
+public class TestDateTimeBuilderCombinations {
+
+    @DataProvider(name = "combine")
+    Object[][] data_combine() {
+        return new Object[][] {
+            {YEAR, 2012, MONTH_OF_YEAR, 6, DAY_OF_MONTH, 3, null, null, LocalDate.class, LocalDate.of(2012, 6, 3)},
+            {EPOCH_MONTH, (2012 - 1970) * 12 + 6 - 1, DAY_OF_MONTH, 3, null, null, null, null, LocalDate.class, LocalDate.of(2012, 6, 3)},
+            {YEAR, 2012, ALIGNED_WEEK_OF_YEAR, 6, DAY_OF_WEEK, 3, null, null, LocalDate.class, LocalDate.of(2012, 2, 8)},
+            {YEAR, 2012, DAY_OF_YEAR, 155, null, null, null, null, LocalDate.class, LocalDate.of(2012, 6, 3)},
+//            {ERA, 1, YEAR_OF_ERA, 2012, DAY_OF_YEAR, 155, null, null, LocalDate.class, LocalDate.of(2012, 6, 3)},
+            {YEAR, 2012, MONTH_OF_YEAR, 6, null, null, null, null, LocalDate.class, null},
+            {EPOCH_DAY, 12, null, null, null, null, null, null, LocalDate.class, LocalDate.of(1970, 1, 13)},
+        };
+    }
+
+    @Test(dataProvider = "combine")
+    public void test_derive(TemporalField field1, Number value1, TemporalField field2, Number value2,
+            TemporalField field3, Number value3, TemporalField field4, Number value4, Class<?> query, Object expectedVal) {
+        DateTimeBuilder builder = new DateTimeBuilder(field1, value1.longValue());
+        if (field2 != null) {
+            builder.addFieldValue(field2, value2.longValue());
+        }
+        if (field3 != null) {
+            builder.addFieldValue(field3, value3.longValue());
+        }
+        if (field4 != null) {
+            builder.addFieldValue(field4, value4.longValue());
+        }
+        builder.resolve();
+        assertEquals(builder.extract((Class<?>) query), expectedVal);
+    }
+
+    //-----------------------------------------------------------------------
+    @DataProvider(name = "normalized")
+    Object[][] data_normalized() {
+        return new Object[][] {
+            {YEAR, 2127, null, null, null, null, YEAR, 2127},
+            {MONTH_OF_YEAR, 12, null, null, null, null, MONTH_OF_YEAR, 12},
+            {DAY_OF_YEAR, 127, null, null, null, null, DAY_OF_YEAR, 127},
+            {DAY_OF_MONTH, 23, null, null, null, null, DAY_OF_MONTH, 23},
+            {DAY_OF_WEEK, 127, null, null, null, null, DAY_OF_WEEK, 127L},
+            {ALIGNED_WEEK_OF_YEAR, 23, null, null, null, null, ALIGNED_WEEK_OF_YEAR, 23},
+            {ALIGNED_DAY_OF_WEEK_IN_YEAR, 4, null, null, null, null, ALIGNED_DAY_OF_WEEK_IN_YEAR, 4L},
+            {ALIGNED_WEEK_OF_MONTH, 4, null, null, null, null, ALIGNED_WEEK_OF_MONTH, 4},
+            {ALIGNED_DAY_OF_WEEK_IN_MONTH, 3, null, null, null, null, ALIGNED_DAY_OF_WEEK_IN_MONTH, 3},
+            {EPOCH_MONTH, 15, null, null, null, null, EPOCH_MONTH, null},
+            {EPOCH_MONTH, 15, null, null, null, null, YEAR, 1971},
+            {EPOCH_MONTH, 15, null, null, null, null, MONTH_OF_YEAR, 4},
+        };
+    }
+
+    @Test(dataProvider = "normalized")
+    public void test_normalized(TemporalField field1, Number value1, TemporalField field2, Number value2,
+            TemporalField field3, Number value3, TemporalField query, Number expectedVal) {
+        DateTimeBuilder builder = new DateTimeBuilder(field1, value1.longValue());
+        if (field2 != null) {
+            builder.addFieldValue(field2, value2.longValue());
+        }
+        if (field3 != null) {
+            builder.addFieldValue(field3, value3.longValue());
+        }
+        builder.resolve();
+        if (expectedVal != null) {
+            assertEquals(builder.getLong(query), expectedVal.longValue());
+        } else {
+            assertEquals(builder.containsFieldValue(query), false);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // TODO: maybe reinstate
+//    public void test_split() {
+//        DateTimeBuilder builder = new DateTimeBuilder();
+//        builder.addCalendrical(LocalDateTime.of(2012, 6, 30, 12, 30));
+//        builder.addCalendrical(ZoneOffset.ofHours(2));
+//        builder.resolve();
+//        assertEquals(builder.build(LocalDate.class), LocalDate.of(2012, 6, 30));
+//        assertEquals(builder.build(LocalTime.class), LocalTime.of(12, 30));
+//        assertEquals(builder.build(ZoneOffset.class), ZoneOffset.ofHours(2));
+//
+//        assertEquals(builder.build(LocalDateTime.class), LocalDateTime.of(2012, 6, 30, 12, 30));
+//        assertEquals(builder.build(OffsetDate.class), OffsetDate.of(LocalDate.of(2012, 6, 30), ZoneOffset.ofHours(2)));
+//        assertEquals(builder.build(OffsetTime.class), OffsetTime.of(LocalTime.of(12, 30), ZoneOffset.ofHours(2)));
+////        assertEquals(builder.build(OffsetDateTime.class), OffsetDateTime.of(2012, 6, 30, 12, 30, ZoneOffset.ofHours(2)));
+//    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/temporal/TestDateTimeValueRange.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.temporal;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import java.time.temporal.ValueRange;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import test.java.time.AbstractTest;
+
+/**
+ * Test.
+ */
+@Test
+public class TestDateTimeValueRange extends AbstractTest {
+
+    //-----------------------------------------------------------------------
+    // Basics
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_immutable() {
+        assertImmutable(ValueRange.class);
+    }
+
+    //-----------------------------------------------------------------------
+    // Serialization
+    //-----------------------------------------------------------------------
+    public void test_serialization() throws Exception {
+        Object obj = ValueRange.of(1, 2, 3, 4);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream oos = new ObjectOutputStream(baos);
+        oos.writeObject(obj);
+        oos.close();
+        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
+        assertEquals(ois.readObject(), obj);
+    }
+
+    //-----------------------------------------------------------------------
+    // of(long,long)
+    //-----------------------------------------------------------------------
+    public void test_of_longlong() {
+        ValueRange test = ValueRange.of(1, 12);
+        assertEquals(test.getMinimum(), 1);
+        assertEquals(test.getLargestMinimum(), 1);
+        assertEquals(test.getSmallestMaximum(), 12);
+        assertEquals(test.getMaximum(), 12);
+        assertEquals(test.isFixed(), true);
+        assertEquals(test.isIntValue(), true);
+    }
+
+    public void test_of_longlong_big() {
+        ValueRange test = ValueRange.of(1, 123456789012345L);
+        assertEquals(test.getMinimum(), 1);
+        assertEquals(test.getLargestMinimum(), 1);
+        assertEquals(test.getSmallestMaximum(), 123456789012345L);
+        assertEquals(test.getMaximum(), 123456789012345L);
+        assertEquals(test.isFixed(), true);
+        assertEquals(test.isIntValue(), false);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void test_of_longlong_minGtMax() {
+        ValueRange.of(12, 1);
+    }
+
+    //-----------------------------------------------------------------------
+    // of(long,long,long)
+    //-----------------------------------------------------------------------
+    public void test_of_longlonglong() {
+        ValueRange test = ValueRange.of(1, 28, 31);
+        assertEquals(test.getMinimum(), 1);
+        assertEquals(test.getLargestMinimum(), 1);
+        assertEquals(test.getSmallestMaximum(), 28);
+        assertEquals(test.getMaximum(), 31);
+        assertEquals(test.isFixed(), false);
+        assertEquals(test.isIntValue(), true);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void test_of_longlonglong_minGtMax() {
+        ValueRange.of(12, 1, 2);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void test_of_longlonglong_smallestmaxminGtMax() {
+        ValueRange.of(1, 31, 28);
+    }
+
+    //-----------------------------------------------------------------------
+    // of(long,long,long,long)
+    //-----------------------------------------------------------------------
+    @DataProvider(name="valid")
+    Object[][] data_valid() {
+        return new Object[][] {
+                {1, 1, 1, 1},
+                {1, 1, 1, 2},
+                {1, 1, 2, 2},
+                {1, 2, 3, 4},
+                {1, 1, 28, 31},
+                {1, 3, 31, 31},
+                {-5, -4, -3, -2},
+                {-5, -4, 3, 4},
+                {1, 20, 10, 31},
+        };
+    }
+
+    @Test(dataProvider="valid")
+    public void test_of_longlonglonglong(long sMin, long lMin, long sMax, long lMax) {
+        ValueRange test = ValueRange.of(sMin, lMin, sMax, lMax);
+        assertEquals(test.getMinimum(), sMin);
+        assertEquals(test.getLargestMinimum(), lMin);
+        assertEquals(test.getSmallestMaximum(), sMax);
+        assertEquals(test.getMaximum(), lMax);
+        assertEquals(test.isFixed(), sMin == lMin && sMax == lMax);
+        assertEquals(test.isIntValue(), true);
+    }
+
+    @DataProvider(name="invalid")
+    Object[][] data_invalid() {
+        return new Object[][] {
+                {1, 2, 31, 28},
+                {1, 31, 2, 28},
+                {31, 2, 1, 28},
+                {31, 2, 3, 28},
+
+                {2, 1, 28, 31},
+                {2, 1, 31, 28},
+                {12, 13, 1, 2},
+        };
+    }
+
+    @Test(dataProvider="invalid", expectedExceptions=IllegalArgumentException.class)
+    public void test_of_longlonglonglong_invalid(long sMin, long lMin, long sMax, long lMax) {
+        ValueRange.of(sMin, lMin, sMax, lMax);
+    }
+
+    //-----------------------------------------------------------------------
+    // isValidValue(long)
+    //-----------------------------------------------------------------------
+    public void test_isValidValue_long() {
+        ValueRange test = ValueRange.of(1, 28, 31);
+        assertEquals(test.isValidValue(0), false);
+        assertEquals(test.isValidValue(1), true);
+        assertEquals(test.isValidValue(2), true);
+        assertEquals(test.isValidValue(30), true);
+        assertEquals(test.isValidValue(31), true);
+        assertEquals(test.isValidValue(32), false);
+    }
+
+    //-----------------------------------------------------------------------
+    // isValidIntValue(long)
+    //-----------------------------------------------------------------------
+    public void test_isValidValue_long_int() {
+        ValueRange test = ValueRange.of(1, 28, 31);
+        assertEquals(test.isValidValue(0), false);
+        assertEquals(test.isValidValue(1), true);
+        assertEquals(test.isValidValue(31), true);
+        assertEquals(test.isValidValue(32), false);
+    }
+
+    public void test_isValidValue_long_long() {
+        ValueRange test = ValueRange.of(1, 28, Integer.MAX_VALUE + 1L);
+        assertEquals(test.isValidIntValue(0), false);
+        assertEquals(test.isValidIntValue(1), false);
+        assertEquals(test.isValidIntValue(31), false);
+        assertEquals(test.isValidIntValue(32), false);
+    }
+
+    //-----------------------------------------------------------------------
+    // equals() / hashCode()
+    //-----------------------------------------------------------------------
+    public void test_equals1() {
+        ValueRange a = ValueRange.of(1, 2, 3, 4);
+        ValueRange b = ValueRange.of(1, 2, 3, 4);
+        assertEquals(a.equals(a), true);
+        assertEquals(a.equals(b), true);
+        assertEquals(b.equals(a), true);
+        assertEquals(b.equals(b), true);
+        assertEquals(a.hashCode() == b.hashCode(), true);
+    }
+
+    public void test_equals2() {
+        ValueRange a = ValueRange.of(1, 2, 3, 4);
+        assertEquals(a.equals(ValueRange.of(0, 2, 3, 4)), false);
+        assertEquals(a.equals(ValueRange.of(1, 3, 3, 4)), false);
+        assertEquals(a.equals(ValueRange.of(1, 2, 4, 4)), false);
+        assertEquals(a.equals(ValueRange.of(1, 2, 3, 5)), false);
+    }
+
+    public void test_equals_otherType() {
+        ValueRange a = ValueRange.of(1, 12);
+        assertEquals(a.equals("Rubbish"), false);
+    }
+
+    public void test_equals_null() {
+        ValueRange a = ValueRange.of(1, 12);
+        assertEquals(a.equals(null), false);
+    }
+
+    //-----------------------------------------------------------------------
+    // toString()
+    //-----------------------------------------------------------------------
+    public void test_toString() {
+        assertEquals(ValueRange.of(1, 1, 4, 4).toString(), "1 - 4");
+        assertEquals(ValueRange.of(1, 1, 3, 4).toString(), "1 - 3/4");
+        assertEquals(ValueRange.of(1, 2, 3, 4).toString(), "1/2 - 3/4");
+        assertEquals(ValueRange.of(1, 2, 4, 4).toString(), "1/2 - 4");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/temporal/TestISOChronoImpl.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.temporal;
+
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.YEAR;
+import static java.time.temporal.ChronoField.YEAR_OF_ERA;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.ISOChrono;
+import java.time.temporal.WeekFields;
+import java.time.temporal.ChronoLocalDate;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test.
+ */
+@Test
+public class TestISOChronoImpl {
+
+    @DataProvider(name = "RangeVersusCalendar")
+    Object[][] provider_rangeVersusCalendar() {
+        return new Object[][]{
+            {LocalDate.of(1900, 1, 4), LocalDate.of(2100, 1, 8)},
+            //{LocalDate.of(1583, 1, 1), LocalDate.of(2100, 1, 1)},
+        };
+    }
+
+    //-----------------------------------------------------------------------
+    // Verify  ISO Calendar matches java.util.Calendar for range
+    //-----------------------------------------------------------------------
+    @Test(groups = {"implementation"}, dataProvider = "RangeVersusCalendar")
+    public void test_ISOChrono_vsCalendar(LocalDate isoStartDate, LocalDate isoEndDate) {
+        GregorianCalendar cal = new GregorianCalendar();
+        assertEquals(cal.getCalendarType(), "gregory", "Unexpected calendar type");
+        ChronoLocalDate<ISOChrono> isoDate = ISOChrono.INSTANCE.date(isoStartDate);
+
+        cal.setTimeZone(TimeZone.getTimeZone("GMT+00"));
+        cal.set(Calendar.YEAR, isoDate.get(YEAR));
+        cal.set(Calendar.MONTH, isoDate.get(MONTH_OF_YEAR) - 1);
+        cal.set(Calendar.DAY_OF_MONTH, isoDate.get(DAY_OF_MONTH));
+
+        while (isoDate.isBefore(isoEndDate)) {
+            assertEquals(isoDate.get(DAY_OF_MONTH), cal.get(Calendar.DAY_OF_MONTH), "Day mismatch in " + isoDate + ";  cal: " + cal);
+            assertEquals(isoDate.get(MONTH_OF_YEAR), cal.get(Calendar.MONTH) + 1, "Month mismatch in " + isoDate);
+            assertEquals(isoDate.get(YEAR_OF_ERA), cal.get(Calendar.YEAR), "Year mismatch in " + isoDate);
+
+            isoDate = isoDate.plus(1, ChronoUnit.DAYS);
+            cal.add(Calendar.DAY_OF_MONTH, 1);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    // Verify  ISO Calendar matches java.util.Calendar
+    // DayOfWeek, WeekOfMonth, WeekOfYear for range
+    //-----------------------------------------------------------------------
+    @Test(groups = {"implementation"}, dataProvider = "RangeVersusCalendar")
+    public void test_DayOfWeek_ISOChrono_vsCalendar(LocalDate isoStartDate, LocalDate isoEndDate) {
+        GregorianCalendar cal = new GregorianCalendar();
+        assertEquals(cal.getCalendarType(), "gregory", "Unexpected calendar type");
+        ChronoLocalDate<ISOChrono> isoDate = ISOChrono.INSTANCE.date(isoStartDate);
+
+        for (DayOfWeek firstDayOfWeek : DayOfWeek.values()) {
+            for (int minDays = 1; minDays <= 7; minDays++) {
+                WeekFields weekDef = WeekFields.of(firstDayOfWeek, minDays);
+                cal.setFirstDayOfWeek(Math.floorMod(firstDayOfWeek.getValue(), 7) + 1);
+                cal.setMinimalDaysInFirstWeek(minDays);
+
+                cal.setTimeZone(TimeZone.getTimeZone("GMT+00"));
+                cal.set(Calendar.YEAR, isoDate.get(YEAR));
+                cal.set(Calendar.MONTH, isoDate.get(MONTH_OF_YEAR) - 1);
+                cal.set(Calendar.DAY_OF_MONTH, isoDate.get(DAY_OF_MONTH));
+
+                while (isoDate.isBefore(isoEndDate)) {
+                    assertEquals(isoDate.get(DAY_OF_MONTH), cal.get(Calendar.DAY_OF_MONTH), "Day mismatch in " + isoDate + ";  cal: " + cal);
+                    assertEquals(isoDate.get(MONTH_OF_YEAR), cal.get(Calendar.MONTH) + 1, "Month mismatch in " + isoDate);
+                    assertEquals(isoDate.get(YEAR_OF_ERA), cal.get(Calendar.YEAR), "Year mismatch in " + isoDate);
+                    int jDOW = Math.floorMod(cal.get(Calendar.DAY_OF_WEEK) - 2, 7) + 1;
+                    int isoDOW = isoDate.get(weekDef.dayOfWeek());
+                    if (jDOW != isoDOW) {
+                        System.err.printf(" DOW vs Calendar jdow: %s, isoDate(DOW): %s, isoDate: %s, WeekDef: %s%n", jDOW, isoDOW, isoDate, weekDef);
+                    }
+                    assertEquals(jDOW, isoDOW, "Calendar DayOfWeek does not match ISO DayOfWeek");
+
+                    int jweekOfMonth = cal.get(Calendar.WEEK_OF_MONTH);
+                    int isoWeekOfMonth = isoDate.get(weekDef.weekOfMonth());
+                    if (jweekOfMonth != isoWeekOfMonth) {
+                        System.err.printf(" WeekOfMonth jWeekOfMonth: %s, isoWeekOfMonth: %s,  isoDate: %s, %s%n",
+                                jweekOfMonth, isoWeekOfMonth, isoDate, weekDef);
+                    }
+                    assertEquals(jweekOfMonth, isoWeekOfMonth, "Calendar WeekOfMonth does not match ISO WeekOfMonth");
+
+                    int jweekOfYear = cal.get(Calendar.WEEK_OF_YEAR);
+                    int isoWeekOfYear = isoDate.get(weekDef.weekOfYear());
+                    if (jweekOfYear != isoWeekOfYear) {
+                        // TBD: Issue #186 Remove misleading output pending resolution
+                        // System.err.printf(" Mismatch WeekOfYear jweekOfYear: %s, isoWeekOfYear: %s, isoDate: %s, WeekDef: %s%n", jweekOfYear, isoWeekOfYear, isoDate, weekDef);
+                    }
+                    //assertEquals(jweekOfYear, isoWeekOfYear,  "Calendar WeekOfYear does not match ISO WeekOfYear");
+
+                    isoDate = isoDate.plus(1, ChronoUnit.DAYS);
+                    cal.add(Calendar.DAY_OF_MONTH, 1);
+                }
+            }
+        }
+    }
+
+    /**
+     * Return the ISO Day of Week from a java.util.Calendr DAY_OF_WEEK.
+     * @param the java.util.Calendar day of week (1=Sunday, 7=Saturday)
+     * @return the ISO DayOfWeek
+     */
+    private DayOfWeek toISOfromCalendarDOW(int i) {
+        return DayOfWeek.of(Math.floorMod(i - 2, 7) + 1);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/temporal/TestJapaneseChronoImpl.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.temporal;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.Calendar;
+import java.util.Locale;
+import java.util.TimeZone;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.temporal.OffsetDateTime;
+import java.time.ZoneOffset;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoLocalDate;
+import java.time.temporal.ChronoUnit;
+import java.time.calendar.JapaneseChrono;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * Test.
+ */
+@Test
+public class TestJapaneseChronoImpl {
+
+    /**
+     * Range of years to check consistency with java.util.Calendar
+     */
+    @DataProvider(name="RangeVersusCalendar")
+    Object[][] provider_rangeVersusCalendar() {
+        return new Object[][] {
+            {LocalDate.of(1868, 1, 1), LocalDate.of(2100, 1, 1)},
+        };
+    }
+
+    //-----------------------------------------------------------------------
+    // Verify  Japanese Calendar matches java.util.Calendar for range
+    //-----------------------------------------------------------------------
+    @Test(groups={"implementation"}, dataProvider="RangeVersusCalendar")
+    public void test_JapaneseChrono_vsCalendar(LocalDate isoStartDate, LocalDate isoEndDate) {
+        Locale locale = Locale.forLanguageTag("ja-JP-u-ca-japanese");
+        assertEquals(locale.toString(), "ja_JP_#u-ca-japanese", "Unexpected locale");
+
+        Calendar cal = java.util.Calendar.getInstance(locale);
+        assertEquals(cal.getCalendarType(), "japanese", "Unexpected calendar type");
+
+        ChronoLocalDate<JapaneseChrono> jDate = JapaneseChrono.INSTANCE.date(isoStartDate);
+
+        // Convert to millis and set Japanese Calendar to that start date (at GMT)
+        OffsetDateTime jodt = OffsetDateTime.of(isoStartDate, LocalTime.MIN, ZoneOffset.UTC);
+        long millis = jodt.toInstant().toEpochMilli();
+        cal.setTimeZone(TimeZone.getTimeZone("GMT+00"));
+        cal.setTimeInMillis(millis);
+
+        while (jDate.isBefore(isoEndDate)) {
+            assertEquals(jDate.get(ChronoField.DAY_OF_MONTH), cal.get(Calendar.DAY_OF_MONTH), "Day mismatch in " + jDate + ";  cal: " + cal);
+            assertEquals(jDate.get(ChronoField.MONTH_OF_YEAR), cal.get(Calendar.MONTH) + 1, "Month mismatch in " + jDate);
+            assertEquals(jDate.get(ChronoField.YEAR_OF_ERA), cal.get(Calendar.YEAR), "Year mismatch in " + jDate);
+
+            jDate = jDate.plus(1, ChronoUnit.DAYS);
+            cal.add(Calendar.DAY_OF_MONTH, 1);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/temporal/TestMonthDay.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.temporal;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
+
+import java.time.LocalDate;
+import java.time.Month;
+import java.time.temporal.MonthDay;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import test.java.time.AbstractTest;
+
+/**
+ * Test MonthDay.
+ */
+@Test
+public class TestMonthDay extends AbstractTest {
+
+    private MonthDay TEST_07_15;
+
+    @BeforeMethod(groups={"tck","implementation"})
+    public void setUp() {
+        TEST_07_15 = MonthDay.of(7, 15);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_immutable() {
+        assertImmutable(MonthDay.class);
+    }
+
+    //-----------------------------------------------------------------------
+    void check(MonthDay test, int m, int d) {
+        assertEquals(test.getMonth().getValue(), m);
+        assertEquals(test.getDayOfMonth(), d);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_with_Month_noChangeSame() {
+        MonthDay test = MonthDay.of(6, 30);
+        assertSame(test.with(Month.JUNE), test);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withMonth_int_noChangeSame() {
+        MonthDay test = MonthDay.of(6, 30);
+        assertSame(test.withMonth(6), test);
+    }
+    @Test(groups={"implementation"})
+    public void test_withDayOfMonth_noChangeSame() {
+        MonthDay test = MonthDay.of(6, 30);
+        assertSame(test.withDayOfMonth(30), test);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_adjustDate_same() {
+        MonthDay test = MonthDay.of(6, 30);
+        LocalDate date = LocalDate.of(2007, 6, 30);
+        assertSame(test.adjustInto(date), date);
+    }
+
+    void doTest_comparisons_MonthDay(MonthDay... localDates) {
+        for (int i = 0; i < localDates.length; i++) {
+            MonthDay a = localDates[i];
+            for (int j = 0; j < localDates.length; j++) {
+                MonthDay b = localDates[j];
+                if (i < j) {
+                    assertTrue(a.compareTo(b) < 0, a + " <=> " + b);
+                    assertEquals(a.isBefore(b), true, a + " <=> " + b);
+                    assertEquals(a.isAfter(b), false, a + " <=> " + b);
+                    assertEquals(a.equals(b), false, a + " <=> " + b);
+                } else if (i > j) {
+                    assertTrue(a.compareTo(b) > 0, a + " <=> " + b);
+                    assertEquals(a.isBefore(b), false, a + " <=> " + b);
+                    assertEquals(a.isAfter(b), true, a + " <=> " + b);
+                    assertEquals(a.equals(b), false, a + " <=> " + b);
+                } else {
+                    assertEquals(a.compareTo(b), 0, a + " <=> " + b);
+                    assertEquals(a.isBefore(b), false, a + " <=> " + b);
+                    assertEquals(a.isAfter(b), false, a + " <=> " + b);
+                    assertEquals(a.equals(b), true, a + " <=> " + b);
+                }
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/temporal/TestOffsetDate.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.temporal;
+
+import java.time.temporal.OffsetDate;
+
+import org.testng.annotations.Test;
+import test.java.time.AbstractTest;
+
+/**
+ * Test OffsetDate.
+ */
+@Test
+public class TestOffsetDate extends AbstractTest {
+
+    @Test
+    public void test_immutable() {
+        assertImmutable(OffsetDate.class);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/temporal/TestOffsetDateTime.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.temporal;
+
+import static org.testng.Assert.assertSame;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneOffset;
+import java.time.temporal.OffsetDateTime;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import test.java.time.AbstractTest;
+import test.java.time.MockSimplePeriod;
+
+/**
+ * Test OffsetDateTime.
+ */
+@Test
+public class TestOffsetDateTime extends AbstractTest {
+
+    private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1);
+    private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2);
+    private OffsetDateTime TEST_2008_6_30_11_30_59_000000500;
+
+    @BeforeMethod(groups={"tck","implementation"})
+    public void setUp() {
+        TEST_2008_6_30_11_30_59_000000500 = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59, 500), OFFSET_PONE);
+    }
+
+    @Test
+    public void test_immutable() {
+        assertImmutable(OffsetDateTime.class);
+    }
+
+    //-----------------------------------------------------------------------
+    // basics
+    //-----------------------------------------------------------------------
+    @DataProvider(name="sampleTimes")
+    Object[][] provider_sampleTimes() {
+        return new Object[][] {
+            {2008, 6, 30, 11, 30, 20, 500, OFFSET_PONE},
+            {2008, 6, 30, 11, 0, 0, 0, OFFSET_PONE},
+            {2008, 6, 30, 23, 59, 59, 999999999, OFFSET_PONE},
+            {-1, 1, 1, 0, 0, 0, 0, OFFSET_PONE},
+        };
+    }
+
+    @Test(dataProvider="sampleTimes", groups={"implementation"})
+    public void test_get_same(int y, int o, int d, int h, int m, int s, int n, ZoneOffset offset) {
+        LocalDate localDate = LocalDate.of(y, o, d);
+        LocalTime localTime = LocalTime.of(h, m, s, n);
+        LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);
+        OffsetDateTime a = OffsetDateTime.of(localDateTime, offset);
+
+        assertSame(a.getOffset(), offset);
+        assertSame(a.getDate(), localDate);
+        assertSame(a.getTime(), localTime);
+        assertSame(a.getDateTime(), localDateTime);
+    }
+
+    //-----------------------------------------------------------------------
+    // withOffsetSameLocal()
+    //-----------------------------------------------------------------------
+    @Test(groups={"implementation"})
+    public void test_withOffsetSameLocal() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.withOffsetSameLocal(OFFSET_PTWO);
+        assertSame(test.getDateTime(), base.getDateTime());
+        assertSame(test.getOffset(), OFFSET_PTWO);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withOffsetSameLocal_noChange() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.withOffsetSameLocal(OFFSET_PONE);
+        assertSame(test, base);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withOffsetSameInstant_noChange() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.withOffsetSameInstant(OFFSET_PONE);
+        assertSame(test, base);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withYear_noChange() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.withYear(2008);
+        assertSame(test, base);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withMonth_noChange() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.withMonth(6);
+        assertSame(test, base);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withDayOfMonth_noChange() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.withDayOfMonth(30);
+        assertSame(test, base);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withDayOfYear_noChange() {
+        OffsetDateTime t = TEST_2008_6_30_11_30_59_000000500.withDayOfYear(31 + 29 + 31 + 30 + 31 + 30);
+        assertSame(t, TEST_2008_6_30_11_30_59_000000500);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withHour_noChange() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.withHour(11);
+        assertSame(test, base);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withMinute_noChange() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.withMinute(30);
+        assertSame(test, base);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withSecond_noChange() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.withSecond(59);
+        assertSame(test, base);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_withNanoOfSecond_noChange() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59, 1), OFFSET_PONE);
+        OffsetDateTime test = base.withNano(1);
+        assertSame(test, base);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plus_Period_zero() {
+        OffsetDateTime t = TEST_2008_6_30_11_30_59_000000500.plus(MockSimplePeriod.ZERO_DAYS);
+        assertSame(t, TEST_2008_6_30_11_30_59_000000500);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusYears_zero() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.plusYears(0);
+        assertSame(test, base);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusMonths_zero() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.plusMonths(0);
+        assertSame(test, base);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusWeeks_zero() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.plusWeeks(0);
+        assertSame(test, base);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusDays_zero() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.plusDays(0);
+        assertSame(test, base);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusHours_zero() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.plusHours(0);
+        assertSame(test, base);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusMinutes_zero() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.plusMinutes(0);
+        assertSame(test, base);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusSeconds_zero() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.plusSeconds(0);
+        assertSame(test, base);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_plusNanos_zero() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.plusNanos(0);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minus_Period_zero() {
+        OffsetDateTime t = TEST_2008_6_30_11_30_59_000000500.minus(MockSimplePeriod.ZERO_DAYS);
+        assertSame(t, TEST_2008_6_30_11_30_59_000000500);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusYears_zero() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2007, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.minusYears(0);
+        assertSame(test, base);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusMonths_zero() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.minusMonths(0);
+        assertSame(test, base);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusWeeks_zero() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.minusWeeks(0);
+        assertSame(test, base);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusDays_zero() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.minusDays(0);
+        assertSame(test, base);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusHours_zero() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.minusHours(0);
+        assertSame(test, base);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusMinutes_zero() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.minusMinutes(0);
+        assertSame(test, base);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusSeconds_zero() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.minusSeconds(0);
+        assertSame(test, base);
+    }
+
+    @Test(groups={"implementation"})
+    public void test_minusNanos_zero() {
+        OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE);
+        OffsetDateTime test = base.minusNanos(0);
+        assertSame(test, base);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/temporal/TestOffsetDateTime_instants.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.temporal;
+
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.Month;
+import java.time.ZoneOffset;
+
+import java.time.temporal.OffsetDateTime;
+import java.time.temporal.Year;
+
+import static org.testng.Assert.assertEquals;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test OffsetDate creation.
+ */
+@Test
+public class TestOffsetDateTime_instants {
+
+    private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1);
+    private static final ZoneOffset OFFSET_MAX = ZoneOffset.ofHours(18);
+    private static final ZoneOffset OFFSET_MIN = ZoneOffset.ofHours(-18);
+
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=NullPointerException.class)
+    public void factory_ofInstant_nullInstant() {
+        OffsetDateTime.ofInstant((Instant) null, OFFSET_PONE);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void factory_ofInstant_nullOffset() {
+        Instant instant = Instant.ofEpochSecond(0L);
+        OffsetDateTime.ofInstant(instant, (ZoneOffset) null);
+    }
+
+    public void factory_ofInstant_allSecsInDay() {
+        for (int i = 0; i < (24 * 60 * 60); i++) {
+            Instant instant = Instant.ofEpochSecond(i);
+            OffsetDateTime test = OffsetDateTime.ofInstant(instant, OFFSET_PONE);
+            assertEquals(test.getYear(), 1970);
+            assertEquals(test.getMonth(), Month.JANUARY);
+            assertEquals(test.getDayOfMonth(), 1 + (i >= 23 * 60 * 60 ? 1 : 0));
+            assertEquals(test.getHour(), ((i / (60 * 60)) + 1) % 24);
+            assertEquals(test.getMinute(), (i / 60) % 60);
+            assertEquals(test.getSecond(), i % 60);
+        }
+    }
+
+    public void factory_ofInstant_allDaysInCycle() {
+        // sanity check using different algorithm
+        OffsetDateTime expected = OffsetDateTime.of(LocalDate.of(1970, 1, 1), LocalTime.of(0, 0, 0, 0), ZoneOffset.UTC);
+        for (long i = 0; i < 146097; i++) {
+            Instant instant = Instant.ofEpochSecond(i * 24L * 60L * 60L);
+            OffsetDateTime test = OffsetDateTime.ofInstant(instant, ZoneOffset.UTC);
+            assertEquals(test, expected);
+            expected = expected.plusDays(1);
+        }
+    }
+
+    public void factory_ofInstant_history() {
+        doTest_factory_ofInstant_all(-2820, 2820);
+    }
+
+    //-----------------------------------------------------------------------
+    public void factory_ofInstant_minYear() {
+        doTest_factory_ofInstant_all(Year.MIN_VALUE, Year.MIN_VALUE + 420);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class)
+    public void factory_ofInstant_tooLow() {
+        long days_0000_to_1970 = (146097 * 5) - (30 * 365 + 7);
+        int year = Year.MIN_VALUE - 1;
+        long days = (year * 365L + (year / 4 - year / 100 + year / 400)) - days_0000_to_1970;
+        Instant instant = Instant.ofEpochSecond(days * 24L * 60L * 60L);
+        OffsetDateTime.ofInstant(instant, ZoneOffset.UTC);
+    }
+
+    public void factory_ofInstant_maxYear() {
+        doTest_factory_ofInstant_all(Year.MAX_VALUE - 420, Year.MAX_VALUE);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class)
+    public void factory_ofInstant_tooBig() {
+        long days_0000_to_1970 = (146097 * 5) - (30 * 365 + 7);
+        long year = Year.MAX_VALUE + 1L;
+        long days = (year * 365L + (year / 4 - year / 100 + year / 400)) - days_0000_to_1970;
+        Instant instant = Instant.ofEpochSecond(days * 24L * 60L * 60L);
+        OffsetDateTime.ofInstant(instant, ZoneOffset.UTC);
+    }
+
+    //-----------------------------------------------------------------------
+    public void factory_ofInstant_minWithMinOffset() {
+        long days_0000_to_1970 = (146097 * 5) - (30 * 365 + 7);
+        int year = Year.MIN_VALUE;
+        long days = (year * 365L + (year / 4 - year / 100 + year / 400)) - days_0000_to_1970;
+        Instant instant = Instant.ofEpochSecond(days * 24L * 60L * 60L - OFFSET_MIN.getTotalSeconds());
+        OffsetDateTime test = OffsetDateTime.ofInstant(instant, OFFSET_MIN);
+        assertEquals(test.getYear(), Year.MIN_VALUE);
+        assertEquals(test.getMonth().getValue(), 1);
+        assertEquals(test.getDayOfMonth(), 1);
+        assertEquals(test.getOffset(), OFFSET_MIN);
+        assertEquals(test.getHour(), 0);
+        assertEquals(test.getMinute(), 0);
+        assertEquals(test.getSecond(), 0);
+        assertEquals(test.getNano(), 0);
+    }
+
+    public void factory_ofInstant_minWithMaxOffset() {
+        long days_0000_to_1970 = (146097 * 5) - (30 * 365 + 7);
+        int year = Year.MIN_VALUE;
+        long days = (year * 365L + (year / 4 - year / 100 + year / 400)) - days_0000_to_1970;
+        Instant instant = Instant.ofEpochSecond(days * 24L * 60L * 60L - OFFSET_MAX.getTotalSeconds());
+        OffsetDateTime test = OffsetDateTime.ofInstant(instant, OFFSET_MAX);
+        assertEquals(test.getYear(), Year.MIN_VALUE);
+        assertEquals(test.getMonth().getValue(), 1);
+        assertEquals(test.getDayOfMonth(), 1);
+        assertEquals(test.getOffset(), OFFSET_MAX);
+        assertEquals(test.getHour(), 0);
+        assertEquals(test.getMinute(), 0);
+        assertEquals(test.getSecond(), 0);
+        assertEquals(test.getNano(), 0);
+    }
+
+    public void factory_ofInstant_maxWithMinOffset() {
+        long days_0000_to_1970 = (146097 * 5) - (30 * 365 + 7);
+        int year = Year.MAX_VALUE;
+        long days = (year * 365L + (year / 4 - year / 100 + year / 400)) + 365 - days_0000_to_1970;
+        Instant instant = Instant.ofEpochSecond((days + 1) * 24L * 60L * 60L - 1 - OFFSET_MIN.getTotalSeconds());
+        OffsetDateTime test = OffsetDateTime.ofInstant(instant, OFFSET_MIN);
+        assertEquals(test.getYear(), Year.MAX_VALUE);
+        assertEquals(test.getMonth().getValue(), 12);
+        assertEquals(test.getDayOfMonth(), 31);
+        assertEquals(test.getOffset(), OFFSET_MIN);
+        assertEquals(test.getHour(), 23);
+        assertEquals(test.getMinute(), 59);
+        assertEquals(test.getSecond(), 59);
+        assertEquals(test.getNano(), 0);
+    }
+
+    public void factory_ofInstant_maxWithMaxOffset() {
+        long days_0000_to_1970 = (146097 * 5) - (30 * 365 + 7);
+        int year = Year.MAX_VALUE;
+        long days = (year * 365L + (year / 4 - year / 100 + year / 400)) + 365 - days_0000_to_1970;
+        Instant instant = Instant.ofEpochSecond((days + 1) * 24L * 60L * 60L - 1 - OFFSET_MAX.getTotalSeconds());
+        OffsetDateTime test = OffsetDateTime.ofInstant(instant, OFFSET_MAX);
+        assertEquals(test.getYear(), Year.MAX_VALUE);
+        assertEquals(test.getMonth().getValue(), 12);
+        assertEquals(test.getDayOfMonth(), 31);
+        assertEquals(test.getOffset(), OFFSET_MAX);
+        assertEquals(test.getHour(), 23);
+        assertEquals(test.getMinute(), 59);
+        assertEquals(test.getSecond(), 59);
+        assertEquals(test.getNano(), 0);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(expectedExceptions=DateTimeException.class)
+    public void factory_ofInstant_maxInstantWithMaxOffset() {
+        Instant instant = Instant.ofEpochSecond(Long.MAX_VALUE);
+        OffsetDateTime.ofInstant(instant, OFFSET_MAX);
+    }
+
+    @Test(expectedExceptions=DateTimeException.class)
+    public void factory_ofInstant_maxInstantWithMinOffset() {
+        Instant instant = Instant.ofEpochSecond(Long.MAX_VALUE);
+        OffsetDateTime.ofInstant(instant, OFFSET_MIN);
+    }
+
+    //-----------------------------------------------------------------------
+    private void doTest_factory_ofInstant_all(long minYear, long maxYear) {
+        long days_0000_to_1970 = (146097 * 5) - (30 * 365 + 7);
+        int minOffset = (minYear <= 0 ? 0 : 3);
+        int maxOffset = (maxYear <= 0 ? 0 : 3);
+        long minDays = (minYear * 365L + ((minYear + minOffset) / 4L - (minYear + minOffset) / 100L + (minYear + minOffset) / 400L)) - days_0000_to_1970;
+        long maxDays = (maxYear * 365L + ((maxYear + maxOffset) / 4L - (maxYear + maxOffset) / 100L + (maxYear + maxOffset) / 400L)) + 365L - days_0000_to_1970;
+
+        final LocalDate maxDate = LocalDate.of(Year.MAX_VALUE, 12, 31);
+        OffsetDateTime expected = OffsetDateTime.of(LocalDate.of((int) minYear, 1, 1), LocalTime.of(0, 0, 0, 0), ZoneOffset.UTC);
+        for (long i = minDays; i < maxDays; i++) {
+            Instant instant = Instant.ofEpochSecond(i * 24L * 60L * 60L);
+            try {
+                OffsetDateTime test = OffsetDateTime.ofInstant(instant, ZoneOffset.UTC);
+                assertEquals(test, expected);
+                if (expected.getDate().equals(maxDate) == false) {
+                    expected = expected.plusDays(1);
+                }
+            } catch (RuntimeException|Error ex) {
+                System.out.println("Error: " + i + " " + expected);
+                throw ex;
+            }
+        }
+    }
+
+    // for performance testing
+    //    private void doTest_factory_ofInstant_all(int minYear, int maxYear) {
+    //        long days_0000_to_1970 = (146097 * 5) - (30 * 365 + 7);
+    //        int minOffset = (minYear <= 0 ? 0 : 3);
+    //        int maxOffset = (maxYear <= 0 ? 0 : 3);
+    //        long minDays = (long) (minYear * 365L + ((minYear + minOffset) / 4L - (minYear + minOffset) / 100L + (minYear + minOffset) / 400L)) - days_0000_to_1970;
+    //        long maxDays = (long) (maxYear * 365L + ((maxYear + maxOffset) / 4L - (maxYear + maxOffset) / 100L + (maxYear + maxOffset) / 400L)) + 365L - days_0000_to_1970;
+    //
+    //        OffsetDateTime expected = OffsetDateTime.dateTime(minYear, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC);
+    //        Date cutover = new Date(Long.MIN_VALUE);
+    //        GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
+    //        cal.setGregorianChange(cutover);
+    //        for (long i = minDays; i < maxDays; i++) {
+    //            Instant instant = Instant.instant(i * 24L * 60L * 60L);
+    //            try {
+    //                cal.setTimeInMillis(instant.getEpochSecond() * 1000L);
+    //                assertEquals(cal.get(GregorianCalendar.MONTH), expected.getMonth().getValue() - 1);
+    //                assertEquals(cal.get(GregorianCalendar.DAY_OF_MONTH), expected.getDayOfMonth().getValue());
+    //                expected = expected.plusDays(1);
+    //            } catch (RuntimeException ex) {
+    //                System.out.println("Error: " + i + " " + expected);
+    //                throw ex;
+    //            } catch (Error ex) {
+    //                System.out.println("Error: " + i + " " + expected);
+    //                throw ex;
+    //            }
+    //        }
+    //    }
+
+    //-----------------------------------------------------------------------
+    public void test_toInstant_19700101() {
+        OffsetDateTime dt = OffsetDateTime.of(LocalDate.of(1970, 1, 1), LocalTime.of(0, 0, 0, 0), ZoneOffset.UTC);
+        Instant test = dt.toInstant();
+        assertEquals(test.getEpochSecond(), 0);
+        assertEquals(test.getNano(), 0);
+    }
+
+    public void test_toInstant_19700101_oneNano() {
+        OffsetDateTime dt = OffsetDateTime.of(LocalDate.of(1970, 1, 1), LocalTime.of(0, 0, 0, 1), ZoneOffset.UTC);
+        Instant test = dt.toInstant();
+        assertEquals(test.getEpochSecond(), 0);
+        assertEquals(test.getNano(), 1);
+    }
+
+    public void test_toInstant_19700101_minusOneNano() {
+        OffsetDateTime dt = OffsetDateTime.of(LocalDate.of(1969, 12, 31), LocalTime.of(23, 59, 59, 999999999), ZoneOffset.UTC);
+        Instant test = dt.toInstant();
+        assertEquals(test.getEpochSecond(), -1);
+        assertEquals(test.getNano(), 999999999);
+    }
+
+    public void test_toInstant_19700102() {
+        OffsetDateTime dt = OffsetDateTime.of(LocalDate.of(1970, 1, 2), LocalTime.of(0, 0, 0, 0), ZoneOffset.UTC);
+        Instant test = dt.toInstant();
+        assertEquals(test.getEpochSecond(), 24L * 60L * 60L);
+        assertEquals(test.getNano(), 0);
+    }
+
+    public void test_toInstant_19691231() {
+        OffsetDateTime dt = OffsetDateTime.of(LocalDate.of(1969, 12, 31), LocalTime.of(0, 0, 0, 0), ZoneOffset.UTC);
+        Instant test = dt.toInstant();
+        assertEquals(test.getEpochSecond(), -24L * 60L * 60L);
+        assertEquals(test.getNano(), 0);
+    }
+
+    //-----------------------------------------------------------------------
+    public void test_toEpochSecond_19700101() {
+        OffsetDateTime dt = OffsetDateTime.of(LocalDate.of(1970, 1, 1), LocalTime.of(0, 0, 0, 0), ZoneOffset.UTC);
+        assertEquals(dt.toEpochSecond(), 0);
+    }
+
+    public void test_toEpochSecond_19700101_oneNano() {
+        OffsetDateTime dt = OffsetDateTime.of(LocalDate.of(1970, 1, 1), LocalTime.of( 0, 0, 0, 1), ZoneOffset.UTC);
+        assertEquals(dt.toEpochSecond(), 0);
+    }
+
+    public void test_toEpochSecond_19700101_minusOneNano() {
+        OffsetDateTime dt = OffsetDateTime.of(LocalDate.of(1969, 12, 31), LocalTime.of(23, 59, 59, 999999999), ZoneOffset.UTC);
+        assertEquals(dt.toEpochSecond(), -1);
+    }
+
+    public void test_toEpochSecond_19700102() {
+        OffsetDateTime dt = OffsetDateTime.of(LocalDate.of(1970, 1, 2), LocalTime.of(0, 0, 0, 0), ZoneOffset.UTC);
+        assertEquals(dt.toEpochSecond(), 24L * 60L * 60L);
+    }
+
+    public void test_toEpochSecond_19691231() {
+        OffsetDateTime dt = OffsetDateTime.of(LocalDate.of(1969, 12, 31), LocalTime.of(0, 0, 0, 0), ZoneOffset.UTC);
+        assertEquals(dt.toEpochSecond(), -24L * 60L * 60L);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/temporal/TestOffsetTime.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.temporal;
+
+import java.time.temporal.OffsetTime;
+
+import org.testng.annotations.Test;
+import test.java.time.AbstractTest;
+
+/**
+ * Test OffsetTime.
+ */
+@Test
+public class TestOffsetTime extends AbstractTest {
+
+    @Test
+    public void test_immutable() {
+        assertImmutable(OffsetTime.class);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/temporal/TestThaiBuddhistChronoImpl.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.temporal;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.Calendar;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import java.time.LocalDate;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.ChronoLocalDate;
+import java.time.calendar.ThaiBuddhistChrono;
+
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+
+/**
+ * Test.
+ */
+@Test
+public class TestThaiBuddhistChronoImpl {
+
+    /**
+     * Range of years to check consistency with java.util.Calendar
+     */
+    @DataProvider(name="RangeVersusCalendar")
+    Object[][] provider_rangeVersusCalendar() {
+        return new Object[][] {
+            {LocalDate.of(1583, 1, 1), LocalDate.of(2100, 1, 1)},
+        };
+    }
+
+    //-----------------------------------------------------------------------
+    // Verify  ThaiBuddhist Calendar matches java.util.Calendar for range
+    //-----------------------------------------------------------------------
+    @Test(groups={"implementation"}, dataProvider="RangeVersusCalendar")
+    public void test_ThaiBuddhistChrono_vsCalendar(LocalDate isoStartDate, LocalDate isoEndDate) {
+        Locale locale = Locale.forLanguageTag("th-TH--u-ca-buddhist");
+        assertEquals(locale.toString(), "th_TH", "Unexpected locale");
+        Calendar cal = java.util.Calendar.getInstance(locale);
+        assertEquals(cal.getCalendarType(), "buddhist", "Unexpected calendar type");
+
+        ChronoLocalDate<ThaiBuddhistChrono> thaiDate = ThaiBuddhistChrono.INSTANCE.date(isoStartDate);
+
+        cal.setTimeZone(TimeZone.getTimeZone("GMT+00"));
+        cal.set(Calendar.YEAR, thaiDate.get(ChronoField.YEAR));
+        cal.set(Calendar.MONTH, thaiDate.get(ChronoField.MONTH_OF_YEAR) - 1);
+        cal.set(Calendar.DAY_OF_MONTH, thaiDate.get(ChronoField.DAY_OF_MONTH));
+
+        while (thaiDate.isBefore(isoEndDate)) {
+            assertEquals(thaiDate.get(ChronoField.DAY_OF_MONTH), cal.get(Calendar.DAY_OF_MONTH), "Day mismatch in " + thaiDate + ";  cal: " + cal);
+            assertEquals(thaiDate.get(ChronoField.MONTH_OF_YEAR), cal.get(Calendar.MONTH) + 1, "Month mismatch in " + thaiDate);
+            assertEquals(thaiDate.get(ChronoField.YEAR_OF_ERA), cal.get(Calendar.YEAR), "Year mismatch in " + thaiDate);
+
+            thaiDate = thaiDate.plus(1, ChronoUnit.DAYS);
+            cal.add(Calendar.DAY_OF_MONTH, 1);
+        }
+    }
+
+    private String calToString(Calendar cal) {
+        return String.format("%04d-%02d-%02d",
+                cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/temporal/TestYear.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.temporal;
+
+import java.time.temporal.Year;
+
+import org.testng.annotations.Test;
+import test.java.time.AbstractTest;
+
+/**
+ * Test Year.
+ */
+@Test
+public class TestYear extends AbstractTest {
+
+    @Test
+    public void test_immutable() {
+        assertImmutable(Year.class);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/temporal/TestYearMonth.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.temporal;
+
+import java.time.temporal.YearMonth;
+
+import org.testng.annotations.Test;
+import test.java.time.AbstractTest;
+
+/**
+ * Test YearMonth.
+ */
+@Test
+public class TestYearMonth extends AbstractTest {
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_immutable() {
+        assertImmutable(YearMonth.class);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/time/zone/TestFixedZoneRules.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2010-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package test.java.time.zone;
+
+import java.time.zone.*;
+
+import static org.testng.Assert.assertEquals;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test ZoneRules for fixed offset time-zones.
+ */
+@Test
+public class TestFixedZoneRules {
+
+    private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1);
+
+    private ZoneRules make(ZoneOffset offset) {
+        return offset.getRules();
+    }
+
+    //-----------------------------------------------------------------------
+    @Test(groups="implementation")
+    public void test_data_nullInput() {
+        ZoneRules test = make(OFFSET_PONE);
+        assertEquals(test.getOffset((Instant) null), OFFSET_PONE);
+        assertEquals(test.getOffset((LocalDateTime) null), OFFSET_PONE);
+        assertEquals(test.getValidOffsets(null).size(), 1);
+        assertEquals(test.getValidOffsets(null).get(0), OFFSET_PONE);
+        assertEquals(test.getTransition(null), null);
+        assertEquals(test.getStandardOffset(null), OFFSET_PONE);
+        assertEquals(test.getDaylightSavings(null), Duration.ZERO);
+        assertEquals(test.isDaylightSavings(null), false);
+        assertEquals(test.nextTransition(null), null);
+        assertEquals(test.previousTransition(null), null);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/time/test/java/util/TestFormatter.java	Tue Jan 22 20:59:21 2013 -0800
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.java.util;
+
+import java.time.Instant;
+import java.time.temporal.OffsetDateTime;
+import java.time.ZonedDateTime;
+import java.time.temporal.ChronoField;
+
+import java.util.*;
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.assertEquals;
+
+/* @test
+ * @summary Unit test for j.u.Formatter threeten date/time support
+ */
+@Test(groups={"implementation"})
+public class TestFormatter {
+
+    // time
+    private static String[] fmtStrTime = new String[] {
+         "H:[%tH] I:[%1$tI] k:[%1$tk] l:[%1$tl] M:[%1$tM] S:[%1$tS] L:[%1$tL] N:[%1$tN] p:[%1$tp]",
+         "H:[%TH] I:[%1$TI] k:[%1$Tk] l:[%1$Tl] M:[%1$TM] S:[%1$TS] L:[%1$TL] N:[%1$TN] p:[%1$Tp]",
+         "R:[%tR] T:[%1$tT] r:[%1$tr]",
+         "R:[%TR] T:[%1$TT] r:[%1$Tr]"
+    };
+    // date
+    private static String[] fmtStrDate = new String[] {
+        "B:[%tB] b:[%1$tb] h:[%1$th] A:[%1$tA] a:[%1$ta] C:[%1$tC] Y:[%1$tY] y:[%1$ty] j:[%1$tj] m:[%1$tm] d:[%1$td] e:[%1$te]",
+        "B:[%TB] b:[%1$Tb] h:[%1$Th] A:[%1$TA] a:[%1$Ta] C:[%1$TC] Y:[%1$TY] y:[%1$Ty] j:[%1$Tj] m:[%1$Tm] d:[%1$Td] e:[%1$Te]",
+        "D:[%tD] F:[%1$tF]",
+        "D:[%TD] F:[%1$TF]"
+    };
+
+    private int total = 0;
+    private int failure = 0;
+    private boolean verbose = true;
+
+    @Test
+    public void test () {
+
+        int N = 12;
+        //locales = Locale.getAvailableLocales();
+        Locale[] locales = new Locale[] {
+           Locale.ENGLISH, Locale.FRENCH, Locale.JAPANESE, Locale.CHINESE};
+
+        Random r = new Random();
+        ZonedDateTime  zdt = ZonedDateTime.now();
+        while (N-- > 0) {
+            zdt = zdt.withDayOfYear(r.nextInt(365) + 1)
+                     .with(ChronoField.SECOND_OF_DAY, r.nextInt(86400));
+            Instant instant = zdt.toInstant();
+            Calendar cal = Calendar.getInstance();
+            cal.setTimeInMillis(instant.toEpochMilli());
+
+            for (Locale locale : locales) {
+                    for (String fmtStr : fmtStrDate) {
+                    testDate(fmtStr, locale, zdt, cal);
+                }
+                for (String fmtStr : fmtStrTime) {
+                    testTime(fmtStr, locale, zdt, cal);
+                }
+                testZoneId(locale, zdt, cal);
+                testInstant(locale, instant, zdt, cal);
+            }
+        }
+        if (verbose) {
+            if (failure != 0) {
+                System.out.println("Total " + failure + "/" + total + " tests failed");
+            } else {
+                System.out.println("All tests (" + total + ") PASSED");
+            }
+        }
+        assertEquals(failure, 0);
+    }
+
+    private String getClassName(Object o) {
+        Class c = o.getClass();
+        return c.getName().substring(c.getPackage().getName().length() + 1);
+    }
+
+    private String test(String fmtStr, Locale locale,
+                               String expected, Object dt) {
+        String out = new Formatter(
+            new StringBuilder(), locale).format(fmtStr, dt).out().toString();
+        if (verbose) {
+            System.out.printf("%-18s  : %s%n", getClassName(dt), out);
+        }
+        if (expected != null && !out.equals(expected)) {
+            System.out.printf("=====>%-18s  : %s  [ FAILED expected: %s ]%n",
+                              getClassName(dt), out, expected);
+            new RuntimeException().printStackTrace();
+            failure++;
+        }
+        total++;
+        return out;
+    }
+
+    private void printFmtStr(Locale locale, String fmtStr) {
+        if (verbose) {
+            System.out.println("--------------------");
+            System.out.printf("[%s, %s]%n", locale.toString(), fmtStr);
+        }
+    }
+
+    private void testDate(String fmtStr, Locale locale,
+                                 ZonedDateTime zdt, Calendar cal) {
+        printFmtStr(locale, fmtStr);
+        String expected = test(fmtStr, locale, null, cal);
+        test(fmtStr, locale, expected, zdt);
+        test(fmtStr, locale, expected, OffsetDateTime.of(zdt));
+        test(fmtStr, locale, expected, zdt.getDateTime());
+        test(fmtStr, locale, expected, OffsetDateTime.of(zdt).toOffsetDate());
+        test(fmtStr, locale, expected, zdt.getDate());
+    }
+
+    private void testTime(String fmtStr, Locale locale,
+                                 ZonedDateTime zdt, Calendar cal) {
+        printFmtStr(locale, fmtStr);
+        String expected = test(fmtStr, locale, null, cal);
+        test(fmtStr, locale, expected, zdt);
+        test(fmtStr, locale, expected, OffsetDateTime.of(zdt));
+        test(fmtStr, locale, expected, zdt.getDateTime());
+        test(fmtStr, locale, expected, OffsetDateTime.of(zdt).toOffsetTime());
+        test(fmtStr, locale, expected, zdt.getTime());
+    }
+
+    private void testZoneId(Locale locale, ZonedDateTime zdt, Calendar cal) {
+        String fmtStr = "z:[%tz] z:[%1$Tz] Z:[%1$tZ] Z:[%1$TZ]";
+        printFmtStr(locale, fmtStr);
+        String expected = test(fmtStr, locale, null, cal);
+        test(fmtStr, locale, expected, zdt);
+        // get a new cal with fixed tz
+        Calendar cal0 = Calendar.getInstance();
+        cal0.setTimeInMillis(zdt.toInstant().toEpochMilli());
+        cal0.setTimeZone(TimeZone.getTimeZone("GMT" + zdt.getOffset().getId()));
+        expected = test(fmtStr, locale, null, cal0).replaceAll("GMT", "");
+        test(fmtStr, locale, expected, OffsetDateTime.of(zdt));
+        test(fmtStr, locale, expected, OffsetDateTime.of(zdt).toOffsetDate());
+        test(fmtStr, locale, expected, OffsetDateTime.of(zdt).toOffsetTime());
+
+        // datetime + zid
+        fmtStr = "c:[%tc] c:[%1$Tc]";
+        printFmtStr(locale, fmtStr);
+        expected = test(fmtStr, locale, null, cal);
+        test(fmtStr, locale, expected, zdt);
+    }
+
+    private void testInstant(Locale locale, Instant instant,
+                             ZonedDateTime zdt, Calendar cal) {
+        String fmtStr = "s:[%ts] s:[%1$Ts] Q:[%1$tQ] Q:[%1$TQ]";
+        printFmtStr(locale, fmtStr);
+        String expected = test(fmtStr, locale, null, cal);
+        test(fmtStr, locale, expected, instant);
+        test(fmtStr, locale, expected, zdt);
+        test(fmtStr, locale, expected, OffsetDateTime.of(zdt));
+    }
+}