changeset 6418:919afffa70b0

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
author sherman
date Tue, 22 Jan 2013 20:59:21 -0800
parents c18f28312c49
children 71691b9d45ab
files make/docs/CORE_PKGS.gmk make/java/Makefile make/java/time/Makefile make/jprt.properties make/sun/Makefile make/sun/tzdb/Makefile make/tools/Makefile make/tools/src/build/tools/tzdb/ChronoField.java make/tools/src/build/tools/tzdb/DateTimeException.java make/tools/src/build/tools/tzdb/LocalDate.java make/tools/src/build/tools/tzdb/LocalDateTime.java make/tools/src/build/tools/tzdb/LocalTime.java make/tools/src/build/tools/tzdb/TimeDefinition.java make/tools/src/build/tools/tzdb/TzdbZoneRulesCompiler.java make/tools/src/build/tools/tzdb/Utils.java make/tools/src/build/tools/tzdb/ZoneOffset.java make/tools/src/build/tools/tzdb/ZoneOffsetTransition.java make/tools/src/build/tools/tzdb/ZoneOffsetTransitionRule.java make/tools/src/build/tools/tzdb/ZoneRules.java make/tools/src/build/tools/tzdb/ZoneRulesBuilder.java make/tools/tzdb/Makefile makefiles/CreateJars.gmk makefiles/GendataTZDB.gmk makefiles/GenerateData.gmk makefiles/Tools.gmk src/share/classes/java/time/Clock.java src/share/classes/java/time/DateTimeException.java src/share/classes/java/time/DayOfWeek.java src/share/classes/java/time/Duration.java src/share/classes/java/time/Instant.java src/share/classes/java/time/LocalDate.java src/share/classes/java/time/LocalDateTime.java src/share/classes/java/time/LocalTime.java src/share/classes/java/time/Month.java src/share/classes/java/time/Period.java src/share/classes/java/time/PeriodParser.java src/share/classes/java/time/Ser.java src/share/classes/java/time/ZoneId.java src/share/classes/java/time/ZoneOffset.java src/share/classes/java/time/ZoneRegion.java src/share/classes/java/time/ZonedDateTime.java src/share/classes/java/time/calendar/ChronoDateImpl.java src/share/classes/java/time/calendar/HijrahChrono.java src/share/classes/java/time/calendar/HijrahDate.java src/share/classes/java/time/calendar/HijrahDeviationReader.java src/share/classes/java/time/calendar/HijrahEra.java src/share/classes/java/time/calendar/JapaneseChrono.java src/share/classes/java/time/calendar/JapaneseDate.java src/share/classes/java/time/calendar/JapaneseEra.java src/share/classes/java/time/calendar/MinguoChrono.java src/share/classes/java/time/calendar/MinguoDate.java src/share/classes/java/time/calendar/MinguoEra.java src/share/classes/java/time/calendar/Ser.java src/share/classes/java/time/calendar/ThaiBuddhistChrono.java src/share/classes/java/time/calendar/ThaiBuddhistDate.java src/share/classes/java/time/calendar/ThaiBuddhistEra.java src/share/classes/java/time/calendar/package-info.java src/share/classes/java/time/format/DateTimeBuilder.java src/share/classes/java/time/format/DateTimeFormatStyleProvider.java src/share/classes/java/time/format/DateTimeFormatSymbols.java src/share/classes/java/time/format/DateTimeFormatter.java src/share/classes/java/time/format/DateTimeFormatterBuilder.java src/share/classes/java/time/format/DateTimeFormatters.java src/share/classes/java/time/format/DateTimeParseContext.java src/share/classes/java/time/format/DateTimeParseException.java src/share/classes/java/time/format/DateTimePrintContext.java src/share/classes/java/time/format/DateTimePrintException.java src/share/classes/java/time/format/DateTimeTextProvider.java src/share/classes/java/time/format/FormatStyle.java src/share/classes/java/time/format/SignStyle.java src/share/classes/java/time/format/TextStyle.java src/share/classes/java/time/format/package-info.java src/share/classes/java/time/overview.html src/share/classes/java/time/package-info.java src/share/classes/java/time/temporal/Adjusters.java src/share/classes/java/time/temporal/Chrono.java src/share/classes/java/time/temporal/ChronoField.java src/share/classes/java/time/temporal/ChronoLocalDate.java src/share/classes/java/time/temporal/ChronoLocalDateTime.java src/share/classes/java/time/temporal/ChronoLocalDateTimeImpl.java src/share/classes/java/time/temporal/ChronoUnit.java src/share/classes/java/time/temporal/ChronoZonedDateTime.java src/share/classes/java/time/temporal/ChronoZonedDateTimeImpl.java src/share/classes/java/time/temporal/Era.java src/share/classes/java/time/temporal/ISOChrono.java src/share/classes/java/time/temporal/ISOEra.java src/share/classes/java/time/temporal/ISOFields.java src/share/classes/java/time/temporal/JulianFields.java src/share/classes/java/time/temporal/MonthDay.java src/share/classes/java/time/temporal/OffsetDate.java src/share/classes/java/time/temporal/OffsetDateTime.java src/share/classes/java/time/temporal/OffsetTime.java src/share/classes/java/time/temporal/Queries.java src/share/classes/java/time/temporal/Ser.java src/share/classes/java/time/temporal/SimplePeriod.java src/share/classes/java/time/temporal/Temporal.java src/share/classes/java/time/temporal/TemporalAccessor.java src/share/classes/java/time/temporal/TemporalAdder.java src/share/classes/java/time/temporal/TemporalAdjuster.java src/share/classes/java/time/temporal/TemporalField.java src/share/classes/java/time/temporal/TemporalQuery.java src/share/classes/java/time/temporal/TemporalSubtractor.java src/share/classes/java/time/temporal/TemporalUnit.java src/share/classes/java/time/temporal/ValueRange.java src/share/classes/java/time/temporal/WeekFields.java src/share/classes/java/time/temporal/Year.java src/share/classes/java/time/temporal/YearMonth.java src/share/classes/java/time/temporal/package-info.java src/share/classes/java/time/zone/Ser.java src/share/classes/java/time/zone/TzdbZoneRulesProvider.java src/share/classes/java/time/zone/ZoneOffsetTransition.java src/share/classes/java/time/zone/ZoneOffsetTransitionRule.java src/share/classes/java/time/zone/ZoneRules.java src/share/classes/java/time/zone/ZoneRulesException.java src/share/classes/java/time/zone/ZoneRulesProvider.java src/share/classes/java/time/zone/package-info.java src/share/classes/java/util/Formatter.java test/Makefile test/java/time/META-INF/services/java.time.temporal.Chrono test/java/time/TEST.properties test/java/time/tck/java/time/AbstractDateTimeTest.java test/java/time/tck/java/time/AbstractTCKTest.java test/java/time/tck/java/time/TCKClock.java test/java/time/tck/java/time/TCKClock_Fixed.java test/java/time/tck/java/time/TCKClock_Offset.java test/java/time/tck/java/time/TCKClock_System.java test/java/time/tck/java/time/TCKClock_Tick.java test/java/time/tck/java/time/TCKDayOfWeek.java test/java/time/tck/java/time/TCKDuration.java test/java/time/tck/java/time/TCKInstant.java test/java/time/tck/java/time/TCKLocalDate.java test/java/time/tck/java/time/TCKLocalDateTime.java test/java/time/tck/java/time/TCKLocalTime.java test/java/time/tck/java/time/TCKMonth.java test/java/time/tck/java/time/TCKZoneId.java test/java/time/tck/java/time/TCKZoneOffset.java test/java/time/tck/java/time/TCKZonedDateTime.java test/java/time/tck/java/time/calendar/CopticChrono.java test/java/time/tck/java/time/calendar/CopticDate.java test/java/time/tck/java/time/calendar/CopticEra.java test/java/time/tck/java/time/calendar/TestChronoLocalDate.java test/java/time/tck/java/time/calendar/TestChronoLocalDateTime.java test/java/time/tck/java/time/calendar/TestHijrahChrono.java test/java/time/tck/java/time/calendar/TestJapaneseChrono.java test/java/time/tck/java/time/calendar/TestMinguoChrono.java test/java/time/tck/java/time/calendar/TestServiceLoader.java test/java/time/tck/java/time/calendar/TestThaiBuddhistChrono.java test/java/time/tck/java/time/format/TCKDateTimeFormatSymbols.java test/java/time/tck/java/time/format/TCKDateTimeFormatter.java test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java test/java/time/tck/java/time/format/TCKDateTimeFormatters.java test/java/time/tck/java/time/format/TCKDateTimePrintException.java test/java/time/tck/java/time/format/TCKDateTimeTextPrinting.java test/java/time/tck/java/time/format/TCKLocalizedFieldParser.java test/java/time/tck/java/time/format/TCKLocalizedFieldPrinter.java test/java/time/tck/java/time/temporal/TCKDateTimeAdjusters.java test/java/time/tck/java/time/temporal/TCKISOFields.java test/java/time/tck/java/time/temporal/TCKJulianFields.java test/java/time/tck/java/time/temporal/TCKMonthDay.java test/java/time/tck/java/time/temporal/TCKOffsetDate.java test/java/time/tck/java/time/temporal/TCKOffsetDateTime.java test/java/time/tck/java/time/temporal/TCKOffsetTime.java test/java/time/tck/java/time/temporal/TCKSimplePeriod.java test/java/time/tck/java/time/temporal/TCKWeekFields.java test/java/time/tck/java/time/temporal/TCKYear.java test/java/time/tck/java/time/temporal/TCKYearMonth.java test/java/time/tck/java/time/temporal/TestChrono.java test/java/time/tck/java/time/temporal/TestChronoLocalDate.java test/java/time/tck/java/time/temporal/TestChronoLocalDateTime.java test/java/time/tck/java/time/temporal/TestChronoZonedDateTime.java test/java/time/tck/java/time/temporal/TestISOChrono.java test/java/time/tck/java/time/zone/TCKFixedZoneRules.java test/java/time/tck/java/time/zone/TCKZoneOffsetTransition.java test/java/time/tck/java/time/zone/TCKZoneOffsetTransitionRule.java test/java/time/tck/java/time/zone/TCKZoneRules.java test/java/time/tck/java/time/zone/TCKZoneRulesProvider.java test/java/time/test/java/time/AbstractTest.java test/java/time/test/java/time/MockSimplePeriod.java test/java/time/test/java/time/TestClock_Fixed.java test/java/time/test/java/time/TestClock_Offset.java test/java/time/test/java/time/TestClock_System.java test/java/time/test/java/time/TestClock_Tick.java test/java/time/test/java/time/TestDuration.java test/java/time/test/java/time/TestInstant.java test/java/time/test/java/time/TestLocalDate.java test/java/time/test/java/time/TestLocalDateTime.java test/java/time/test/java/time/TestLocalTime.java test/java/time/test/java/time/TestPeriod.java test/java/time/test/java/time/TestPeriodParser.java test/java/time/test/java/time/TestZoneId.java test/java/time/test/java/time/TestZoneOffset.java test/java/time/test/java/time/TestZonedDateTime.java test/java/time/test/java/time/format/AbstractTestPrinterParser.java test/java/time/test/java/time/format/MockIOExceptionAppendable.java test/java/time/test/java/time/format/TestCharLiteralParser.java test/java/time/test/java/time/format/TestCharLiteralPrinter.java test/java/time/test/java/time/format/TestDateTimeFormatSymbols.java test/java/time/test/java/time/format/TestDateTimeFormatter.java test/java/time/test/java/time/format/TestDateTimeFormatters.java test/java/time/test/java/time/format/TestDateTimePrintException.java test/java/time/test/java/time/format/TestDateTimeTextProvider.java test/java/time/test/java/time/format/TestFractionPrinterParser.java test/java/time/test/java/time/format/TestNumberParser.java test/java/time/test/java/time/format/TestNumberPrinter.java test/java/time/test/java/time/format/TestPadParserDecorator.java test/java/time/test/java/time/format/TestPadPrinterDecorator.java test/java/time/test/java/time/format/TestReducedParser.java test/java/time/test/java/time/format/TestReducedPrinter.java test/java/time/test/java/time/format/TestSettingsParser.java test/java/time/test/java/time/format/TestStringLiteralParser.java test/java/time/test/java/time/format/TestStringLiteralPrinter.java test/java/time/test/java/time/format/TestTextParser.java test/java/time/test/java/time/format/TestTextPrinter.java test/java/time/test/java/time/format/TestZoneIdParser.java test/java/time/test/java/time/format/TestZoneOffsetParser.java test/java/time/test/java/time/format/TestZoneOffsetPrinter.java test/java/time/test/java/time/format/TestZoneTextPrinterParser.java test/java/time/test/java/time/temporal/MockFieldNoValue.java test/java/time/test/java/time/temporal/MockFieldValue.java test/java/time/test/java/time/temporal/TestChronoUnit.java test/java/time/test/java/time/temporal/TestDateTimeAdjusters.java test/java/time/test/java/time/temporal/TestDateTimeBuilderCombinations.java test/java/time/test/java/time/temporal/TestDateTimeValueRange.java test/java/time/test/java/time/temporal/TestISOChronoImpl.java test/java/time/test/java/time/temporal/TestJapaneseChronoImpl.java test/java/time/test/java/time/temporal/TestMonthDay.java test/java/time/test/java/time/temporal/TestOffsetDate.java test/java/time/test/java/time/temporal/TestOffsetDateTime.java test/java/time/test/java/time/temporal/TestOffsetDateTime_instants.java test/java/time/test/java/time/temporal/TestOffsetTime.java test/java/time/test/java/time/temporal/TestThaiBuddhistChronoImpl.java test/java/time/test/java/time/temporal/TestYear.java test/java/time/test/java/time/temporal/TestYearMonth.java test/java/time/test/java/time/zone/TestFixedZoneRules.java test/java/time/test/java/util/TestFormatter.java
diffstat 235 files changed, 103765 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/make/docs/CORE_PKGS.gmk	Tue Jan 22 18:30:49 2013 -0800
+++ b/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/make/java/Makefile	Tue Jan 22 18:30:49 2013 -0800
+++ b/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/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/make/jprt.properties	Tue Jan 22 18:30:49 2013 -0800
+++ b/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/make/sun/Makefile	Tue Jan 22 18:30:49 2013 -0800
+++ b/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/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/make/tools/Makefile	Tue Jan 22 18:30:49 2013 -0800
+++ b/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/makefiles/CreateJars.gmk	Tue Jan 22 18:30:49 2013 -0800
+++ b/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/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/makefiles/GenerateData.gmk	Tue Jan 22 18:30:49 2013 -0800
+++ b/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/makefiles/Tools.gmk	Tue Jan 22 18:30:49 2013 -0800
+++ b/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/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/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/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/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/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/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;