diff --git a/make/docs/CORE_PKGS.gmk b/make/docs/CORE_PKGS.gmk index 2c2b1774f3269689655c87eae04a513c9364531a..86aeae9501d02786601609620833d677a4185619 100644 --- a/make/docs/CORE_PKGS.gmk +++ b/make/docs/CORE_PKGS.gmk @@ -127,6 +127,11 @@ CORE_PKGS = \ java.sql \ java.text \ java.text.spi \ + java.time \ + java.time.temporal \ + java.time.calendar \ + java.time.format \ + java.time.zone \ java.util \ java.util.concurrent \ java.util.concurrent.atomic \ diff --git a/make/java/Makefile b/make/java/Makefile index 67f735fcb1d095e072e3abf67341f51c88c1cea8..80c97d27f5815839967c24d6dc591b025af6aaa7 100644 --- a/make/java/Makefile +++ b/make/java/Makefile @@ -39,7 +39,7 @@ SUBDIRS += version jvm redist verify fdlibm java sun_nio jli main zip # Others # Note: java_crw_demo java_hprof_demo are demos but must be delivered built in sdk -SUBDIRS += security math util text net nio jar +SUBDIRS += security math util text net nio jar time SUBDIRS_desktop = awt applet beans SUBDIRS_management = management diff --git a/make/java/time/Makefile b/make/java/time/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0ff3698bbf31f65982c1007a122d83426c4ba85b --- /dev/null +++ b/make/java/time/Makefile @@ -0,0 +1,42 @@ +# +# Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# +# Makefile for building jar utility. +# + +BUILDDIR = ../../ +PACKAGE = java.time +include $(BUILDDIR)/common/Defs.gmk + +# +# Files +# +AUTO_FILES_JAVA_DIRS = java/time + +# +# Rules +# +include $(BUILDDIR)/common/Classes.gmk diff --git a/make/jprt.properties b/make/jprt.properties index 4bd2d4b84c61657f9179a2f6c9fc1a17ba220ad7..a6d2ea1d0d4c7d8d94ef4f304afc6acd38e4d5f5 100644 --- a/make/jprt.properties +++ b/make/jprt.properties @@ -87,6 +87,7 @@ jprt.make.rule.core.test.targets= \ ${jprt.my.test.target.set:TESTNAME=jdk_text}, \ ${jprt.my.test.target.set:TESTNAME=jdk_tools}, \ ${jprt.my.test.target.set:TESTNAME=jdk_jfr}, \ + ${jprt.my.test.target.set:TESTNAME=jdk_time}, \ ${jprt.my.test.target.set:TESTNAME=jdk_other} # All vm test targets (testset=all) diff --git a/make/sun/Makefile b/make/sun/Makefile index 623923296114cf0c9bc1d5ac9b70feef4c129be4..3d26ee5e0b4d1887f256ade0de6e07189cb48a55 100644 --- a/make/sun/Makefile +++ b/make/sun/Makefile @@ -70,7 +70,7 @@ else endif # nio need to be compiled before awt to have all charsets ready -SUBDIRS = jar security javazic misc net nio text util launcher cldr +SUBDIRS = jar security javazic misc net nio text util launcher cldr tzdb ifdef BUILD_HEADLESS_ONLY DISPLAY_LIBS = awt $(HEADLESS_SUBDIR) diff --git a/make/sun/tzdb/Makefile b/make/sun/tzdb/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d09a1251b1de074d79270fa483977ba3c18e1d5a --- /dev/null +++ b/make/sun/tzdb/Makefile @@ -0,0 +1,68 @@ +# +# Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# +# Makefile for building tzdb compiler utility. +# + +BUILDDIR = ../.. +PACKAGE = sun.tzdb +PRODUCT = sun +include $(BUILDDIR)/common/Defs.gmk + +# This program must contain a manifest that defines the execution level +# needed to follow standard Vista User Access Control Guidelines +# This must be set before Program.gmk is included +# +BUILD_MANIFEST=true + +# +# Time zone data file creation +# +TZDATA_DIR := ../javazic/tzdata +TZDATA_VER := $(subst tzdata,,$(shell $(GREP) '^tzdata' $(TZDATA_DIR)/VERSION)) +TZFILE := africa antarctica asia australasia europe northamerica southamerica backward etcetera +TZFILES := $(addprefix $(TZDATA_DIR)/,$(TZFILE)) + +TZDB_JAR = tzdb.jar + +# +# Rules +# +include $(BUILDDIR)/common/Classes.gmk + +# +# Add to the build rule +# +build: $(LIBDIR)/$(TZDB_JAR) + +$(LIBDIR)/$(TZDB_JAR): $(TZFILES) + $(prep-target) + echo build tzdb from version $(TZDATA_VER) + $(BOOT_JAVA_CMD) -jar $(BUILDTOOLJARDIR)/tzdb.jar -verbose \ + -version $(TZDATA_VER) -srcdir $(TZDATA_DIR) -dstdir $(LIBDIR) $(TZFILE) + +clean clobber:: + $(RM) $(LIBDIR)/$(TZDB_JAR) diff --git a/make/tools/Makefile b/make/tools/Makefile index ca39dd6df67710ae5d7f10f43cc9ef554abfa8a5..586a169948658cda877e84acb2dff6982e11014d 100644 --- a/make/tools/Makefile +++ b/make/tools/Makefile @@ -53,6 +53,7 @@ SUBDIRS = \ makeclasslist \ strip_properties \ spp \ + tzdb \ CharsetMapping ifndef DISABLE_NIMBUS diff --git a/make/tools/src/build/tools/tzdb/ChronoField.java b/make/tools/src/build/tools/tzdb/ChronoField.java new file mode 100644 index 0000000000000000000000000000000000000000..7ce34bbfae262f02e427880ab762c0cd8edb604e --- /dev/null +++ b/make/tools/src/build/tools/tzdb/ChronoField.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package build.tools.tzdb; + +/** + * A standard set of date/time fields. + * + * @since 1.8 + */ +enum ChronoField { + + /** + * The second-of-minute. + *
+ * This counts the second within the minute, from 0 to 59. + * This field has the same meaning for all calendar systems. + */ + SECOND_OF_MINUTE("SecondOfMinute", 0, 59), + + /** + * The second-of-day. + *
+ * This counts the second within the day, from 0 to (24 * 60 * 60) - 1. + * This field has the same meaning for all calendar systems. + */ + SECOND_OF_DAY("SecondOfDay", 0, 86400 - 1), + + /** + * The minute-of-hour. + *
+ * This counts the minute within the hour, from 0 to 59. + * This field has the same meaning for all calendar systems. + */ + MINUTE_OF_HOUR("MinuteOfHour", 0, 59), + + /** + * The hour-of-day. + *
+ * This counts the hour within the day, from 0 to 23. + * This is the hour that would be observed on a standard 24-hour digital clock. + * This field has the same meaning for all calendar systems. + */ + HOUR_OF_DAY("HourOfDay", 0, 23), + + + /** + * The day-of-month. + *
+ * This represents the concept of the day within the month. + * In the default ISO calendar system, this has values from 1 to 31 in most months. + * April, June, September, November have days from 1 to 30, while February has days + * from 1 to 28, or 29 in a leap year. + *
+ * Non-ISO calendar systems should implement this field using the most recognized + * day-of-month values for users of the calendar system. + * Normally, this is a count of days from 1 to the length of the month. + */ + DAY_OF_MONTH("DayOfMonth", 1, 31), + + /** + * The month-of-year, such as March. + *
+ * This represents the concept of the month within the year. + * In the default ISO calendar system, this has values from January (1) to December (12). + *
+ * Non-ISO calendar systems should implement this field using the most recognized + * month-of-year values for users of the calendar system. + * Normally, this is a count of months starting from 1. + */ + MONTH_OF_YEAR("MonthOfYear", 1, 12), + + /** + * The proleptic year, such as 2012. + *
+ * This represents the concept of the year, counting sequentially and using negative numbers. + * The proleptic year is not interpreted in terms of the era. + * See {@link #YEAR_OF_ERA} for an example showing the mapping from proleptic year to year-of-era. + *
+ * The standard mental model for a date is based on three concepts - year, month and day. + * These map onto the {@code YEAR}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} fields. + * Note that there is no reference to eras. + * The full model for a date requires four concepts - era, year, month and day. These map onto + * the {@code ERA}, {@code YEAR_OF_ERA}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} fields. + * Whether this field or {@code YEAR_OF_ERA} is used depends on which mental model is being used. + * See {@link ChronoLocalDate} for more discussion on this topic. + *
+ * Non-ISO calendar systems should implement this field as follows. + * If the calendar system has only two eras, before and after a fixed date, then the + * proleptic-year value must be the same as the year-of-era value for the later era, + * and increasingly negative for the earlier era. + * If the calendar system has more than two eras, then the proleptic-year value may be + * defined with any appropriate value, although defining it to be the same as ISO may be + * the best option. + */ + YEAR("Year", -999_999_999, 999_999_999); + + private final String name; + private final int min; + private final int max; + + private ChronoField(String name, int min, int max) { + this.name = name; + this.min= min; + this.max= max; + } + + /** + * Checks that the specified value is valid for this field. + *
+ * + * @param value the value to check + * @return the value that was passed in + */ + public int checkValidValue(int value) { + if (value >= min && value <= max) { + return value; + } + throw new DateTimeException("Invalid value for " + name + " value: " + value); + } + + public String toString() { + return name; + } + +} diff --git a/make/tools/src/build/tools/tzdb/DateTimeException.java b/make/tools/src/build/tools/tzdb/DateTimeException.java new file mode 100644 index 0000000000000000000000000000000000000000..2b7674df3ff44ddc6587b4bad7e9f6030bd16aa4 --- /dev/null +++ b/make/tools/src/build/tools/tzdb/DateTimeException.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package build.tools.tzdb; + +/** + * Exception used to indicate a problem while calculating a date-time. + *
+ * This exception is used to indicate problems with creating, querying + * and manipulating date-time objects. + * + * @since 1.8 + */ +class DateTimeException extends RuntimeException { + + /** + * Serialization version. + */ + private static final long serialVersionUID = -1632418723876261839L; + + /** + * Constructs a new date-time exception with the specified message. + * + * @param message the message to use for this exception, may be null + */ + public DateTimeException(String message) { + super(message); + } + + /** + * Constructs a new date-time exception with the specified message and cause. + * + * @param message the message to use for this exception, may be null + * @param cause the cause of the exception, may be null + */ + public DateTimeException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/make/tools/src/build/tools/tzdb/LocalDate.java b/make/tools/src/build/tools/tzdb/LocalDate.java new file mode 100644 index 0000000000000000000000000000000000000000..fedab6d31561e208565873c5e8c73fe702555f9e --- /dev/null +++ b/make/tools/src/build/tools/tzdb/LocalDate.java @@ -0,0 +1,363 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package build.tools.tzdb; + +import static build.tools.tzdb.Utils.*; +import static build.tools.tzdb.LocalTime.SECONDS_PER_DAY; +import static build.tools.tzdb.ChronoField.DAY_OF_MONTH; +import static build.tools.tzdb.ChronoField.MONTH_OF_YEAR; +import static build.tools.tzdb.ChronoField.YEAR; + +import java.util.Objects; + +/** + * A date without a time-zone in the ISO-8601 calendar system, + * such as {@code 2007-12-03}. + * + * @since 1.8 + */ +final class LocalDate { + + /** + * The minimum supported {@code LocalDate}, '-999999999-01-01'. + * This could be used by an application as a "far past" date. + */ + public static final LocalDate MIN = new LocalDate(YEAR_MIN_VALUE, 1, 1); + /** + * The maximum supported {@code LocalDate}, '+999999999-12-31'. + * This could be used by an application as a "far future" date. + */ + public static final LocalDate MAX = new LocalDate(YEAR_MAX_VALUE, 12, 31); + + /** + * The number of days in a 400 year cycle. + */ + private static final int DAYS_PER_CYCLE = 146097; + /** + * The number of days from year zero to year 1970. + * There are five 400 year cycles from year zero to 2000. + * There are 7 leap years from 1970 to 2000. + */ + static final long DAYS_0000_TO_1970 = (DAYS_PER_CYCLE * 5L) - (30L * 365L + 7L); + + /** + * The year. + */ + private final int year; + /** + * The month-of-year. + */ + private final short month; + /** + * The day-of-month. + */ + private final short day; + + /** + * Obtains an instance of {@code LocalDate} from a year, month and day. + *
+ * The day must be valid for the year and month, otherwise an exception will be thrown. + * + * @param year the year to represent, from MIN_YEAR to MAX_YEAR + * @param month the month-of-year to represent, from 1 (January) to 12 (December) + * @param dayOfMonth the day-of-month to represent, from 1 to 31 + * @return the local date, not null + * @throws DateTimeException if the value of any field is out of range + * @throws DateTimeException if the day-of-month is invalid for the month-year + */ + public static LocalDate of(int year, int month, int dayOfMonth) { + YEAR.checkValidValue(year); + MONTH_OF_YEAR.checkValidValue(month); + DAY_OF_MONTH.checkValidValue(dayOfMonth); + if (dayOfMonth > 28 && dayOfMonth > lengthOfMonth(month, isLeapYear(year))) { + if (dayOfMonth == 29) { + throw new DateTimeException("Invalid date 'February 29' as '" + year + "' is not a leap year"); + } else { + throw new DateTimeException("Invalid date '" + month + " " + dayOfMonth + "'"); + } + } + return new LocalDate(year, month, dayOfMonth); + } + + /** + * Constructor, previously validated. + * + * @param year the year to represent, from MIN_YEAR to MAX_YEAR + * @param month the month-of-year to represent, not null + * @param dayOfMonth the day-of-month to represent, valid for year-month, from 1 to 31 + */ + private LocalDate(int year, int month, int dayOfMonth) { + this.year = year; + this.month = (short) month; + this.day = (short) dayOfMonth; + } + + /** + * Gets the year field. + *
+ * This method returns the primitive {@code int} value for the year. + *
+ * The year returned by this method is proleptic as per {@code get(YEAR)}. + * To obtain the year-of-era, use {@code get(YEAR_OF_ERA}. + * + * @return the year, from MIN_YEAR to MAX_YEAR + */ + public int getYear() { + return year; + } + + /** + * Gets the month-of-year field as an int from 1 to 12. + * + * @return the month-of-year + */ + public int getMonth() { + return month; + } + + /** + * Gets the day-of-month field. + *
+ * This method returns the primitive {@code int} value for the day-of-month. + * + * @return the day-of-month, from 1 to 31 + */ + public int getDayOfMonth() { + return day; + } + + /** + * Gets the day-of-week field, which is an int from 1 to 7. + * + * @return the day-of-week + */ + public int getDayOfWeek() { + return (int)floorMod(toEpochDay() + 3, 7) + 1; + } + + /** + * Returns a copy of this {@code LocalDate} with the specified number of days added. + *
+ * This method adds the specified amount to the days field incrementing the + * month and year fields as necessary to ensure the result remains valid. + * The result is only invalid if the maximum/minimum year is exceeded. + *
+ * For example, 2008-12-31 plus one day would result in 2009-01-01. + *
+ * This instance is immutable and unaffected by this method call. + * + * @param daysToAdd the days to add, may be negative + * @return a {@code LocalDate} based on this date with the days added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public LocalDate plusDays(long daysToAdd) { + if (daysToAdd == 0) { + return this; + } + long mjDay = addExact(toEpochDay(), daysToAdd); + return LocalDate.ofEpochDay(mjDay); + } + + /** + * Returns a copy of this {@code LocalDate} with the specified number of days subtracted. + *
+ * This method subtracts the specified amount from the days field decrementing the + * month and year fields as necessary to ensure the result remains valid. + * The result is only invalid if the maximum/minimum year is exceeded. + *
+ * For example, 2009-01-01 minus one day would result in 2008-12-31. + *
+ * This instance is immutable and unaffected by this method call. + * + * @param daysToSubtract the days to subtract, may be negative + * @return a {@code LocalDate} based on this date with the days subtracted, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public LocalDate minusDays(long daysToSubtract) { + return (daysToSubtract == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-daysToSubtract)); + } + + /** + * Obtains an instance of {@code LocalDate} from the epoch day count. + *
+ * The Epoch Day count is a simple incrementing count of days + * where day 0 is 1970-01-01. Negative numbers represent earlier days. + * + * @param epochDay the Epoch Day to convert, based on the epoch 1970-01-01 + * @return the local date, not null + * @throws DateTimeException if the epoch days exceeds the supported date range + */ + public static LocalDate ofEpochDay(long epochDay) { + long zeroDay = epochDay + DAYS_0000_TO_1970; + // find the march-based year + zeroDay -= 60; // adjust to 0000-03-01 so leap day is at end of four year cycle + long adjust = 0; + if (zeroDay < 0) { + // adjust negative years to positive for calculation + long adjustCycles = (zeroDay + 1) / DAYS_PER_CYCLE - 1; + adjust = adjustCycles * 400; + zeroDay += -adjustCycles * DAYS_PER_CYCLE; + } + long yearEst = (400 * zeroDay + 591) / DAYS_PER_CYCLE; + long doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400); + if (doyEst < 0) { + // fix estimate + yearEst--; + doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400); + } + yearEst += adjust; // reset any negative year + int marchDoy0 = (int) doyEst; + + // convert march-based values back to january-based + int marchMonth0 = (marchDoy0 * 5 + 2) / 153; + int month = (marchMonth0 + 2) % 12 + 1; + int dom = marchDoy0 - (marchMonth0 * 306 + 5) / 10 + 1; + yearEst += marchMonth0 / 10; + + // check year now we are certain it is correct + int year = YEAR.checkValidValue((int)yearEst); + return new LocalDate(year, month, dom); + } + + public long toEpochDay() { + long y = year; + long m = month; + long total = 0; + total += 365 * y; + if (y >= 0) { + total += (y + 3) / 4 - (y + 99) / 100 + (y + 399) / 400; + } else { + total -= y / -4 - y / -100 + y / -400; + } + total += ((367 * m - 362) / 12); + total += day - 1; + if (m > 2) { + total--; + if (isLeapYear(year) == false) { + total--; + } + } + return total - DAYS_0000_TO_1970; + } + + /** + * Compares this date to another date. + *
+ * The comparison is primarily based on the date, from earliest to latest. + * It is "consistent with equals", as defined by {@link Comparable}. + *
+ * If all the dates being compared are instances of {@code LocalDate}, + * then the comparison will be entirely based on the date. + * If some dates being compared are in different chronologies, then the + * chronology is also considered, see {@link java.time.temporal.ChronoLocalDate#compareTo}. + * + * @param other the other date to compare to, not null + * @return the comparator value, negative if less, positive if greater + */ + public int compareTo(LocalDate otherDate) { + int cmp = (year - otherDate.year); + if (cmp == 0) { + cmp = (month - otherDate.month); + if (cmp == 0) { + cmp = (day - otherDate.day); + } + } + return cmp; + } + + /** + * Checks if this date is equal to another date. + *
+ * Compares this {@code LocalDate} with another ensuring that the date is the same. + *
+ * Only objects of type {@code LocalDate} are compared, other types return false. + * To compare the dates of two {@code TemporalAccessor} instances, including dates + * in two different chronologies, use {@link ChronoField#EPOCH_DAY} as a comparator. + * + * @param obj the object to check, null returns false + * @return true if this is equal to the other date + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof LocalDate) { + return compareTo((LocalDate) obj) == 0; + } + return false; + } + + /** + * A hash code for this date. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + int yearValue = year; + int monthValue = month; + int dayValue = day; + return (yearValue & 0xFFFFF800) ^ ((yearValue << 11) + (monthValue << 6) + (dayValue)); + } + +} diff --git a/make/tools/src/build/tools/tzdb/LocalDateTime.java b/make/tools/src/build/tools/tzdb/LocalDateTime.java new file mode 100644 index 0000000000000000000000000000000000000000..ced37b72613da44120d551067ccb317bd10f3cdb --- /dev/null +++ b/make/tools/src/build/tools/tzdb/LocalDateTime.java @@ -0,0 +1,427 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package build.tools.tzdb; + +import static build.tools.tzdb.Utils.*; +import static build.tools.tzdb.LocalTime.HOURS_PER_DAY; +import static build.tools.tzdb.LocalTime.MICROS_PER_DAY; +import static build.tools.tzdb.LocalTime.MILLIS_PER_DAY; +import static build.tools.tzdb.LocalTime.MINUTES_PER_DAY; +import static build.tools.tzdb.LocalTime.SECONDS_PER_DAY; +import static build.tools.tzdb.LocalTime.SECONDS_PER_MINUTE; +import static build.tools.tzdb.LocalTime.SECONDS_PER_HOUR; + +import java.util.Objects; + +/** + * A date-time without a time-zone in the ISO-8601 calendar system, + * such as {@code 2007-12-03T10:15:30}. + * + * @since 1.8 + */ +final class LocalDateTime { + + /** + * The minimum supported {@code LocalDateTime}, '-999999999-01-01T00:00:00'. + * This is the local date-time of midnight at the start of the minimum date. + * This combines {@link LocalDate#MIN} and {@link LocalTime#MIN}. + * This could be used by an application as a "far past" date-time. + */ + public static final LocalDateTime MIN = LocalDateTime.of(LocalDate.MIN, LocalTime.MIN); + /** + * The maximum supported {@code LocalDateTime}, '+999999999-12-31T23:59:59.999999999'. + * This is the local date-time just before midnight at the end of the maximum date. + * This combines {@link LocalDate#MAX} and {@link LocalTime#MAX}. + * This could be used by an application as a "far future" date-time. + */ + public static final LocalDateTime MAX = LocalDateTime.of(LocalDate.MAX, LocalTime.MAX); + + /** + * The date part. + */ + private final LocalDate date; + /** + * The time part. + */ + private final LocalTime time; + + /** + * Obtains an instance of {@code LocalDateTime} from year, month, + * day, hour and minute, setting the second and nanosecond to zero. + *
+ * The day must be valid for the year and month, otherwise an exception will be thrown. + * The second and nanosecond fields will be set to zero. + * + * @param year the year to represent, from MIN_YEAR to MAX_YEAR + * @param month the month-of-year to represent, from 1 (January) to 12 (December) + * @param dayOfMonth the day-of-month to represent, from 1 to 31 + * @param hour the hour-of-day to represent, from 0 to 23 + * @param minute the minute-of-hour to represent, from 0 to 59 + * @return the local date-time, not null + * @throws DateTimeException if the value of any field is out of range + * @throws DateTimeException if the day-of-month is invalid for the month-year + */ + public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute) { + LocalDate date = LocalDate.of(year, month, dayOfMonth); + LocalTime time = LocalTime.of(hour, minute); + return new LocalDateTime(date, time); + } + + /** + * Obtains an instance of {@code LocalDateTime} from a date and time. + * + * @param date the local date, not null + * @param time the local time, not null + * @return the local date-time, not null + */ + public static LocalDateTime of(LocalDate date, LocalTime time) { + Objects.requireNonNull(date, "date"); + Objects.requireNonNull(time, "time"); + return new LocalDateTime(date, time); + } + + /** + * Obtains an instance of {@code LocalDateTime} using seconds from the + * epoch of 1970-01-01T00:00:00Z. + *
+ * This allows the {@link ChronoField#INSTANT_SECONDS epoch-second} field + * to be converted to a local date-time. This is primarily intended for + * low-level conversions rather than general application usage. + * + * @param epochSecond the number of seconds from the epoch of 1970-01-01T00:00:00Z + * @param nanoOfSecond the nanosecond within the second, from 0 to 999,999,999 + * @param offset the zone offset, not null + * @return the local date-time, not null + * @throws DateTimeException if the result exceeds the supported range + */ + public static LocalDateTime ofEpochSecond(long epochSecond, int nanoOfSecond, ZoneOffset offset) { + Objects.requireNonNull(offset, "offset"); + long localSecond = epochSecond + offset.getTotalSeconds(); // overflow caught later + long localEpochDay = floorDiv(localSecond, SECONDS_PER_DAY); + int secsOfDay = (int)floorMod(localSecond, SECONDS_PER_DAY); + LocalDate date = LocalDate.ofEpochDay(localEpochDay); + LocalTime time = LocalTime.ofSecondOfDay(secsOfDay); // ignore nano + return new LocalDateTime(date, time); + } + + /** + * Constructor. + * + * @param date the date part of the date-time, validated not null + * @param time the time part of the date-time, validated not null + */ + private LocalDateTime(LocalDate date, LocalTime time) { + this.date = date; + this.time = time; + } + + /** + * Returns a copy of this date-time with the new date and time, checking + * to see if a new object is in fact required. + * + * @param newDate the date of the new date-time, not null + * @param newTime the time of the new date-time, not null + * @return the date-time, not null + */ + private LocalDateTime with(LocalDate newDate, LocalTime newTime) { + if (date == newDate && time == newTime) { + return this; + } + return new LocalDateTime(newDate, newTime); + } + + /** + * Gets the {@code LocalDate} part of this date-time. + *
+ * This returns a {@code LocalDate} with the same year, month and day + * as this date-time. + * + * @return the date part of this date-time, not null + */ + public LocalDate getDate() { + return date; + } + + /** + * Gets the year field. + *
+ * This method returns the primitive {@code int} value for the year. + *
+ * The year returned by this method is proleptic as per {@code get(YEAR)}. + * To obtain the year-of-era, use {@code get(YEAR_OF_ERA}. + * + * @return the year, from MIN_YEAR to MAX_YEAR + */ + public int getYear() { + return date.getYear(); + } + + /** + * Gets the month-of-year field as an int from 1 to 12. + * + * @return the month-of-year + */ + public int getMonth() { + return date.getMonth(); + } + + /** + * Gets the day-of-month field. + *
+ * This method returns the primitive {@code int} value for the day-of-month. + * + * @return the day-of-month, from 1 to 31 + */ + public int getDayOfMonth() { + return date.getDayOfMonth(); + } + + /** + * Gets the day-of-week field, which is an integer from 1 to 7. + * + * @return the day-of-week, from 1 to 7 + */ + public int getDayOfWeek() { + return date.getDayOfWeek(); + } + + /** + * Gets the {@code LocalTime} part of this date-time. + *
+ * This returns a {@code LocalTime} with the same hour, minute, second and + * nanosecond as this date-time. + * + * @return the time part of this date-time, not null + */ + public LocalTime getTime() { + return time; + } + + /** + * Gets the hour-of-day field. + * + * @return the hour-of-day, from 0 to 23 + */ + public int getHour() { + return time.getHour(); + } + + /** + * Gets the minute-of-hour field. + * + * @return the minute-of-hour, from 0 to 59 + */ + public int getMinute() { + return time.getMinute(); + } + + /** + * Gets the second-of-minute field. + * + * @return the second-of-minute, from 0 to 59 + */ + public int getSecond() { + return time.getSecond(); + } + + /** + * Converts this date-time to the number of seconds from the epoch + * of 1970-01-01T00:00:00Z. + *
+ * This combines this local date-time and the specified offset to calculate the + * epoch-second value, which is the number of elapsed seconds from 1970-01-01T00:00:00Z. + * Instants on the time-line after the epoch are positive, earlier are negative. + *
+ * This default implementation calculates from the epoch-day of the date and the + * second-of-day of the time. + * + * @param offset the offset to use for the conversion, not null + * @return the number of seconds from the epoch of 1970-01-01T00:00:00Z + */ + public long toEpochSecond(ZoneOffset offset) { + Objects.requireNonNull(offset, "offset"); + long epochDay = getDate().toEpochDay(); + long secs = epochDay * 86400 + getTime().toSecondOfDay(); + secs -= offset.getTotalSeconds(); + return secs; + } + + /** + * Returns a copy of this {@code LocalDateTime} with the specified period in days added. + *
+ * This method adds the specified amount to the days field incrementing the + * month and year fields as necessary to ensure the result remains valid. + * The result is only invalid if the maximum/minimum year is exceeded. + *
+ * For example, 2008-12-31 plus one day would result in 2009-01-01. + *
+ * This instance is immutable and unaffected by this method call. + * + * @param days the days to add, may be negative + * @return a {@code LocalDateTime} based on this date-time with the days added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public LocalDateTime plusDays(long days) { + LocalDate newDate = date.plusDays(days); + return with(newDate, time); + } + + /** + * Returns a copy of this {@code LocalDateTime} with the specified period in seconds added. + *
+ * This instance is immutable and unaffected by this method call. + * + * @param seconds the seconds to add, may be negative + * @return a {@code LocalDateTime} based on this date-time with the seconds added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public LocalDateTime plusSeconds(long seconds) { + return plusWithOverflow(date, 0, 0, seconds, 1); + } + + /** + * Returns a copy of this {@code LocalDateTime} with the specified period added. + *
+ * This instance is immutable and unaffected by this method call. + * + * @param newDate the new date to base the calculation on, not null + * @param hours the hours to add, may be negative + * @param minutes the minutes to add, may be negative + * @param seconds the seconds to add, may be negative + * @param nanos the nanos to add, may be negative + * @param sign the sign to determine add or subtract + * @return the combined result, not null + */ + private LocalDateTime plusWithOverflow(LocalDate newDate, long hours, long minutes, long seconds, int sign) { + if ((hours | minutes | seconds) == 0) { + return with(newDate, time); + } + long totDays = seconds / SECONDS_PER_DAY + // max/24*60*60 + minutes / MINUTES_PER_DAY + // max/24*60 + hours / HOURS_PER_DAY; // max/24 + totDays *= sign; // total max*0.4237... + long totSecs = (seconds % SECONDS_PER_DAY) + + (minutes % MINUTES_PER_DAY) * SECONDS_PER_MINUTE + + (hours % HOURS_PER_DAY) * SECONDS_PER_HOUR; + long curSoD = time.toSecondOfDay(); + totSecs = totSecs * sign + curSoD; // total 432000000000000 + totDays += floorDiv(totSecs, SECONDS_PER_DAY); + + int newSoD = (int)floorMod(totSecs, SECONDS_PER_DAY); + LocalTime newTime = (newSoD == curSoD ? time : LocalTime.ofSecondOfDay(newSoD)); + return with(newDate.plusDays(totDays), newTime); + } + + /** + * Compares this date-time to another date-time. + *
+ * The comparison is primarily based on the date-time, from earliest to latest. + * It is "consistent with equals", as defined by {@link Comparable}. + *
+ * If all the date-times being compared are instances of {@code LocalDateTime}, + * then the comparison will be entirely based on the date-time. + * If some dates being compared are in different chronologies, then the + * chronology is also considered, see {@link ChronoLocalDateTime#compareTo}. + * + * @param other the other date-time to compare to, not null + * @return the comparator value, negative if less, positive if greater + */ + public int compareTo(LocalDateTime other) { + int cmp = date.compareTo(other.getDate()); + if (cmp == 0) { + cmp = time.compareTo(other.getTime()); + } + return cmp; + } + + /** + * Checks if this date-time is equal to another date-time. + *
+ * Compares this {@code LocalDateTime} with another ensuring that the date-time is the same. + * Only objects of type {@code LocalDateTime} are compared, other types return false. + * + * @param obj the object to check, null returns false + * @return true if this is equal to the other date-time + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof LocalDateTime) { + LocalDateTime other = (LocalDateTime) obj; + return date.equals(other.date) && time.equals(other.time); + } + return false; + } + + /** + * A hash code for this date-time. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + return date.hashCode() ^ time.hashCode(); + } + +} diff --git a/make/tools/src/build/tools/tzdb/LocalTime.java b/make/tools/src/build/tools/tzdb/LocalTime.java new file mode 100644 index 0000000000000000000000000000000000000000..0fc318689446ae4141d12162ffd63489ffdffb50 --- /dev/null +++ b/make/tools/src/build/tools/tzdb/LocalTime.java @@ -0,0 +1,388 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package build.tools.tzdb; + +import static build.tools.tzdb.ChronoField.HOUR_OF_DAY; +import static build.tools.tzdb.ChronoField.MINUTE_OF_HOUR; +import static build.tools.tzdb.ChronoField.SECOND_OF_MINUTE; +import static build.tools.tzdb.ChronoField.SECOND_OF_DAY; + +import java.util.Objects; + +/** + * A time without time-zone in the ISO-8601 calendar system, + * such as {@code 10:15:30}. + * + */ +final class LocalTime { + + /** + * The minimum supported {@code LocalTime}, '00:00'. + * This is the time of midnight at the start of the day. + */ + public static final LocalTime MIN; + /** + * The minimum supported {@code LocalTime}, '23:59:59.999999999'. + * This is the time just before midnight at the end of the day. + */ + public static final LocalTime MAX; + /** + * The time of midnight at the start of the day, '00:00'. + */ + public static final LocalTime MIDNIGHT; + /** + * The time of noon in the middle of the day, '12:00'. + */ + public static final LocalTime NOON; + /** + * Constants for the local time of each hour. + */ + private static final LocalTime[] HOURS = new LocalTime[24]; + static { + for (int i = 0; i < HOURS.length; i++) { + HOURS[i] = new LocalTime(i, 0, 0); + } + MIDNIGHT = HOURS[0]; + NOON = HOURS[12]; + MIN = HOURS[0]; + MAX = new LocalTime(23, 59, 59); + } + + /** + * Hours per day. + */ + static final int HOURS_PER_DAY = 24; + /** + * Minutes per hour. + */ + static final int MINUTES_PER_HOUR = 60; + /** + * Minutes per day. + */ + static final int MINUTES_PER_DAY = MINUTES_PER_HOUR * HOURS_PER_DAY; + /** + * Seconds per minute. + */ + static final int SECONDS_PER_MINUTE = 60; + /** + * Seconds per hour. + */ + static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR; + /** + * Seconds per day. + */ + static final int SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY; + /** + * Milliseconds per day. + */ + static final long MILLIS_PER_DAY = SECONDS_PER_DAY * 1000L; + /** + * Microseconds per day. + */ + static final long MICROS_PER_DAY = SECONDS_PER_DAY * 1000_000L; + + /** + * The hour. + */ + private final byte hour; + /** + * The minute. + */ + private final byte minute; + /** + * The second. + */ + private final byte second; + + /** + * Obtains an instance of {@code LocalTime} from an hour and minute. + *
+ * The second and nanosecond fields will be set to zero by this factory method. + *
+ * This factory may return a cached value, but applications must not rely on this. + * + * @param hour the hour-of-day to represent, from 0 to 23 + * @param minute the minute-of-hour to represent, from 0 to 59 + * @return the local time, not null + * @throws DateTimeException if the value of any field is out of range + */ + public static LocalTime of(int hour, int minute) { + HOUR_OF_DAY.checkValidValue(hour); + if (minute == 0) { + return HOURS[hour]; // for performance + } + MINUTE_OF_HOUR.checkValidValue(minute); + return new LocalTime(hour, minute, 0); + } + + /** + * Obtains an instance of {@code LocalTime} from an hour, minute and second. + *
+ * The nanosecond field will be set to zero by this factory method. + *
+ * This factory may return a cached value, but applications must not rely on this. + * + * @param hour the hour-of-day to represent, from 0 to 23 + * @param minute the minute-of-hour to represent, from 0 to 59 + * @param second the second-of-minute to represent, from 0 to 59 + * @return the local time, not null + * @throws DateTimeException if the value of any field is out of range + */ + public static LocalTime of(int hour, int minute, int second) { + HOUR_OF_DAY.checkValidValue(hour); + if ((minute | second) == 0) { + return HOURS[hour]; // for performance + } + MINUTE_OF_HOUR.checkValidValue(minute); + SECOND_OF_MINUTE.checkValidValue(second); + return new LocalTime(hour, minute, second); + } + + /** + * Obtains an instance of {@code LocalTime} from a second-of-day value. + *
+ * This factory may return a cached value, but applications must not rely on this. + * + * @param secondOfDay the second-of-day, from {@code 0} to {@code 24 * 60 * 60 - 1} + * @return the local time, not null + * @throws DateTimeException if the second-of-day value is invalid + */ + public static LocalTime ofSecondOfDay(int secondOfDay) { + SECOND_OF_DAY.checkValidValue(secondOfDay); + int hours = secondOfDay / SECONDS_PER_HOUR; + secondOfDay -= hours * SECONDS_PER_HOUR; + int minutes = secondOfDay / SECONDS_PER_MINUTE; + secondOfDay -= minutes * SECONDS_PER_MINUTE; + return create(hours, minutes, secondOfDay); + } + + + /** + * Creates a local time from the hour, minute, second and nanosecond fields. + *
+ * This factory may return a cached value, but applications must not rely on this. + * + * @param hour the hour-of-day to represent, validated from 0 to 23 + * @param minute the minute-of-hour to represent, validated from 0 to 59 + * @param second the second-of-minute to represent, validated from 0 to 59 + * @return the local time, not null + */ + private static LocalTime create(int hour, int minute, int second) { + if ((minute | second) == 0) { + return HOURS[hour]; + } + return new LocalTime(hour, minute, second); + } + + /** + * Constructor, previously validated. + * + * @param hour the hour-of-day to represent, validated from 0 to 23 + * @param minute the minute-of-hour to represent, validated from 0 to 59 + * @param second the second-of-minute to represent, validated from 0 to 59 + */ + private LocalTime(int hour, int minute, int second) { + this.hour = (byte) hour; + this.minute = (byte) minute; + this.second = (byte) second; + } + + /** + * Gets the hour-of-day field. + * + * @return the hour-of-day, from 0 to 23 + */ + public int getHour() { + return hour; + } + + /** + * Gets the minute-of-hour field. + * + * @return the minute-of-hour, from 0 to 59 + */ + public int getMinute() { + return minute; + } + + /** + * Gets the second-of-minute field. + * + * @return the second-of-minute, from 0 to 59 + */ + public int getSecond() { + return second; + } + + /** + * Returns a copy of this {@code LocalTime} with the specified period in seconds added. + *
+ * This adds the specified number of seconds to this time, returning a new time. + * The calculation wraps around midnight. + *
+ * This instance is immutable and unaffected by this method call. + * + * @param secondstoAdd the seconds to add, may be negative + * @return a {@code LocalTime} based on this time with the seconds added, not null + */ + public LocalTime plusSeconds(long secondstoAdd) { + if (secondstoAdd == 0) { + return this; + } + int sofd = hour * SECONDS_PER_HOUR + + minute * SECONDS_PER_MINUTE + second; + int newSofd = ((int) (secondstoAdd % SECONDS_PER_DAY) + sofd + SECONDS_PER_DAY) % SECONDS_PER_DAY; + if (sofd == newSofd) { + return this; + } + int newHour = newSofd / SECONDS_PER_HOUR; + int newMinute = (newSofd / SECONDS_PER_MINUTE) % MINUTES_PER_HOUR; + int newSecond = newSofd % SECONDS_PER_MINUTE; + return create(newHour, newMinute, newSecond); + } + + /** + * Returns a copy of this {@code LocalTime} with the specified period in seconds subtracted. + *
+ * This subtracts the specified number of seconds from this time, returning a new time. + * The calculation wraps around midnight. + *
+ * This instance is immutable and unaffected by this method call. + * + * @param secondsToSubtract the seconds to subtract, may be negative + * @return a {@code LocalTime} based on this time with the seconds subtracted, not null + */ + public LocalTime minusSeconds(long secondsToSubtract) { + return plusSeconds(-(secondsToSubtract % SECONDS_PER_DAY)); + } + + /** + * Extracts the time as seconds of day, + * from {@code 0} to {@code 24 * 60 * 60 - 1}. + * + * @return the second-of-day equivalent to this time + */ + public int toSecondOfDay() { + int total = hour * SECONDS_PER_HOUR; + total += minute * SECONDS_PER_MINUTE; + total += second; + return total; + } + + /** + * Compares this {@code LocalTime} to another time. + *
+ * The comparison is based on the time-line position of the local times within a day. + * It is "consistent with equals", as defined by {@link Comparable}. + * + * @param other the other time to compare to, not null + * @return the comparator value, negative if less, positive if greater + * @throws NullPointerException if {@code other} is null + */ + public int compareTo(LocalTime other) { + int cmp = Integer.compare(hour, other.hour); + if (cmp == 0) { + cmp = Integer.compare(minute, other.minute); + if (cmp == 0) { + cmp = Integer.compare(second, other.second); + } + } + return cmp; + } + + /** + * Checks if this time is equal to another time. + *
+ * The comparison is based on the time-line position of the time within a day. + *
+ * Only objects of type {@code LocalTime} are compared, other types return false. + * To compare the date of two {@code TemporalAccessor} instances, use + * {@link ChronoField#NANO_OF_DAY} as a comparator. + * + * @param obj the object to check, null returns false + * @return true if this is equal to the other time + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof LocalTime) { + LocalTime other = (LocalTime) obj; + return hour == other.hour && minute == other.minute && + second == other.second; + } + return false; + } + + /** + * A hash code for this time. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + long sod = toSecondOfDay(); + return (int) (sod ^ (sod >>> 32)); + } + +} diff --git a/make/tools/src/build/tools/tzdb/TimeDefinition.java b/make/tools/src/build/tools/tzdb/TimeDefinition.java new file mode 100644 index 0000000000000000000000000000000000000000..8a5853db3d7d6db7451ef99520af486a2347f915 --- /dev/null +++ b/make/tools/src/build/tools/tzdb/TimeDefinition.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package build.tools.tzdb; + +import java.util.Objects; + +/** + * A definition of the way a local time can be converted to the actual + * transition date-time. + *
+ * Time zone rules are expressed in one of three ways: + *
+ */ +public enum TimeDefinition { + /** The local date-time is expressed in terms of the UTC offset. */ + UTC, + /** The local date-time is expressed in terms of the wall offset. */ + WALL, + /** The local date-time is expressed in terms of the standard offset. */ + STANDARD; + + /** + * Converts the specified local date-time to the local date-time actually + * seen on a wall clock. + *
+ * This method converts using the type of this enum. + * The output is defined relative to the 'before' offset of the transition. + *
+ * The UTC type uses the UTC offset.
+ * The STANDARD type uses the standard offset.
+ * The WALL type returns the input date-time.
+ * The result is intended for use with the wall-offset.
+ *
+ * @param dateTime the local date-time, not null
+ * @param standardOffset the standard offset, not null
+ * @param wallOffset the wall offset, not null
+ * @return the date-time relative to the wall/before offset, not null
+ */
+ public LocalDateTime createDateTime(LocalDateTime dateTime, ZoneOffset standardOffset, ZoneOffset wallOffset) {
+ switch (this) {
+ case UTC: {
+ int difference = wallOffset.getTotalSeconds() - ZoneOffset.UTC.getTotalSeconds();
+ return dateTime.plusSeconds(difference);
+ }
+ case STANDARD: {
+ int difference = wallOffset.getTotalSeconds() - standardOffset.getTotalSeconds();
+ return dateTime.plusSeconds(difference);
+ }
+ default: // WALL
+ return dateTime;
+ }
+ }
+
+}
diff --git a/make/tools/src/build/tools/tzdb/TzdbZoneRulesCompiler.java b/make/tools/src/build/tools/tzdb/TzdbZoneRulesCompiler.java
new file mode 100644
index 0000000000000000000000000000000000000000..7b32ccf267a3a617d5cf087ad2262b4f6207d429
--- /dev/null
+++ b/make/tools/src/build/tools/tzdb/TzdbZoneRulesCompiler.java
@@ -0,0 +1,876 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package build.tools.tzdb;
+
+import static build.tools.tzdb.Utils.*;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.text.ParsePosition;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.StringTokenizer;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.jar.JarOutputStream;
+import java.util.zip.ZipEntry;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A builder that can read the TZDB time-zone files and build {@code ZoneRules} instances.
+ *
+ * @since 1.8
+ */
+public final class TzdbZoneRulesCompiler {
+
+ private static final Matcher YEAR = Pattern.compile("(?i)(?
+ * 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
+ * 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
+ * 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:
+ *
+ * Note that ± means either the plus or minus symbol.
+ *
+ * The ID of the returned offset will be normalized to one of the formats
+ * described by {@link #getId()}.
+ *
+ * The maximum supported range is from +18:00 to -18:00 inclusive.
+ *
+ * @param offsetId the offset ID, not null
+ * @return the zone-offset, not null
+ * @throws DateTimeException if the offset ID is invalid
+ */
+ @SuppressWarnings("fallthrough")
+ public static ZoneOffset of(String offsetId) {
+ Objects.requireNonNull(offsetId, "offsetId");
+ // "Z" is always in the cache
+ ZoneOffset offset = ID_CACHE.get(offsetId);
+ if (offset != null) {
+ return offset;
+ }
+
+ // parse - +h, +hh, +hhmm, +hh:mm, +hhmmss, +hh:mm:ss
+ final int hours, minutes, seconds;
+ switch (offsetId.length()) {
+ case 2:
+ offsetId = offsetId.charAt(0) + "0" + offsetId.charAt(1); // fallthru
+ case 3:
+ hours = parseNumber(offsetId, 1, false);
+ minutes = 0;
+ seconds = 0;
+ break;
+ case 5:
+ hours = parseNumber(offsetId, 1, false);
+ minutes = parseNumber(offsetId, 3, false);
+ seconds = 0;
+ break;
+ case 6:
+ hours = parseNumber(offsetId, 1, false);
+ minutes = parseNumber(offsetId, 4, true);
+ seconds = 0;
+ break;
+ case 7:
+ hours = parseNumber(offsetId, 1, false);
+ minutes = parseNumber(offsetId, 3, false);
+ seconds = parseNumber(offsetId, 5, false);
+ break;
+ case 9:
+ hours = parseNumber(offsetId, 1, false);
+ minutes = parseNumber(offsetId, 4, true);
+ seconds = parseNumber(offsetId, 7, true);
+ break;
+ default:
+ throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid");
+ }
+ char first = offsetId.charAt(0);
+ if (first != '+' && first != '-') {
+ throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid: Plus/minus not found when expected");
+ }
+ if (first == '-') {
+ return ofHoursMinutesSeconds(-hours, -minutes, -seconds);
+ } else {
+ return ofHoursMinutesSeconds(hours, minutes, seconds);
+ }
+ }
+
+ /**
+ * Parse a two digit zero-prefixed number.
+ *
+ * @param offsetId the offset ID, not null
+ * @param pos the position to parse, valid
+ * @param precededByColon should this number be prefixed by a precededByColon
+ * @return the parsed number, from 0 to 99
+ */
+ private static int parseNumber(CharSequence offsetId, int pos, boolean precededByColon) {
+ if (precededByColon && offsetId.charAt(pos - 1) != ':') {
+ throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid: Colon not found when expected");
+ }
+ char ch1 = offsetId.charAt(pos);
+ char ch2 = offsetId.charAt(pos + 1);
+ if (ch1 < '0' || ch1 > '9' || ch2 < '0' || ch2 > '9') {
+ throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid: Non numeric characters found");
+ }
+ return (ch1 - 48) * 10 + (ch2 - 48);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code ZoneOffset} using an offset in hours.
+ *
+ * @param hours the time-zone offset in hours, from -18 to +18
+ * @return the zone-offset, not null
+ * @throws DateTimeException if the offset is not in the required range
+ */
+ public static ZoneOffset ofHours(int hours) {
+ return ofHoursMinutesSeconds(hours, 0, 0);
+ }
+
+ /**
+ * Obtains an instance of {@code ZoneOffset} using an offset in
+ * hours and minutes.
+ *
+ * The sign of the hours and minutes components must match.
+ * Thus, if the hours is negative, the minutes must be negative or zero.
+ * If the hours is zero, the minutes may be positive, negative or zero.
+ *
+ * @param hours the time-zone offset in hours, from -18 to +18
+ * @param minutes the time-zone offset in minutes, from 0 to ±59, sign matches hours
+ * @return the zone-offset, not null
+ * @throws DateTimeException if the offset is not in the required range
+ */
+ public static ZoneOffset ofHoursMinutes(int hours, int minutes) {
+ return ofHoursMinutesSeconds(hours, minutes, 0);
+ }
+
+ /**
+ * Obtains an instance of {@code ZoneOffset} using an offset in
+ * hours, minutes and seconds.
+ *
+ * The sign of the hours, minutes and seconds components must match.
+ * Thus, if the hours is negative, the minutes and seconds must be negative or zero.
+ *
+ * @param hours the time-zone offset in hours, from -18 to +18
+ * @param minutes the time-zone offset in minutes, from 0 to ±59, sign matches hours and seconds
+ * @param seconds the time-zone offset in seconds, from 0 to ±59, sign matches hours and minutes
+ * @return the zone-offset, not null
+ * @throws DateTimeException if the offset is not in the required range
+ */
+ public static ZoneOffset ofHoursMinutesSeconds(int hours, int minutes, int seconds) {
+ validate(hours, minutes, seconds);
+ int totalSeconds = totalSeconds(hours, minutes, seconds);
+ return ofTotalSeconds(totalSeconds);
+ }
+
+ /**
+ * Validates the offset fields.
+ *
+ * @param hours the time-zone offset in hours, from -18 to +18
+ * @param minutes the time-zone offset in minutes, from 0 to ±59
+ * @param seconds the time-zone offset in seconds, from 0 to ±59
+ * @throws DateTimeException if the offset is not in the required range
+ */
+ private static void validate(int hours, int minutes, int seconds) {
+ if (hours < -18 || hours > 18) {
+ throw new DateTimeException("Zone offset hours not in valid range: value " + hours +
+ " is not in the range -18 to 18");
+ }
+ if (hours > 0) {
+ if (minutes < 0 || seconds < 0) {
+ throw new DateTimeException("Zone offset minutes and seconds must be positive because hours is positive");
+ }
+ } else if (hours < 0) {
+ if (minutes > 0 || seconds > 0) {
+ throw new DateTimeException("Zone offset minutes and seconds must be negative because hours is negative");
+ }
+ } else if ((minutes > 0 && seconds < 0) || (minutes < 0 && seconds > 0)) {
+ throw new DateTimeException("Zone offset minutes and seconds must have the same sign");
+ }
+ if (Math.abs(minutes) > 59) {
+ throw new DateTimeException("Zone offset minutes not in valid range: abs(value) " +
+ Math.abs(minutes) + " is not in the range 0 to 59");
+ }
+ if (Math.abs(seconds) > 59) {
+ throw new DateTimeException("Zone offset seconds not in valid range: abs(value) " +
+ Math.abs(seconds) + " is not in the range 0 to 59");
+ }
+ if (Math.abs(hours) == 18 && (Math.abs(minutes) > 0 || Math.abs(seconds) > 0)) {
+ throw new DateTimeException("Zone offset not in valid range: -18:00 to +18:00");
+ }
+ }
+
+ /**
+ * Calculates the total offset in seconds.
+ *
+ * @param hours the time-zone offset in hours, from -18 to +18
+ * @param minutes the time-zone offset in minutes, from 0 to ±59, sign matches hours and seconds
+ * @param seconds the time-zone offset in seconds, from 0 to ±59, sign matches hours and minutes
+ * @return the total in seconds
+ */
+ private static int totalSeconds(int hours, int minutes, int seconds) {
+ return hours * SECONDS_PER_HOUR + minutes * SECONDS_PER_MINUTE + seconds;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code ZoneOffset} specifying the total offset in seconds
+ *
+ * The offset must be in the range {@code -18:00} to {@code +18:00}, which corresponds to -64800 to +64800.
+ *
+ * @param totalSeconds the total time-zone offset in seconds, from -64800 to +64800
+ * @return the ZoneOffset, not null
+ * @throws DateTimeException if the offset is not in the required range
+ */
+ public static ZoneOffset ofTotalSeconds(int totalSeconds) {
+ if (Math.abs(totalSeconds) > MAX_SECONDS) {
+ throw new DateTimeException("Zone offset not in valid range: -18:00 to +18:00");
+ }
+ if (totalSeconds % (15 * SECONDS_PER_MINUTE) == 0) {
+ Integer totalSecs = totalSeconds;
+ ZoneOffset result = SECONDS_CACHE.get(totalSecs);
+ if (result == null) {
+ result = new ZoneOffset(totalSeconds);
+ SECONDS_CACHE.putIfAbsent(totalSecs, result);
+ result = SECONDS_CACHE.get(totalSecs);
+ ID_CACHE.putIfAbsent(result.getId(), result);
+ }
+ return result;
+ } else {
+ return new ZoneOffset(totalSeconds);
+ }
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param totalSeconds the total time-zone offset in seconds, from -64800 to +64800
+ */
+ private ZoneOffset(int totalSeconds) {
+ super();
+ this.totalSeconds = totalSeconds;
+ id = buildId(totalSeconds);
+ }
+
+ private static String buildId(int totalSeconds) {
+ if (totalSeconds == 0) {
+ return "Z";
+ } else {
+ int absTotalSeconds = Math.abs(totalSeconds);
+ StringBuilder buf = new StringBuilder();
+ int absHours = absTotalSeconds / SECONDS_PER_HOUR;
+ int absMinutes = (absTotalSeconds / SECONDS_PER_MINUTE) % MINUTES_PER_HOUR;
+ buf.append(totalSeconds < 0 ? "-" : "+")
+ .append(absHours < 10 ? "0" : "").append(absHours)
+ .append(absMinutes < 10 ? ":0" : ":").append(absMinutes);
+ int absSeconds = absTotalSeconds % SECONDS_PER_MINUTE;
+ if (absSeconds != 0) {
+ buf.append(absSeconds < 10 ? ":0" : ":").append(absSeconds);
+ }
+ return buf.toString();
+ }
+ }
+
+ /**
+ * Gets the total zone offset in seconds.
+ *
+ * This is the primary way to access the offset amount.
+ * It returns the total of the hours, minutes and seconds fields as a
+ * single offset that can be added to a time.
+ *
+ * @return the total zone offset amount in seconds
+ */
+ public int getTotalSeconds() {
+ return totalSeconds;
+ }
+
+ /**
+ * Gets the normalized zone offset ID.
+ *
+ * The ID is minor variation to the standard ISO-8601 formatted string
+ * for the offset. There are three formats:
+ *
+ *
+ * @return the zone offset ID, not null
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Compares this offset to another offset in descending order.
+ *
+ * The offsets are compared in the order that they occur for the same time
+ * of day around the world. Thus, an offset of {@code +10:00} comes before an
+ * offset of {@code +09:00} and so on down to {@code -18:00}.
+ *
+ * The comparison is "consistent with equals", as defined by {@link Comparable}.
+ *
+ * @param other the other date to compare to, not null
+ * @return the comparator value, negative if less, postive if greater
+ * @throws NullPointerException if {@code other} is null
+ */
+ @Override
+ public int compareTo(ZoneOffset other) {
+ return other.totalSeconds - totalSeconds;
+ }
+
+ /**
+ * Checks if this offset is equal to another offset.
+ *
+ * The comparison is based on the amount of the offset in seconds.
+ * This is equivalent to a comparison by ID.
+ *
+ * @param obj the object to check, null returns false
+ * @return true if this is equal to the other offset
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof ZoneOffset) {
+ return totalSeconds == ((ZoneOffset) obj).totalSeconds;
+ }
+ return false;
+ }
+
+ /**
+ * A hash code for this offset.
+ *
+ * @return a suitable hash code
+ */
+ @Override
+ public int hashCode() {
+ return totalSeconds;
+ }
+
+ /**
+ * Outputs this offset as a {@code String}, using the normalized ID.
+ *
+ * @return a string representation of this offset, not null
+ */
+ @Override
+ public String toString() {
+ return id;
+ }
+
+}
diff --git a/make/tools/src/build/tools/tzdb/ZoneOffsetTransition.java b/make/tools/src/build/tools/tzdb/ZoneOffsetTransition.java
new file mode 100644
index 0000000000000000000000000000000000000000..167b5f112dee1da440b9eddc64a75787768df432
--- /dev/null
+++ b/make/tools/src/build/tools/tzdb/ZoneOffsetTransition.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package build.tools.tzdb;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A transition between two offsets caused by a discontinuity in the local time-line.
+ *
+ * @since 1.8
+ */
+final class ZoneOffsetTransition implements Comparable
+ * This is the date-time where the discontinuity begins expressed with the 'before' offset.
+ * At this instant, the 'after' offset is actually used, therefore the combination of this
+ * date-time and the 'before' offset will never occur.
+ *
+ * The combination of the 'before' date-time and offset represents the same instant
+ * as the 'after' date-time and offset.
+ *
+ * @return the transition date-time expressed with the before offset, not null
+ */
+ public LocalDateTime getDateTimeBefore() {
+ return transition;
+ }
+
+ /**
+ * Gets the local transition date-time, as would be expressed with the 'after' offset.
+ *
+ * This is the first date-time after the discontinuity, when the new offset applies.
+ *
+ * The combination of the 'before' date-time and offset represents the same instant
+ * as the 'after' date-time and offset.
+ *
+ * @return the transition date-time expressed with the after offset, not null
+ */
+ public LocalDateTime getDateTimeAfter() {
+ return transition.plusSeconds(getDurationSeconds());
+ }
+
+ /**
+ * Gets the offset before the transition.
+ *
+ * This is the offset in use before the instant of the transition.
+ *
+ * @return the offset before the transition, not null
+ */
+ public ZoneOffset getOffsetBefore() {
+ return offsetBefore;
+ }
+
+ /**
+ * Gets the offset after the transition.
+ *
+ * This is the offset in use on and after the instant of the transition.
+ *
+ * @return the offset after the transition, not null
+ */
+ public ZoneOffset getOffsetAfter() {
+ return offsetAfter;
+ }
+
+ /**
+ * Gets the duration of the transition in seconds.
+ *
+ * @return the duration in seconds
+ */
+ private int getDurationSeconds() {
+ return getOffsetAfter().getTotalSeconds() - getOffsetBefore().getTotalSeconds();
+ }
+
+ /**
+ * Does this transition represent a gap in the local time-line.
+ *
+ * Gaps occur where there are local date-times that simply do not not exist.
+ * An example would be when the offset changes from {@code +01:00} to {@code +02:00}.
+ * This might be described as 'the clocks will move forward one hour tonight at 1am'.
+ *
+ * @return true if this transition is a gap, false if it is an overlap
+ */
+ public boolean isGap() {
+ return getOffsetAfter().getTotalSeconds() > getOffsetBefore().getTotalSeconds();
+ }
+
+ /**
+ * Does this transition represent a gap in the local time-line.
+ *
+ * Overlaps occur where there are local date-times that exist twice.
+ * An example would be when the offset changes from {@code +02:00} to {@code +01:00}.
+ * This might be described as 'the clocks will move back one hour tonight at 2am'.
+ *
+ * @return true if this transition is an overlap, false if it is a gap
+ */
+ public boolean isOverlap() {
+ return getOffsetAfter().getTotalSeconds() < getOffsetBefore().getTotalSeconds();
+ }
+
+ /**
+ * Checks if the specified offset is valid during this transition.
+ *
+ * This checks to see if the given offset will be valid at some point in the transition.
+ * A gap will always return false.
+ * An overlap will return true if the offset is either the before or after offset.
+ *
+ * @param offset the offset to check, null returns false
+ * @return true if the offset is valid during the transition
+ */
+ public boolean isValidOffset(ZoneOffset offset) {
+ return isGap() ? false : (getOffsetBefore().equals(offset) || getOffsetAfter().equals(offset));
+ }
+
+ /**
+ * Gets the valid offsets during this transition.
+ *
+ * A gap will return an empty list, while an overlap will return both offsets.
+ *
+ * @return the list of valid offsets
+ */
+ List
+ * This compares the instants of each transition.
+ * The offsets are ignored, making this order inconsistent with equals.
+ *
+ * @param transition the transition to compare to, not null
+ * @return the comparator value, negative if less, positive if greater
+ */
+ @Override
+ public int compareTo(ZoneOffsetTransition transition) {
+ return Long.compare(this.toEpochSecond(), transition.toEpochSecond());
+ }
+
+ /**
+ * Checks if this object equals another.
+ *
+ * The entire state of the object is compared.
+ *
+ * @param other the other object to compare to, null returns false
+ * @return true if equal
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+ if (other instanceof ZoneOffsetTransition) {
+ ZoneOffsetTransition d = (ZoneOffsetTransition) other;
+ return transition.equals(d.transition) &&
+ offsetBefore.equals(d.offsetBefore) && offsetAfter.equals(d.offsetAfter);
+ }
+ return false;
+ }
+
+ /**
+ * Returns a suitable hash code.
+ *
+ * @return the hash code
+ */
+ @Override
+ public int hashCode() {
+ return transition.hashCode() ^ offsetBefore.hashCode() ^ Integer.rotateLeft(offsetAfter.hashCode(), 16);
+ }
+
+}
diff --git a/make/tools/src/build/tools/tzdb/ZoneOffsetTransitionRule.java b/make/tools/src/build/tools/tzdb/ZoneOffsetTransitionRule.java
new file mode 100644
index 0000000000000000000000000000000000000000..783499c21632911c8972d346e320e6306d44cdfc
--- /dev/null
+++ b/make/tools/src/build/tools/tzdb/ZoneOffsetTransitionRule.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package build.tools.tzdb;
+
+import static build.tools.tzdb.Utils.*;
+import java.util.Objects;
+
+/**
+ * A rule expressing how to create a transition.
+ *
+ * This class allows rules for identifying future transitions to be expressed.
+ * A rule might be written in many forms:
+ *
+ * These different rule types can be expressed and queried.
+ *
+ *
+ * The entire state of the object is compared.
+ *
+ * @param otherRule the other object to compare to, null returns false
+ * @return true if equal
+ */
+ @Override
+ public boolean equals(Object otherRule) {
+ if (otherRule == this) {
+ return true;
+ }
+ if (otherRule instanceof ZoneOffsetTransitionRule) {
+ ZoneOffsetTransitionRule other = (ZoneOffsetTransitionRule) otherRule;
+ return month == other.month && dom == other.dom && dow == other.dow &&
+ timeDefinition == other.timeDefinition &&
+ time.equals(other.time) &&
+ timeEndOfDay == other.timeEndOfDay &&
+ standardOffset.equals(other.standardOffset) &&
+ offsetBefore.equals(other.offsetBefore) &&
+ offsetAfter.equals(other.offsetAfter);
+ }
+ return false;
+ }
+
+ /**
+ * Returns a suitable hash code.
+ *
+ * @return the hash code
+ */
+ @Override
+ public int hashCode() {
+ int hash = ((time.toSecondOfDay() + (timeEndOfDay ? 1 : 0)) << 15) +
+ (month << 11) + ((dom + 32) << 5) +
+ ((dow == -1 ? 8 : dow) << 2) + (timeDefinition.ordinal());
+ return hash ^ standardOffset.hashCode() ^
+ offsetBefore.hashCode() ^ offsetAfter.hashCode();
+ }
+
+}
diff --git a/make/tools/src/build/tools/tzdb/ZoneRules.java b/make/tools/src/build/tools/tzdb/ZoneRules.java
new file mode 100644
index 0000000000000000000000000000000000000000..22c3be80c027590b9c45e4082eba5d72c4728a7c
--- /dev/null
+++ b/make/tools/src/build/tools/tzdb/ZoneRules.java
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package build.tools.tzdb;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.ObjectOutput;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Duplicated code of javax.time.zone.ZoneRules, ZoneOffsetTransitionRule
+ * and Ser to generate the serialization form output of ZoneRules for
+ * tzdb.jar.
+ *
+ * Implementation here is the copy/paste of ZoneRules, ZoneOffsetTransitionRule
+ * and Ser in javax.time.zone package. Make sure the code here is synchrionozed
+ * with the serialization implementation there.
+ *
+ * @since 1.8
+ */
+
+final class ZoneRules {
+
+ /**
+ * The transitions between standard offsets (epoch seconds), sorted.
+ */
+ private final long[] standardTransitions;
+ /**
+ * The standard offsets.
+ */
+ private final ZoneOffset[] standardOffsets;
+ /**
+ * The transitions between instants (epoch seconds), sorted.
+ */
+ private final long[] savingsInstantTransitions;
+
+ /**
+ * The wall offsets.
+ */
+ private final ZoneOffset[] wallOffsets;
+ /**
+ * The last rule.
+ */
+ private final ZoneOffsetTransitionRule[] lastRules;
+
+ /**
+ * Creates an instance.
+ *
+ * @param baseStandardOffset the standard offset to use before legal rules were set, not null
+ * @param baseWallOffset the wall offset to use before legal rules were set, not null
+ * @param standardOffsetTransitionList the list of changes to the standard offset, not null
+ * @param transitionList the list of transitions, not null
+ * @param lastRules the recurring last rules, size 16 or less, not null
+ */
+ ZoneRules(ZoneOffset baseStandardOffset,
+ ZoneOffset baseWallOffset,
+ List
+ * Two rule sets are equal if they will always result in the same output
+ * for any given input instant or local date-time.
+ * Rules from two different groups may return false even if they are in fact the same.
+ *
+ * This definition should result in implementations comparing their entire state.
+ *
+ * @param otherRules the other rules, null returns false
+ * @return true if this rules is the same as that specified
+ */
+ @Override
+ public boolean equals(Object otherRules) {
+ if (this == otherRules) {
+ return true;
+ }
+ if (otherRules instanceof ZoneRules) {
+ ZoneRules other = (ZoneRules) otherRules;
+ return Arrays.equals(standardTransitions, other.standardTransitions) &&
+ Arrays.equals(standardOffsets, other.standardOffsets) &&
+ Arrays.equals(savingsInstantTransitions, other.savingsInstantTransitions) &&
+ Arrays.equals(wallOffsets, other.wallOffsets) &&
+ Arrays.equals(lastRules, other.lastRules);
+ }
+ return false;
+ }
+
+ /**
+ * Returns a suitable hash code given the definition of {@code #equals}.
+ *
+ * @return the hash code
+ */
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(standardTransitions) ^
+ Arrays.hashCode(standardOffsets) ^
+ Arrays.hashCode(savingsInstantTransitions) ^
+ Arrays.hashCode(wallOffsets) ^
+ Arrays.hashCode(lastRules);
+ }
+
+}
diff --git a/make/tools/src/build/tools/tzdb/ZoneRulesBuilder.java b/make/tools/src/build/tools/tzdb/ZoneRulesBuilder.java
new file mode 100644
index 0000000000000000000000000000000000000000..f4a437dc074bf6398b13e60ea7156e3575d6b712
--- /dev/null
+++ b/make/tools/src/build/tools/tzdb/ZoneRulesBuilder.java
@@ -0,0 +1,743 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package build.tools.tzdb;
+
+import static build.tools.tzdb.Utils.*;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * A mutable builder used to create all the rules for a historic time-zone.
+ *
+ * The rules of a time-zone describe how the offset changes over time.
+ * The rules are created by building windows on the time-line within which
+ * the different rules apply. The rules may be one of two kinds:
+ *
+ *
+ *
+ * The builder is used by adding one or more windows representing portions
+ * of the time-line. The standard offset from UTC/Greenwich will be constant
+ * within a window, although two adjacent windows can have the same standard offset.
+ *
+ * Within each window, there can either be a
+ * {@link #setFixedSavingsToWindow fixed savings amount} or a
+ * {@link #addRuleToWindow list of rules}.
+ */
+ public ZoneRulesBuilder() {
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Adds a window to the builder that can be used to filter a set of rules.
+ *
+ * This method defines and adds a window to the zone where the standard offset is specified.
+ * The window limits the effect of subsequent additions of transition rules
+ * or fixed savings. If neither rules or fixed savings are added to the window
+ * then the window will default to no savings.
+ *
+ * Each window must be added sequentially, as the start instant of the window
+ * is derived from the until instant of the previous window.
+ *
+ * @param standardOffset the standard offset, not null
+ * @param until the date-time that the offset applies until, not null
+ * @param untilDefinition the time type for the until date-time, not null
+ * @return this, for chaining
+ * @throws IllegalStateException if the window order is invalid
+ */
+ public ZoneRulesBuilder addWindow(
+ ZoneOffset standardOffset,
+ LocalDateTime until,
+ TimeDefinition untilDefinition) {
+ Objects.requireNonNull(standardOffset, "standardOffset");
+ Objects.requireNonNull(until, "until");
+ Objects.requireNonNull(untilDefinition, "untilDefinition");
+ TZWindow window = new TZWindow(standardOffset, until, untilDefinition);
+ if (windowList.size() > 0) {
+ TZWindow previous = windowList.get(windowList.size() - 1);
+ window.validateWindowOrder(previous);
+ }
+ windowList.add(window);
+ return this;
+ }
+
+ /**
+ * Adds a window that applies until the end of time to the builder that can be
+ * used to filter a set of rules.
+ *
+ * This method defines and adds a window to the zone where the standard offset is specified.
+ * The window limits the effect of subsequent additions of transition rules
+ * or fixed savings. If neither rules or fixed savings are added to the window
+ * then the window will default to no savings.
+ *
+ * This must be added after all other windows.
+ * No more windows can be added after this one.
+ *
+ * @param standardOffset the standard offset, not null
+ * @return this, for chaining
+ * @throws IllegalStateException if a forever window has already been added
+ */
+ public ZoneRulesBuilder addWindowForever(ZoneOffset standardOffset) {
+ return addWindow(standardOffset, LocalDateTime.MAX, TimeDefinition.WALL);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Sets the previously added window to have fixed savings.
+ *
+ * Setting a window to have fixed savings simply means that a single daylight
+ * savings amount applies throughout the window. The window could be small,
+ * such as a single summer, or large, such as a multi-year daylight savings.
+ *
+ * A window can either have fixed savings or rules but not both.
+ *
+ * @param fixedSavingAmountSecs the amount of saving to use for the whole window, not null
+ * @return this, for chaining
+ * @throws IllegalStateException if no window has yet been added
+ * @throws IllegalStateException if the window already has rules
+ */
+ public ZoneRulesBuilder setFixedSavingsToWindow(int fixedSavingAmountSecs) {
+ if (windowList.isEmpty()) {
+ throw new IllegalStateException("Must add a window before setting the fixed savings");
+ }
+ TZWindow window = windowList.get(windowList.size() - 1);
+ window.setFixedSavings(fixedSavingAmountSecs);
+ return this;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Adds a single transition rule to the current window.
+ *
+ * This adds a rule such that the offset, expressed as a daylight savings amount,
+ * changes at the specified date-time.
+ *
+ * @param transitionDateTime the date-time that the transition occurs as defined by timeDefintion, not null
+ * @param timeDefinition the definition of how to convert local to actual time, not null
+ * @param savingAmountSecs the amount of saving from the standard offset after the transition in seconds
+ * @return this, for chaining
+ * @throws IllegalStateException if no window has yet been added
+ * @throws IllegalStateException if the window already has fixed savings
+ * @throws IllegalStateException if the window has reached the maximum capacity of 2000 rules
+ */
+ public ZoneRulesBuilder addRuleToWindow(
+ LocalDateTime transitionDateTime,
+ TimeDefinition timeDefinition,
+ int savingAmountSecs) {
+ Objects.requireNonNull(transitionDateTime, "transitionDateTime");
+ return addRuleToWindow(
+ transitionDateTime.getYear(), transitionDateTime.getYear(),
+ transitionDateTime.getMonth(), transitionDateTime.getDayOfMonth(),
+ -1, transitionDateTime.getTime(), false, timeDefinition, savingAmountSecs);
+ }
+
+ /**
+ * Adds a single transition rule to the current window.
+ *
+ * This adds a rule such that the offset, expressed as a daylight savings amount,
+ * changes at the specified date-time.
+ *
+ * @param year the year of the transition, from MIN_YEAR to MAX_YEAR
+ * @param month the month of the transition, not null
+ * @param dayOfMonthIndicator the day-of-month of the transition, adjusted by dayOfWeek,
+ * from 1 to 31 adjusted later, or -1 to -28 adjusted earlier from the last day of the month
+ * @param time the time that the transition occurs as defined by timeDefintion, not null
+ * @param timeEndOfDay whether midnight is at the end of day
+ * @param timeDefinition the definition of how to convert local to actual time, not null
+ * @param savingAmountSecs the amount of saving from the standard offset after the transition in seconds
+ * @return this, for chaining
+ * @throws DateTimeException if a date-time field is out of range
+ * @throws IllegalStateException if no window has yet been added
+ * @throws IllegalStateException if the window already has fixed savings
+ * @throws IllegalStateException if the window has reached the maximum capacity of 2000 rules
+ */
+ public ZoneRulesBuilder addRuleToWindow(
+ int year,
+ int month,
+ int dayOfMonthIndicator,
+ LocalTime time,
+ boolean timeEndOfDay,
+ TimeDefinition timeDefinition,
+ int savingAmountSecs) {
+ return addRuleToWindow(year, year, month, dayOfMonthIndicator, -1, time, timeEndOfDay, timeDefinition, savingAmountSecs);
+ }
+
+ /**
+ * Adds a multi-year transition rule to the current window.
+ *
+ * This adds a rule such that the offset, expressed as a daylight savings amount,
+ * changes at the specified date-time for each year in the range.
+ *
+ * @param startYear the start year of the rule, from MIN_YEAR to MAX_YEAR
+ * @param endYear the end year of the rule, from MIN_YEAR to MAX_YEAR
+ * @param month the month of the transition, from 1 to 12
+ * @param dayOfMonthIndicator the day-of-month of the transition, adjusted by dayOfWeek,
+ * from 1 to 31 adjusted later, or -1 to -28 adjusted earlier from the last day of the month
+ * @param dayOfWeek the day-of-week to adjust to, -1 if day-of-month should not be adjusted
+ * @param time the time that the transition occurs as defined by timeDefintion, not null
+ * @param timeEndOfDay whether midnight is at the end of day
+ * @param timeDefinition the definition of how to convert local to actual time, not null
+ * @param savingAmountSecs the amount of saving from the standard offset after the transition in seconds
+ * @return this, for chaining
+ * @throws DateTimeException if a date-time field is out of range
+ * @throws IllegalArgumentException if the day of month indicator is invalid
+ * @throws IllegalArgumentException if the end of day midnight flag does not match the time
+ * @throws IllegalStateException if no window has yet been added
+ * @throws IllegalStateException if the window already has fixed savings
+ * @throws IllegalStateException if the window has reached the maximum capacity of 2000 rules
+ */
+ public ZoneRulesBuilder addRuleToWindow(
+ int startYear,
+ int endYear,
+ int month,
+ int dayOfMonthIndicator,
+ int dayOfWeek,
+ LocalTime time,
+ boolean timeEndOfDay,
+ TimeDefinition timeDefinition,
+ int savingAmountSecs) {
+ Objects.requireNonNull(time, "time");
+ Objects.requireNonNull(timeDefinition, "timeDefinition");
+ if (dayOfMonthIndicator < -28 || dayOfMonthIndicator > 31 || dayOfMonthIndicator == 0) {
+ throw new IllegalArgumentException("Day of month indicator must be between -28 and 31 inclusive excluding zero");
+ }
+ if (timeEndOfDay && time.equals(LocalTime.MIDNIGHT) == false) {
+ throw new IllegalArgumentException("Time must be midnight when end of day flag is true");
+ }
+ if (windowList.isEmpty()) {
+ throw new IllegalStateException("Must add a window before adding a rule");
+ }
+ TZWindow window = windowList.get(windowList.size() - 1);
+ window.addRule(startYear, endYear, month, dayOfMonthIndicator, dayOfWeek, time, timeEndOfDay, timeDefinition, savingAmountSecs);
+ return this;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Completes the build converting the builder to a set of time-zone rules.
+ *
+ * Calling this method alters the state of the builder.
+ * Further rules should not be added to this builder once this method is called.
+ *
+ * @param zoneId the time-zone ID, not null
+ * @return the zone rules, not null
+ * @throws IllegalStateException if no windows have been added
+ * @throws IllegalStateException if there is only one rule defined as being forever for any given window
+ */
+ public ZoneRules toRules(String zoneId) {
+ Objects.requireNonNull(zoneId, "zoneId");
+ if (windowList.isEmpty()) {
+ throw new IllegalStateException("No windows have been added to the builder");
+ }
+
+ final List
+ * 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()}.
+ *
+ * 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.
+ *
+ * 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:
+ *
+ * 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.
+ *
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * This clock, rather than {@link #systemDefaultZone()}, should be used when
+ * you need the current instant without the date or time.
+ *
+ * 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.
+ *
+ * Conversion from instant to date or time uses the {@linkplain ZoneOffset#UTC UTC time-zone}.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * Conversion from instant to date or time uses the specified time-zone.
+ *
+ * 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.
+ *
+ * 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)}.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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)}.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * A duration of zero or one nanosecond would have no truncation effect.
+ * Passing one of these will return the underlying clock.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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
+ *
+ * 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.
+ *
+ * A duration of zero would have no offsetting effect.
+ * Passing zero will return the underlying clock.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * This returns the millisecond-based instant, measured from 1970-01-01T00:00 UTC.
+ * This is equivalent to the definition of {@link System#currentTimeMillis()}.
+ *
+ * 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.
+ *
+ * This returns an instant representing the current instant as defined by the clock.
+ *
+ * The default implementation currently calls {@link #millis}.
+ *
+ * @return the current instant from this clock, not null
+ * @throws DateTimeException if the instant cannot be obtained, not thrown by most implementations
+ */
+ public Instant instant() {
+ return Instant.ofEpochMilli(millis());
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks if this clock is equal to another clock.
+ *
+ * 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.
+ *
+ * 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) + "]";
+ }
+ }
+
+}
diff --git a/src/share/classes/java/time/DateTimeException.java b/src/share/classes/java/time/DateTimeException.java
new file mode 100644
index 0000000000000000000000000000000000000000..e5e9efa85ca99191d89cd0c186902a9a43940aed
--- /dev/null
+++ b/src/share/classes/java/time/DateTimeException.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * 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.
+ *
+ * This exception is used to indicate problems with creating, querying
+ * and manipulating date-time objects.
+ *
+ *
+ * {@code DayOfWeek} is an enum representing the 7 days of the week -
+ * Monday, Tuesday, Wednesday, Thursday, Friday, Saturday and Sunday.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * Do not use {@code ordinal()} to obtain the numeric representation of {@code DayOfWeek}.
+ * Use {@code getValue()} instead.
+ *
+ * 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.
+ *
+ *
+ * {@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.
+ *
+ * A {@code TemporalAccessor} represents some form of date and time information.
+ * This factory converts the arbitrary temporal object to an instance of {@code DayOfWeek}.
+ *
+ * The conversion extracts the {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} field.
+ *
+ * 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.
+ *
+ * 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'.
+ *
+ * This returns the textual name used to identify the day-of-week.
+ * The parameters control the length of the returned text and the locale.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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}.
+ *
+ * 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}.
+ *
+ * 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.
+ *
+ * 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}.
+ *
+ * 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}.
+ *
+ * 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.
+ *
+ * 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}.
+ *
+ * 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.
+ *
+ * The calculation rolls around the end of the week from Sunday to Monday.
+ * The specified period may be negative.
+ *
+ * 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.
+ *
+ * The calculation rolls around the start of the year from Monday to Sunday.
+ * The specified period may be negative.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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
+ * 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.
+ *
+ * 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)}.
+ *
+ * In most cases, it is clearer to reverse the calling pattern by using
+ * {@link Temporal#with(TemporalAdjuster)}:
+ *
+ * For example, given a date that is a Wednesday, the following are output:
+ *
+ * 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());
+ }
+
+}
diff --git a/src/share/classes/java/time/Duration.java b/src/share/classes/java/time/Duration.java
new file mode 100644
index 0000000000000000000000000000000000000000..e8d75fadba19af887858574fc497820daa3ad11e
--- /dev/null
+++ b/src/share/classes/java/time/Duration.java
@@ -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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * The range of a duration requires the storage of a number larger than a {@code long}.
+ * To achieve this, the class stores a {@code long} representing seconds and an {@code int}
+ * representing nanosecond-of-second, which will always be between 0 and 999,999,999.
+ *
+ * The 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.
+ *
+ *
+ * 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.
+ *
+ * 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:
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * The seconds are calculated based on the standard definition of a minute,
+ * where each minute is 60 seconds.
+ * The nanosecond in second field is set to zero.
+ *
+ * @param minutes the number of minutes, positive or negative
+ * @return a {@code Duration}, not null
+ * @throws ArithmeticException if the input minutes exceeds the capacity of {@code Duration}
+ */
+ public static Duration ofMinutes(long minutes) {
+ return create(Math.multiplyExact(minutes, 60), 0);
+ }
+
+ /**
+ * Obtains an instance of {@code Duration} from a number of standard length hours.
+ *
+ * The seconds are calculated based on the standard definition of an hour,
+ * where each hour is 3600 seconds.
+ * The nanosecond in second field is set to zero.
+ *
+ * @param hours the number of hours, positive or negative
+ * @return a {@code Duration}, not null
+ * @throws ArithmeticException if the input hours exceeds the capacity of {@code Duration}
+ */
+ public static Duration ofHours(long hours) {
+ return create(Math.multiplyExact(hours, 3600), 0);
+ }
+
+ /**
+ * Obtains an instance of {@code Duration} from a number of standard 24 hour days.
+ *
+ * The seconds are calculated based on the standard definition of a day,
+ * where each day is 86400 seconds which implies a 24 hour day.
+ * The nanosecond in second field is set to zero.
+ *
+ * @param days the number of days, positive or negative
+ * @return a {@code Duration}, not null
+ * @throws ArithmeticException if the input days exceeds the capacity of {@code Duration}
+ */
+ public static Duration ofDays(long days) {
+ return create(Math.multiplyExact(days, 86400), 0);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code Duration} from a duration in the specified unit.
+ *
+ * The parameters represent the two parts of a phrase like '6 Hours'. For example:
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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()}.
+ *
+ * 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.
+ *
+ * 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()}.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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}.
+ *
+ * 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.
+ *
+ * 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}.
+ *
+ * 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.
+ *
+ * This returns a temporal object of the same observable type as the input
+ * with this duration added.
+ *
+ * In most cases, it is clearer to reverse the calling pattern by using
+ * {@link Temporal#plus(TemporalAdder)}.
+ *
+ * A {@code Duration} can only be added to a {@code Temporal} that
+ * represents an instant and can supply {@link ChronoField#INSTANT_SECONDS}.
+ *
+ * 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.
+ *
+ * This returns a temporal object of the same observable type as the input
+ * with this duration subtracted.
+ *
+ * In most cases, it is clearer to reverse the calling pattern by using
+ * {@link Temporal#minus(TemporalSubtractor)}.
+ *
+ * A {@code Duration} can only be subtracted from a {@code Temporal} that
+ * represents an instant and can supply {@link ChronoField#INSTANT_SECONDS}.
+ *
+ * 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.
+ *
+ * If this duration is too large to fit in a {@code long} milliseconds, then an
+ * exception is thrown.
+ *
+ * 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}.
+ *
+ * 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}.
+ *
+ * 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}.
+ *
+ * The comparison is based on the total length of the durations.
+ *
+ * @param otherDuration the other duration to compare to, not null
+ * @return true if this duration is greater than the specified duration
+ */
+ public boolean isGreaterThan(Duration otherDuration) {
+ return compareTo(otherDuration) > 0;
+ }
+
+ /**
+ * Checks if this duration is less than the specified {@code Duration}.
+ *
+ * The comparison is based on the total length of the durations.
+ *
+ * @param otherDuration the other duration to compare to, not null
+ * @return true if this duration is less than the specified duration
+ */
+ public boolean isLessThan(Duration otherDuration) {
+ return compareTo(otherDuration) < 0;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks if this duration is equal to the specified {@code Duration}.
+ *
+ * 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}.
+ *
+ * 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
+ * dedicated serialized form.
+ *
+ * This class models a single instantaneous point on the time-line.
+ * This might be used to record event time-stamps in the application.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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 leap-seconds.
+ * 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.
+ *
+ * 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.
+ *
+ * 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:
+ *
+ * Agreed international civil time is the base time-scale agreed by international convention,
+ * which in 2012 is UTC (with leap-seconds).
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ * UTC-SLS 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.
+ *
+ * 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.
+ *
+ * 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}.
+ *
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * This will query the {@link Clock#systemUTC() system UTC clock} to
+ * obtain the current instant.
+ *
+ * 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.
+ *
+ * This will query the specified clock to obtain the current time.
+ *
+ * Using this method allows the use of an alternate clock for testing.
+ * The alternate clock may be introduced using {@link Clock dependency injection}.
+ *
+ * @param clock the clock to use, not null
+ * @return the current 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.
+ *
+ * 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.
+ *
+ * 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:
+ *
+ * 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.
+ *
+ * A {@code TemporalAccessor} represents some form of date and time information.
+ * This factory converts the arbitrary temporal object to an instance of {@code Instant}.
+ *
+ * The conversion extracts the {@link ChronoField#INSTANT_SECONDS INSTANT_SECONDS}
+ * and {@link ChronoField#NANO_OF_SECOND NANO_OF_SECOND} fields.
+ *
+ * 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}.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * If the field is a {@link ChronoField} then the query is implemented here.
+ * The supported fields are:
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * If the field is a {@link ChronoField} then the query is implemented here.
+ * The {@link #isSupported(TemporalField) supported fields} will return
+ * appropriate range instances.
+ * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)}
+ * passing {@code this} as the argument.
+ * Whether the range can be obtained is determined by the field.
+ *
+ * @param field the field to query the range for, not null
+ * @return the range of valid values for the field, not null
+ * @throws DateTimeException if the range for the field cannot be obtained
+ */
+ @Override // 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}.
+ *
+ * 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.
+ *
+ * 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}.
+ *
+ * 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}.
+ *
+ * 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.
+ *
+ * If the field is a {@link ChronoField} then the query is implemented here.
+ * The {@link #isSupported(TemporalField) supported fields} will return valid
+ * values based on this date-time.
+ * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+ * passing {@code this} as the argument. Whether the value can be obtained,
+ * and what the value represents, is determined by the field.
+ *
+ * @param field the field to get, not null
+ * @return the value for the field
+ * @throws DateTimeException if a value for the field cannot be obtained
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public long getLong(TemporalField field) {
+ if (field instanceof ChronoField) {
+ switch ((ChronoField) field) {
+ case 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * The result of this method is obtained by invoking the
+ * {@link TemporalAdjuster#adjustInto(Temporal)} method on the
+ * specified adjuster passing {@code this} as the argument.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param adjuster the adjuster to use, not null
+ * @return an {@code 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.
+ *
+ * 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.
+ *
+ * If the field is a {@link ChronoField} then the adjustment is implemented here.
+ * The supported fields behave as follows:
+ *
+ * In all cases, if the new value is outside the valid range of values for the field
+ * then a {@code DateTimeException} will be thrown.
+ *
+ * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doWith(Temporal, long)}
+ * passing {@code this} as the argument. In this case, the field determines
+ * whether and how to adjust the instant.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param field the field to set in the result, not null
+ * @param newValue the new value of the field in the result
+ * @return 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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
+ * This returns a temporal object of the same observable type as the input
+ * with the instant changed to be the same as this.
+ *
+ * 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.
+ *
+ * In most cases, it is clearer to reverse the calling pattern by using
+ * {@link Temporal#with(TemporalAdjuster)}:
+ *
+ * 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.
+ *
+ * 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)}.
+ *
+ * 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:
+ *
+ * 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.
+ *
+ * If the unit is not a {@code ChronoUnit}, then the result of this method
+ * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
+ * passing {@code this} as the first argument and the input temporal as
+ * the second argument.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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
+ * dedicated serialized form.
+ *
+ * {@code LocalDate} is an immutable date-time object that represents a date,
+ * often viewed as year-month-day. Other date fields, such as day-of-year,
+ * day-of-week and week-of-year, can also be accessed.
+ * For example, the value "2nd October 2007" can be stored in a {@code LocalDate}.
+ *
+ * This class does not store or represent a time or time-zone.
+ * Instead, it is a description of the date, as used for birthdays.
+ * It cannot represent an instant on the time-line without additional information
+ * such as an offset or time-zone.
+ *
+ * The ISO-8601 calendar system is the modern civil calendar system used today
+ * in most of the world. It is equivalent to the proleptic Gregorian calendar
+ * system, in which today's rules for leap years are applied for all time.
+ * For most applications written today, the ISO-8601 rules are entirely suitable.
+ * However, any application that makes use of historical dates, and requires them
+ * to be accurate will find the ISO-8601 approach unsuitable.
+ *
+ *
+ * This will query the {@link Clock#systemDefaultZone() system clock} in the default
+ * time-zone to obtain the current date.
+ *
+ * Using this method will prevent the ability to use an alternate clock for testing
+ * because the clock is hard-coded.
+ *
+ * @return the current date using the system clock and default time-zone, not null
+ */
+ public static LocalDate now() {
+ return now(Clock.systemDefaultZone());
+ }
+
+ /**
+ * Obtains the current date from the system clock in the specified time-zone.
+ *
+ * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date.
+ * Specifying the time-zone avoids dependence on the default time-zone.
+ *
+ * Using this method will prevent the ability to use an alternate clock for testing
+ * because the clock is hard-coded.
+ *
+ * @param zone the zone ID to use, not null
+ * @return the current date using the system clock, not null
+ */
+ public static LocalDate now(ZoneId zone) {
+ return now(Clock.system(zone));
+ }
+
+ /**
+ * Obtains the current date from the specified clock.
+ *
+ * This will query the specified clock to obtain the current date - today.
+ * Using this method allows the use of an alternate clock for testing.
+ * The alternate clock may be introduced using {@link Clock dependency injection}.
+ *
+ * @param clock the clock to use, not null
+ * @return the current date, not null
+ */
+ public static LocalDate now(Clock clock) {
+ Objects.requireNonNull(clock, "clock");
+ // inline OffsetDate factory to avoid creating object and InstantProvider checks
+ final Instant now = clock.instant(); // called once
+ ZoneOffset offset = clock.getZone().getRules().getOffset(now);
+ long epochSec = now.getEpochSecond() + offset.getTotalSeconds(); // overflow caught later
+ long epochDay = Math.floorDiv(epochSec, SECONDS_PER_DAY);
+ return LocalDate.ofEpochDay(epochDay);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code LocalDate} from a year, month and day.
+ *
+ * The day must be valid for the year and month, otherwise an exception will be thrown.
+ *
+ * @param year the year to represent, from MIN_YEAR to MAX_YEAR
+ * @param month the month-of-year to represent, not null
+ * @param dayOfMonth the day-of-month to represent, from 1 to 31
+ * @return the local date, not null
+ * @throws DateTimeException if the value of any field is out of range
+ * @throws DateTimeException if the day-of-month is invalid for the month-year
+ */
+ public static LocalDate of(int year, Month month, int dayOfMonth) {
+ YEAR.checkValidValue(year);
+ Objects.requireNonNull(month, "month");
+ DAY_OF_MONTH.checkValidValue(dayOfMonth);
+ return create(year, month, dayOfMonth);
+ }
+
+ /**
+ * Obtains an instance of {@code LocalDate} from a year, month and day.
+ *
+ * The day must be valid for the year and month, otherwise an exception will be thrown.
+ *
+ * @param year the year to represent, from MIN_YEAR to MAX_YEAR
+ * @param month the month-of-year to represent, from 1 (January) to 12 (December)
+ * @param dayOfMonth the day-of-month to represent, from 1 to 31
+ * @return the local date, not null
+ * @throws DateTimeException if the value of any field is out of range
+ * @throws DateTimeException if the day-of-month is invalid for the month-year
+ */
+ public static LocalDate of(int year, int month, int dayOfMonth) {
+ YEAR.checkValidValue(year);
+ MONTH_OF_YEAR.checkValidValue(month);
+ DAY_OF_MONTH.checkValidValue(dayOfMonth);
+ return create(year, Month.of(month), dayOfMonth);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code LocalDate} from a year and day-of-year.
+ *
+ * The day-of-year must be valid for the year, otherwise an exception will be thrown.
+ *
+ * @param year the year to represent, from MIN_YEAR to MAX_YEAR
+ * @param dayOfYear the day-of-year to represent, from 1 to 366
+ * @return the local date, not null
+ * @throws DateTimeException if the value of any field is out of range
+ * @throws DateTimeException if the day-of-year is invalid for the month-year
+ */
+ public static LocalDate ofYearDay(int year, int dayOfYear) {
+ YEAR.checkValidValue(year);
+ DAY_OF_YEAR.checkValidValue(dayOfYear);
+ boolean leap = ISOChrono.INSTANCE.isLeapYear(year);
+ if (dayOfYear == 366 && leap == false) {
+ throw new DateTimeException("Invalid date 'DayOfYear 366' as '" + year + "' is not a leap year");
+ }
+ Month moy = Month.of((dayOfYear - 1) / 31 + 1);
+ int monthEnd = moy.firstDayOfYear(leap) + moy.length(leap) - 1;
+ if (dayOfYear > monthEnd) {
+ moy = moy.plus(1);
+ }
+ int dom = dayOfYear - moy.firstDayOfYear(leap) + 1;
+ return create(year, moy, dom);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code LocalDate} from the epoch day count.
+ *
+ * The Epoch Day count is a simple incrementing count of days
+ * where day 0 is 1970-01-01. Negative numbers represent earlier days.
+ *
+ * @param epochDay the Epoch Day to convert, based on the epoch 1970-01-01
+ * @return the local date, not null
+ * @throws DateTimeException if the epoch days exceeds the supported date range
+ */
+ public static LocalDate ofEpochDay(long epochDay) {
+ long zeroDay = epochDay + DAYS_0000_TO_1970;
+ // find the march-based year
+ zeroDay -= 60; // adjust to 0000-03-01 so leap day is at end of four year cycle
+ long adjust = 0;
+ if (zeroDay < 0) {
+ // adjust negative years to positive for calculation
+ long adjustCycles = (zeroDay + 1) / DAYS_PER_CYCLE - 1;
+ adjust = adjustCycles * 400;
+ zeroDay += -adjustCycles * DAYS_PER_CYCLE;
+ }
+ long yearEst = (400 * zeroDay + 591) / DAYS_PER_CYCLE;
+ long doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400);
+ if (doyEst < 0) {
+ // fix estimate
+ yearEst--;
+ doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400);
+ }
+ yearEst += adjust; // reset any negative year
+ int marchDoy0 = (int) doyEst;
+
+ // convert march-based values back to january-based
+ int marchMonth0 = (marchDoy0 * 5 + 2) / 153;
+ int month = (marchMonth0 + 2) % 12 + 1;
+ int dom = marchDoy0 - (marchMonth0 * 306 + 5) / 10 + 1;
+ yearEst += marchMonth0 / 10;
+
+ // check year now we are certain it is correct
+ int year = YEAR.checkValidIntValue(yearEst);
+ return new LocalDate(year, month, dom);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code LocalDate} from a temporal object.
+ *
+ * A {@code TemporalAccessor} represents some form of date and time information.
+ * This factory converts the arbitrary temporal object to an instance of {@code LocalDate}.
+ *
+ * The conversion extracts the {@link ChronoField#EPOCH_DAY EPOCH_DAY} field.
+ *
+ * This method matches the signature of the functional interface {@link TemporalQuery}
+ * allowing it to be used as a query via method reference, {@code LocalDate::from}.
+ *
+ * @param temporal the temporal object to convert, not null
+ * @return the local date, not null
+ * @throws DateTimeException if unable to convert to a {@code LocalDate}
+ */
+ public static LocalDate from(TemporalAccessor temporal) {
+ if (temporal instanceof LocalDate) {
+ return (LocalDate) temporal;
+ } else if (temporal instanceof LocalDateTime) {
+ return ((LocalDateTime) temporal).getDate();
+ } else if (temporal instanceof ZonedDateTime) {
+ return ((ZonedDateTime) temporal).getDate();
+ }
+ // handle builder as a special case
+ if (temporal instanceof DateTimeBuilder) {
+ DateTimeBuilder builder = (DateTimeBuilder) temporal;
+ LocalDate date = builder.extract(LocalDate.class);
+ if (date != null) {
+ return date;
+ }
+ }
+ try {
+ return ofEpochDay(temporal.getLong(EPOCH_DAY));
+ } catch (DateTimeException ex) {
+ throw new DateTimeException("Unable to obtain LocalDate from TemporalAccessor: " + temporal.getClass(), ex);
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code LocalDate} from a text string such as {@code 2007-12-03}.
+ *
+ * The string must represent a valid date and is parsed using
+ * {@link java.time.format.DateTimeFormatters#isoLocalDate()}.
+ *
+ * @param text the text to parse such as "2007-12-03", not null
+ * @return the parsed local date, not null
+ * @throws DateTimeParseException if the text cannot be parsed
+ */
+ public static LocalDate parse(CharSequence text) {
+ return parse(text, DateTimeFormatters.isoLocalDate());
+ }
+
+ /**
+ * Obtains an instance of {@code LocalDate} from a text string using a specific formatter.
+ *
+ * The text is parsed using the formatter, returning a date.
+ *
+ * @param text the text to parse, not null
+ * @param formatter the formatter to use, not null
+ * @return the parsed local date, not null
+ * @throws DateTimeParseException if the text cannot be parsed
+ */
+ public static LocalDate parse(CharSequence text, DateTimeFormatter formatter) {
+ Objects.requireNonNull(formatter, "formatter");
+ return formatter.parse(text, LocalDate::from);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Creates a local date from the year, month and day fields.
+ *
+ * @param year the year to represent, validated from MIN_YEAR to MAX_YEAR
+ * @param month the month-of-year to represent, validated not null
+ * @param dayOfMonth the day-of-month to represent, validated from 1 to 31
+ * @return the local date, not null
+ * @throws DateTimeException if the day-of-month is invalid for the month-year
+ */
+ private static LocalDate create(int year, Month month, int dayOfMonth) {
+ if (dayOfMonth > 28 && dayOfMonth > month.length(ISOChrono.INSTANCE.isLeapYear(year))) {
+ if (dayOfMonth == 29) {
+ throw new DateTimeException("Invalid date 'February 29' as '" + year + "' is not a leap year");
+ } else {
+ throw new DateTimeException("Invalid date '" + month.name() + " " + dayOfMonth + "'");
+ }
+ }
+ return new LocalDate(year, month.getValue(), dayOfMonth);
+ }
+
+ /**
+ * Resolves the date, resolving days past the end of month.
+ *
+ * @param year the year to represent, validated from MIN_YEAR to MAX_YEAR
+ * @param month the month-of-year to represent, validated from 1 to 12
+ * @param day the day-of-month to represent, validated from 1 to 31
+ * @return the resolved date, not null
+ */
+ private static LocalDate resolvePreviousValid(int year, int month, int day) {
+ switch (month) {
+ case 2:
+ day = Math.min(day, ISOChrono.INSTANCE.isLeapYear(year) ? 29 : 28);
+ break;
+ case 4:
+ case 6:
+ case 9:
+ case 11:
+ day = Math.min(day, 30);
+ break;
+ }
+ return LocalDate.of(year, month, day);
+ }
+
+ /**
+ * Constructor, previously validated.
+ *
+ * @param year the year to represent, from MIN_YEAR to MAX_YEAR
+ * @param month the month-of-year to represent, not null
+ * @param dayOfMonth the day-of-month to represent, valid for year-month, from 1 to 31
+ */
+ private LocalDate(int year, int month, int dayOfMonth) {
+ this.year = year;
+ this.month = (short) month;
+ this.day = (short) dayOfMonth;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks if the specified field is supported.
+ *
+ * This checks if this date can be queried for the specified field.
+ * If false, then calling the {@link #range(TemporalField) range} and
+ * {@link #get(TemporalField) get} methods will throw an exception.
+ *
+ * If the field is a {@link ChronoField} then the query is implemented here.
+ * The {@link #isSupported(TemporalField) supported fields} will return valid
+ * values based on this date-time.
+ * The supported fields are:
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)}
+ * passing {@code this} as the argument.
+ * Whether the field is supported is determined by the field.
+ *
+ * @param field the field to check, null returns false
+ * @return true if the field is supported on this date, false if not
+ */
+ @Override // override for Javadoc
+ public boolean isSupported(TemporalField field) {
+ return ChronoLocalDate.super.isSupported(field);
+ }
+
+ /**
+ * Gets the range of valid values for the specified field.
+ *
+ * The range object expresses the minimum and maximum valid values for a field.
+ * This date is used to enhance the accuracy of the returned range.
+ * If it is not possible to return the range, because the field is not supported
+ * or for some other reason, an exception is thrown.
+ *
+ * If the field is a {@link ChronoField} then the query is implemented here.
+ * The {@link #isSupported(TemporalField) supported fields} will return
+ * appropriate range instances.
+ * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)}
+ * passing {@code this} as the argument.
+ * Whether the range can be obtained is determined by the field.
+ *
+ * @param field the field to query the range for, not null
+ * @return the range of valid values for the field, not null
+ * @throws DateTimeException if the range for the field cannot be obtained
+ */
+ @Override
+ public ValueRange range(TemporalField field) {
+ if (field instanceof ChronoField) {
+ ChronoField f = (ChronoField) field;
+ if (f.isDateField()) {
+ switch (f) {
+ case DAY_OF_MONTH: return ValueRange.of(1, lengthOfMonth());
+ case DAY_OF_YEAR: return ValueRange.of(1, lengthOfYear());
+ case ALIGNED_WEEK_OF_MONTH: return ValueRange.of(1, getMonth() == Month.FEBRUARY && isLeapYear() == false ? 4 : 5);
+ case YEAR_OF_ERA:
+ return (getYear() <= 0 ? ValueRange.of(1, Year.MAX_VALUE + 1) : ValueRange.of(1, Year.MAX_VALUE));
+ }
+ return field.range();
+ }
+ throw new DateTimeException("Unsupported field: " + field.getName());
+ }
+ return field.doRange(this);
+ }
+
+ /**
+ * Gets the value of the specified field from this date as an {@code int}.
+ *
+ * This queries this date for the value for the specified field.
+ * The returned value will always be within the valid range of values for the field.
+ * If it is not possible to return the value, because the field is not supported
+ * or for some other reason, an exception is thrown.
+ *
+ * If the field is a {@link ChronoField} then the query is implemented here.
+ * The {@link #isSupported(TemporalField) supported fields} will return valid
+ * values based on this date, except {@code EPOCH_DAY} and {@code EPOCH_MONTH}
+ * which are too large to fit in an {@code int} and throw a {@code DateTimeException}.
+ * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+ * passing {@code this} as the argument. Whether the value can be obtained,
+ * and what the value represents, is determined by the field.
+ *
+ * @param field the field to get, not null
+ * @return the value for the field
+ * @throws DateTimeException if a value for the field cannot be obtained
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override // override for Javadoc and performance
+ public int get(TemporalField field) {
+ if (field instanceof ChronoField) {
+ return get0(field);
+ }
+ return ChronoLocalDate.super.get(field);
+ }
+
+ /**
+ * Gets the value of the specified field from this date as a {@code long}.
+ *
+ * This queries this date for the value for the specified field.
+ * If it is not possible to return the value, because the field is not supported
+ * or for some other reason, an exception is thrown.
+ *
+ * If the field is a {@link ChronoField} then the query is implemented here.
+ * The {@link #isSupported(TemporalField) supported fields} will return valid
+ * values based on this date.
+ * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+ * passing {@code this} as the argument. Whether the value can be obtained,
+ * and what the value represents, is determined by the field.
+ *
+ * @param field the field to get, not null
+ * @return the value for the field
+ * @throws DateTimeException if a value for the field cannot be obtained
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public long getLong(TemporalField field) {
+ if (field instanceof ChronoField) {
+ if (field == EPOCH_DAY) {
+ return toEpochDay();
+ }
+ if (field == EPOCH_MONTH) {
+ return getEpochMonth();
+ }
+ return get0(field);
+ }
+ return field.doGet(this);
+ }
+
+ private int get0(TemporalField field) {
+ switch ((ChronoField) field) {
+ case DAY_OF_WEEK: return getDayOfWeek().getValue();
+ case ALIGNED_DAY_OF_WEEK_IN_MONTH: return ((day - 1) % 7) + 1;
+ case ALIGNED_DAY_OF_WEEK_IN_YEAR: return ((getDayOfYear() - 1) % 7) + 1;
+ case DAY_OF_MONTH: return day;
+ case DAY_OF_YEAR: return getDayOfYear();
+ case EPOCH_DAY: throw new DateTimeException("Field too large for an int: " + field);
+ case ALIGNED_WEEK_OF_MONTH: return ((day - 1) / 7) + 1;
+ case ALIGNED_WEEK_OF_YEAR: return ((getDayOfYear() - 1) / 7) + 1;
+ case MONTH_OF_YEAR: return month;
+ case EPOCH_MONTH: throw new DateTimeException("Field too large for an int: " + field);
+ case YEAR_OF_ERA: return (year >= 1 ? year : 1 - year);
+ case YEAR: return year;
+ case ERA: return (year >= 1 ? 1 : 0);
+ }
+ throw new DateTimeException("Unsupported field: " + field.getName());
+ }
+
+ private long getEpochMonth() {
+ return ((year - 1970) * 12L) + (month - 1);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the chronology of this date, which is the ISO calendar system.
+ *
+ * The {@code Chrono} represents the calendar system in use.
+ * The ISO-8601 calendar system is the modern civil calendar system used today
+ * in most of the world. It is equivalent to the proleptic Gregorian calendar
+ * system, in which todays's rules for leap years are applied for all time.
+ *
+ * @return the ISO chronology, not null
+ */
+ @Override
+ public ISOChrono getChrono() {
+ return ISOChrono.INSTANCE;
+ }
+
+ /**
+ * Gets the era applicable at this date.
+ *
+ * The official ISO-8601 standard does not define eras, however {@code ISOChrono} does.
+ * It defines two eras, 'CE' from year one onwards and 'BCE' from year zero backwards.
+ * Since dates before the Julian-Gregorian cutover are not in line with history,
+ * the cutover between 'BCE' and 'CE' is also not aligned with the commonly used
+ * eras, often referred to using 'BC' and 'AD'.
+ *
+ * Users of this class should typically ignore this method as it exists primarily
+ * to fulfill the {@link ChronoLocalDate} contract where it is necessary to support
+ * the Japanese calendar system.
+ *
+ * The returned era will be a singleton capable of being compared with the constants
+ * in {@link ISOChrono} using the {@code ==} operator.
+ *
+ * @return the {@code ISOChrono} era constant applicable at this date, not null
+ */
+ @Override // override for Javadoc
+ public Era
+ * This method returns the primitive {@code int} value for the year.
+ *
+ * The year returned by this method is proleptic as per {@code get(YEAR)}.
+ * To obtain the year-of-era, use {@code get(YEAR_OF_ERA}.
+ *
+ * @return the year, from MIN_YEAR to MAX_YEAR
+ */
+ public int getYear() {
+ return year;
+ }
+
+ /**
+ * Gets the month-of-year field from 1 to 12.
+ *
+ * This method returns the month as an {@code int} from 1 to 12.
+ * Application code is frequently clearer if the enum {@link Month}
+ * is used by calling {@link #getMonth()}.
+ *
+ * @return the month-of-year, from 1 to 12
+ * @see #getMonth()
+ */
+ public int getMonthValue() {
+ return month;
+ }
+
+ /**
+ * Gets the month-of-year field using the {@code Month} enum.
+ *
+ * This method returns the enum {@link Month} for the month.
+ * This avoids confusion as to what {@code int} values mean.
+ * If you need access to the primitive {@code int} value then the enum
+ * provides the {@link Month#getValue() int value}.
+ *
+ * @return the month-of-year, not null
+ * @see #getMonthValue()
+ */
+ public Month getMonth() {
+ return Month.of(month);
+ }
+
+ /**
+ * Gets the day-of-month field.
+ *
+ * This method returns the primitive {@code int} value for the day-of-month.
+ *
+ * @return the day-of-month, from 1 to 31
+ */
+ public int getDayOfMonth() {
+ return day;
+ }
+
+ /**
+ * Gets the day-of-year field.
+ *
+ * This method returns the primitive {@code int} value for the day-of-year.
+ *
+ * @return the day-of-year, from 1 to 365, or 366 in a leap year
+ */
+ public int getDayOfYear() {
+ return getMonth().firstDayOfYear(isLeapYear()) + day - 1;
+ }
+
+ /**
+ * Gets the day-of-week field, which is an enum {@code DayOfWeek}.
+ *
+ * This method returns the enum {@link DayOfWeek} for the day-of-week.
+ * This avoids confusion as to what {@code int} values mean.
+ * If you need access to the primitive {@code int} value then the enum
+ * provides the {@link DayOfWeek#getValue() int value}.
+ *
+ * Additional information can be obtained from the {@code DayOfWeek}.
+ * This includes textual names of the values.
+ *
+ * @return the day-of-week, not null
+ */
+ public DayOfWeek getDayOfWeek() {
+ int dow0 = (int)Math.floorMod(toEpochDay() + 3, 7);
+ return DayOfWeek.of(dow0 + 1);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks if the year is a leap year, according to the ISO proleptic
+ * calendar system rules.
+ *
+ * This method applies the current rules for leap years across the whole time-line.
+ * In general, a year is a leap year if it is divisible by four without
+ * remainder. However, years divisible by 100, are not leap years, with
+ * the exception of years divisible by 400 which are.
+ *
+ * For example, 1904 is a leap year it is divisible by 4.
+ * 1900 was not a leap year as it is divisible by 100, however 2000 was a
+ * leap year as it is divisible by 400.
+ *
+ * The calculation is proleptic - applying the same rules into the far future and far past.
+ * This is historically inaccurate, but is correct for the ISO-8601 standard.
+ *
+ * @return true if the year is leap, false otherwise
+ */
+ @Override // override for Javadoc and performance
+ public boolean isLeapYear() {
+ return ISOChrono.INSTANCE.isLeapYear(year);
+ }
+
+ /**
+ * Returns the length of the month represented by this date.
+ *
+ * This returns the length of the month in days.
+ * For example, a date in January would return 31.
+ *
+ * @return the length of the month in days
+ */
+ @Override
+ public int lengthOfMonth() {
+ switch (month) {
+ case 2:
+ return (isLeapYear() ? 29 : 28);
+ case 4:
+ case 6:
+ case 9:
+ case 11:
+ return 30;
+ default:
+ return 31;
+ }
+ }
+
+ /**
+ * Returns the length of the year represented by this date.
+ *
+ * This returns the length of the year in days, either 365 or 366.
+ *
+ * @return 366 if the year is leap, 365 otherwise
+ */
+ @Override // override for Javadoc and performance
+ public int lengthOfYear() {
+ return (isLeapYear() ? 366 : 365);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns an adjusted copy of this date.
+ *
+ * This returns a new {@code LocalDate}, based on this one, with the date adjusted.
+ * The adjustment takes place using the specified adjuster strategy object.
+ * Read the documentation of the adjuster to understand what adjustment will be made.
+ *
+ * A simple adjuster might simply set the one of the fields, such as the year field.
+ * A more complex adjuster might set the date to the last day of the month.
+ * A selection of common adjustments is provided in {@link java.time.temporal.Adjusters}.
+ * These include finding the "last day of the month" and "next Wednesday".
+ * Key date-time classes also implement the {@code TemporalAdjuster} interface,
+ * such as {@link Month} and {@link java.time.temporal.MonthDay MonthDay}.
+ * The adjuster is responsible for handling special cases, such as the varying
+ * lengths of month and leap years.
+ *
+ * For example this code returns a date on the last day of July:
+ *
+ * The result of this method is obtained by invoking the
+ * {@link TemporalAdjuster#adjustInto(Temporal)} method on the
+ * specified adjuster passing {@code this} as the argument.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param adjuster the adjuster to use, not null
+ * @return a {@code LocalDate} based on {@code this} with the adjustment made, not null
+ * @throws DateTimeException if the adjustment cannot be made
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public LocalDate with(TemporalAdjuster adjuster) {
+ // optimizations
+ if (adjuster instanceof LocalDate) {
+ return (LocalDate) adjuster;
+ }
+ return (LocalDate) adjuster.adjustInto(this);
+ }
+
+ /**
+ * Returns a copy of this date with the specified field set to a new value.
+ *
+ * This returns a new {@code LocalDate}, based on this one, with the value
+ * for the specified field changed.
+ * This can be used to change any supported field, such as the year, month or day-of-month.
+ * If it is not possible to set the value, because the field is not supported or for
+ * some other reason, an exception is thrown.
+ *
+ * In some cases, changing the specified field can cause the resulting date to become invalid,
+ * such as changing the month from 31st January to February would make the day-of-month invalid.
+ * In cases like this, the field is responsible for resolving the date. Typically it will choose
+ * the previous valid date, which would be the last valid day of February in this example.
+ *
+ * If the field is a {@link ChronoField} then the adjustment is implemented here.
+ * The supported fields behave as follows:
+ *
+ * In all cases, if the new value is outside the valid range of values for the field
+ * then a {@code DateTimeException} will be thrown.
+ *
+ * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doWith(Temporal, long)}
+ * passing {@code this} as the argument. In this case, the field determines
+ * whether and how to adjust the instant.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param field the field to set in the result, not null
+ * @param newValue the new value of the field in the result
+ * @return a {@code LocalDate} based on {@code this} with the specified field set, not null
+ * @throws DateTimeException if the field cannot be set
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public LocalDate with(TemporalField field, long newValue) {
+ if (field instanceof ChronoField) {
+ ChronoField f = (ChronoField) field;
+ f.checkValidValue(newValue);
+ switch (f) {
+ case DAY_OF_WEEK: return plusDays(newValue - getDayOfWeek().getValue());
+ case ALIGNED_DAY_OF_WEEK_IN_MONTH: return plusDays(newValue - getLong(ALIGNED_DAY_OF_WEEK_IN_MONTH));
+ case ALIGNED_DAY_OF_WEEK_IN_YEAR: return plusDays(newValue - getLong(ALIGNED_DAY_OF_WEEK_IN_YEAR));
+ case DAY_OF_MONTH: return withDayOfMonth((int) newValue);
+ case DAY_OF_YEAR: return withDayOfYear((int) newValue);
+ case EPOCH_DAY: return LocalDate.ofEpochDay(newValue);
+ case ALIGNED_WEEK_OF_MONTH: return plusWeeks(newValue - getLong(ALIGNED_WEEK_OF_MONTH));
+ case ALIGNED_WEEK_OF_YEAR: return plusWeeks(newValue - getLong(ALIGNED_WEEK_OF_YEAR));
+ case MONTH_OF_YEAR: return withMonth((int) newValue);
+ case EPOCH_MONTH: return plusMonths(newValue - getLong(EPOCH_MONTH));
+ case YEAR_OF_ERA: return withYear((int) (year >= 1 ? newValue : 1 - newValue));
+ case YEAR: return withYear((int) newValue);
+ case ERA: return (getLong(ERA) == newValue ? this : withYear(1 - year));
+ }
+ throw new DateTimeException("Unsupported field: " + field.getName());
+ }
+ return field.doWith(this, newValue);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this date with the year altered.
+ * If the day-of-month is invalid for the year, it will be changed to the last valid day of the month.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param year the year to set in the result, from MIN_YEAR to MAX_YEAR
+ * @return a {@code LocalDate} based on this date with the requested year, not null
+ * @throws DateTimeException if the year value is invalid
+ */
+ public LocalDate withYear(int year) {
+ if (this.year == year) {
+ return this;
+ }
+ YEAR.checkValidValue(year);
+ return resolvePreviousValid(year, month, day);
+ }
+
+ /**
+ * Returns a copy of this date with the month-of-year altered.
+ * If the day-of-month is invalid for the year, it will be changed to the last valid day of the month.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param month the month-of-year to set in the result, from 1 (January) to 12 (December)
+ * @return a {@code LocalDate} based on this date with the requested month, not null
+ * @throws DateTimeException if the month-of-year value is invalid
+ */
+ public LocalDate withMonth(int month) {
+ if (this.month == month) {
+ return this;
+ }
+ MONTH_OF_YEAR.checkValidValue(month);
+ return resolvePreviousValid(year, month, day);
+ }
+
+ /**
+ * Returns a copy of this date with the day-of-month altered.
+ * If the resulting date is invalid, an exception is thrown.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param dayOfMonth the day-of-month to set in the result, from 1 to 28-31
+ * @return a {@code LocalDate} based on this date with the requested day, not null
+ * @throws DateTimeException if the day-of-month value is invalid
+ * @throws DateTimeException if the day-of-month is invalid for the month-year
+ */
+ public LocalDate withDayOfMonth(int dayOfMonth) {
+ if (this.day == dayOfMonth) {
+ return this;
+ }
+ return of(year, month, dayOfMonth);
+ }
+
+ /**
+ * Returns a copy of this date with the day-of-year altered.
+ * If the resulting date is invalid, an exception is thrown.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param dayOfYear the day-of-year to set in the result, from 1 to 365-366
+ * @return a {@code LocalDate} based on this date with the requested day, not null
+ * @throws DateTimeException if the day-of-year value is invalid
+ * @throws DateTimeException if the day-of-year is invalid for the year
+ */
+ public LocalDate withDayOfYear(int dayOfYear) {
+ if (this.getDayOfYear() == dayOfYear) {
+ return this;
+ }
+ return ofYearDay(year, dayOfYear);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this date with the specified period added.
+ *
+ * This method returns a new date based on this date with the specified period added.
+ * The adder is typically {@link Period} but may be any other type implementing
+ * the {@link TemporalAdder} interface.
+ * The calculation is delegated to the specified adjuster, which typically calls
+ * back to {@link #plus(long, TemporalUnit)}.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param adder the adder to use, not null
+ * @return a {@code LocalDate} based on this date with the addition made, not null
+ * @throws DateTimeException if the addition cannot be made
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public LocalDate plus(TemporalAdder adder) {
+ return (LocalDate) adder.addTo(this);
+ }
+
+ /**
+ * Returns a copy of this date with the specified period added.
+ *
+ * This method returns a new date based on this date with the specified period added.
+ * This can be used to add any period that is defined by a unit, for example to add years, months or days.
+ * The unit is responsible for the details of the calculation, including the resolution
+ * of any edge cases in the calculation.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param amountToAdd the amount of the unit to add to the result, may be negative
+ * @param unit the unit of the period to add, not null
+ * @return a {@code LocalDate} based on this date with the specified period added, not null
+ * @throws DateTimeException if the unit cannot be added to this type
+ */
+ @Override
+ public LocalDate plus(long amountToAdd, TemporalUnit unit) {
+ if (unit instanceof ChronoUnit) {
+ ChronoUnit f = (ChronoUnit) unit;
+ switch (f) {
+ case DAYS: return plusDays(amountToAdd);
+ case WEEKS: return plusWeeks(amountToAdd);
+ case MONTHS: return plusMonths(amountToAdd);
+ case YEARS: return plusYears(amountToAdd);
+ case DECADES: return plusYears(Math.multiplyExact(amountToAdd, 10));
+ case CENTURIES: return plusYears(Math.multiplyExact(amountToAdd, 100));
+ case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000));
+ case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd));
+ }
+ throw new DateTimeException("Unsupported unit: " + unit.getName());
+ }
+ return unit.doPlus(this, amountToAdd);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this {@code LocalDate} with the specified period in years added.
+ *
+ * This method adds the specified amount to the years field in three steps:
+ *
+ * For example, 2008-02-29 (leap year) plus one year would result in the
+ * invalid date 2009-02-29 (standard year). Instead of returning an invalid
+ * result, the last valid day of the month, 2009-02-28, is selected instead.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param yearsToAdd the years to add, may be negative
+ * @return a {@code LocalDate} based on this date with the years added, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public LocalDate plusYears(long yearsToAdd) {
+ if (yearsToAdd == 0) {
+ return this;
+ }
+ int newYear = YEAR.checkValidIntValue(year + yearsToAdd); // safe overflow
+ return resolvePreviousValid(newYear, month, day);
+ }
+
+ /**
+ * Returns a copy of this {@code LocalDate} with the specified period in months added.
+ *
+ * This method adds the specified amount to the months field in three steps:
+ *
+ * For example, 2007-03-31 plus one month would result in the invalid date
+ * 2007-04-31. Instead of returning an invalid result, the last valid day
+ * of the month, 2007-04-30, is selected instead.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param monthsToAdd the months to add, may be negative
+ * @return a {@code LocalDate} based on this date with the months added, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public LocalDate plusMonths(long monthsToAdd) {
+ if (monthsToAdd == 0) {
+ return this;
+ }
+ long monthCount = year * 12L + (month - 1);
+ long calcMonths = monthCount + monthsToAdd; // safe overflow
+ int newYear = YEAR.checkValidIntValue(Math.floorDiv(calcMonths, 12));
+ int newMonth = (int)Math.floorMod(calcMonths, 12) + 1;
+ return resolvePreviousValid(newYear, newMonth, day);
+ }
+
+ /**
+ * Returns a copy of this {@code LocalDate} with the specified period in weeks added.
+ *
+ * This method adds the specified amount in weeks to the days field incrementing
+ * the month and year fields as necessary to ensure the result remains valid.
+ * The result is only invalid if the maximum/minimum year is exceeded.
+ *
+ * For example, 2008-12-31 plus one week would result in 2009-01-07.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param weeksToAdd the weeks to add, may be negative
+ * @return a {@code LocalDate} based on this date with the weeks added, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public LocalDate plusWeeks(long weeksToAdd) {
+ return plusDays(Math.multiplyExact(weeksToAdd, 7));
+ }
+
+ /**
+ * Returns a copy of this {@code LocalDate} with the specified number of days added.
+ *
+ * This method adds the specified amount to the days field incrementing the
+ * month and year fields as necessary to ensure the result remains valid.
+ * The result is only invalid if the maximum/minimum year is exceeded.
+ *
+ * For example, 2008-12-31 plus one day would result in 2009-01-01.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param daysToAdd the days to add, may be negative
+ * @return a {@code LocalDate} based on this date with the days added, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public LocalDate plusDays(long daysToAdd) {
+ if (daysToAdd == 0) {
+ return this;
+ }
+ long mjDay = Math.addExact(toEpochDay(), daysToAdd);
+ return LocalDate.ofEpochDay(mjDay);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this date with the specified period subtracted.
+ *
+ * This method returns a new date based on this date with the specified period subtracted.
+ * The subtractor is typically {@link Period} but may be any other type implementing
+ * the {@link TemporalSubtractor} interface.
+ * The calculation is delegated to the specified adjuster, which typically calls
+ * back to {@link #minus(long, TemporalUnit)}.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param subtractor the subtractor to use, not null
+ * @return a {@code LocalDate} based on this date with the subtraction made, not null
+ * @throws DateTimeException if the subtraction cannot be made
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public LocalDate minus(TemporalSubtractor subtractor) {
+ return (LocalDate) subtractor.subtractFrom(this);
+ }
+
+ /**
+ * Returns a copy of this date with the specified period subtracted.
+ *
+ * This method returns a new date based on this date with the specified period subtracted.
+ * This can be used to subtract any period that is defined by a unit, for example to subtract years, months or days.
+ * The unit is responsible for the details of the calculation, including the resolution
+ * of any edge cases in the calculation.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param amountToSubtract the amount of the unit to subtract from the result, may be negative
+ * @param unit the unit of the period to subtract, not null
+ * @return a {@code LocalDate} based on this date with the specified period subtracted, not null
+ * @throws DateTimeException if the unit cannot be added to this type
+ */
+ @Override
+ public LocalDate minus(long amountToSubtract, TemporalUnit unit) {
+ return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this {@code LocalDate} with the specified period in years subtracted.
+ *
+ * This method subtracts the specified amount from the years field in three steps:
+ *
+ * For example, 2008-02-29 (leap year) minus one year would result in the
+ * invalid date 2007-02-29 (standard year). Instead of returning an invalid
+ * result, the last valid day of the month, 2007-02-28, is selected instead.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param yearsToSubtract the years to subtract, may be negative
+ * @return a {@code LocalDate} based on this date with the years subtracted, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public LocalDate minusYears(long yearsToSubtract) {
+ return (yearsToSubtract == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-yearsToSubtract));
+ }
+
+ /**
+ * Returns a copy of this {@code LocalDate} with the specified period in months subtracted.
+ *
+ * This method subtracts the specified amount from the months field in three steps:
+ *
+ * For example, 2007-03-31 minus one month would result in the invalid date
+ * 2007-02-31. Instead of returning an invalid result, the last valid day
+ * of the month, 2007-02-28, is selected instead.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param monthsToSubtract the months to subtract, may be negative
+ * @return a {@code LocalDate} based on this date with the months subtracted, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public LocalDate minusMonths(long monthsToSubtract) {
+ return (monthsToSubtract == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-monthsToSubtract));
+ }
+
+ /**
+ * Returns a copy of this {@code LocalDate} with the specified period in weeks subtracted.
+ *
+ * This method subtracts the specified amount in weeks from the days field decrementing
+ * the month and year fields as necessary to ensure the result remains valid.
+ * The result is only invalid if the maximum/minimum year is exceeded.
+ *
+ * For example, 2009-01-07 minus one week would result in 2008-12-31.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param weeksToSubtract the weeks to subtract, may be negative
+ * @return a {@code LocalDate} based on this date with the weeks subtracted, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public LocalDate minusWeeks(long weeksToSubtract) {
+ return (weeksToSubtract == Long.MIN_VALUE ? plusWeeks(Long.MAX_VALUE).plusWeeks(1) : plusWeeks(-weeksToSubtract));
+ }
+
+ /**
+ * Returns a copy of this {@code LocalDate} with the specified number of days subtracted.
+ *
+ * This method subtracts the specified amount from the days field decrementing the
+ * month and year fields as necessary to ensure the result remains valid.
+ * The result is only invalid if the maximum/minimum year is exceeded.
+ *
+ * For example, 2009-01-01 minus one day would result in 2008-12-31.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param daysToSubtract the days to subtract, may be negative
+ * @return a {@code LocalDate} based on this date with the days subtracted, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public LocalDate minusDays(long daysToSubtract) {
+ return (daysToSubtract == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-daysToSubtract));
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Queries this date using the specified query.
+ *
+ * This queries this date using the specified query strategy object.
+ * The {@code TemporalQuery} object defines the logic to be used to
+ * obtain the result. Read the documentation of the query to understand
+ * what the result of this method will be.
+ *
+ * The result of this method is obtained by invoking the
+ * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
+ * specified query passing {@code this} as the argument.
+ *
+ * @param
+ * This returns a temporal object of the same observable type as the input
+ * with the date changed to be the same as this.
+ *
+ * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+ * passing {@link ChronoField#EPOCH_DAY} as the field.
+ *
+ * In most cases, it is clearer to reverse the calling pattern by using
+ * {@link Temporal#with(TemporalAdjuster)}:
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param temporal the target object to be adjusted, not null
+ * @return the adjusted object, not null
+ * @throws DateTimeException if unable to make the adjustment
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override // override for Javadoc
+ public Temporal adjustInto(Temporal temporal) {
+ return ChronoLocalDate.super.adjustInto(temporal);
+ }
+
+ /**
+ * Calculates the period between this date and another date in
+ * terms of the specified unit.
+ *
+ * This calculates the period between two dates in terms of a single unit.
+ * The start and end points are {@code this} and the specified date.
+ * The result will be negative if the end is before the start.
+ * The {@code Temporal} passed to this method must be a {@code LocalDate}.
+ * For example, the period in days between two dates can be calculated
+ * using {@code startDate.periodUntil(endDate, DAYS)}.
+ *
+ * The calculation returns a whole number, representing the number of
+ * complete units between the two dates.
+ * For example, the period in months between 2012-06-15 and 2012-08-14
+ * will only be one month as it is one day short of two months.
+ *
+ * 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:
+ *
+ * The calculation is implemented in this method for {@link ChronoUnit}.
+ * The units {@code DAYS}, {@code WEEKS}, {@code MONTHS}, {@code YEARS},
+ * {@code DECADES}, {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS}
+ * are supported. Other {@code ChronoUnit} values will throw an exception.
+ *
+ * If the unit is not a {@code ChronoUnit}, then the result of this method
+ * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
+ * passing {@code this} as the first argument and the input temporal as
+ * the second argument.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param endDate the end date, which must be a {@code LocalDate}, not null
+ * @param unit the unit to measure the period in, not null
+ * @return the amount of the period between this date and the end date
+ * @throws DateTimeException if the period cannot be calculated
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public long periodUntil(Temporal endDate, TemporalUnit unit) {
+ if (endDate instanceof LocalDate == false) {
+ Objects.requireNonNull(endDate, "endDate");
+ throw new DateTimeException("Unable to calculate period between objects of two different types");
+ }
+ LocalDate end = (LocalDate) endDate;
+ if (unit instanceof ChronoUnit) {
+ switch ((ChronoUnit) unit) {
+ case DAYS: return daysUntil(end);
+ case WEEKS: return daysUntil(end) / 7;
+ case MONTHS: return monthsUntil(end);
+ case YEARS: return monthsUntil(end) / 12;
+ case DECADES: return monthsUntil(end) / 120;
+ case CENTURIES: return monthsUntil(end) / 1200;
+ case MILLENNIA: return monthsUntil(end) / 12000;
+ case ERAS: return end.getLong(ERA) - getLong(ERA);
+ }
+ throw new DateTimeException("Unsupported unit: " + unit.getName());
+ }
+ return unit.between(this, endDate).getAmount();
+ }
+
+ long daysUntil(LocalDate end) {
+ return end.toEpochDay() - toEpochDay(); // no overflow
+ }
+
+ private long monthsUntil(LocalDate end) {
+ long packed1 = getEpochMonth() * 32L + getDayOfMonth(); // no overflow
+ long packed2 = end.getEpochMonth() * 32L + end.getDayOfMonth(); // no overflow
+ return (packed2 - packed1) / 32;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a local date-time formed from this date at the specified time.
+ *
+ * This combines this date with the specified time to form a {@code LocalDateTime}.
+ * All possible combinations of date and time are valid.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param time the time to combine with, not null
+ * @return the local date-time formed from this date and the specified time, not null
+ */
+ @Override
+ public LocalDateTime atTime(LocalTime time) {
+ return LocalDateTime.of(this, time);
+ }
+
+ /**
+ * Returns a local date-time formed from this date at the specified time.
+ *
+ * This combines this date with the specified time to form a {@code LocalDateTime}.
+ * The individual time fields must be within their valid range.
+ * All possible combinations of date and time are valid.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param hour the hour-of-day to use, from 0 to 23
+ * @param minute the minute-of-hour to use, from 0 to 59
+ * @return the local date-time formed from this date and the specified time, not null
+ * @throws DateTimeException if the value of any field is out of range
+ */
+ public LocalDateTime atTime(int hour, int minute) {
+ return atTime(LocalTime.of(hour, minute));
+ }
+
+ /**
+ * Returns a local date-time formed from this date at the specified time.
+ *
+ * This combines this date with the specified time to form a {@code LocalDateTime}.
+ * The individual time fields must be within their valid range.
+ * All possible combinations of date and time are valid.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param hour the hour-of-day to use, from 0 to 23
+ * @param minute the minute-of-hour to use, from 0 to 59
+ * @param second the second-of-minute to represent, from 0 to 59
+ * @return the local date-time formed from this date and the specified time, not null
+ * @throws DateTimeException if the value of any field is out of range
+ */
+ public LocalDateTime atTime(int hour, int minute, int second) {
+ return atTime(LocalTime.of(hour, minute, second));
+ }
+
+ /**
+ * Returns a local date-time formed from this date at the specified time.
+ *
+ * This combines this date with the specified time to form a {@code LocalDateTime}.
+ * The individual time fields must be within their valid range.
+ * All possible combinations of date and time are valid.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param hour the hour-of-day to use, from 0 to 23
+ * @param minute the minute-of-hour to use, from 0 to 59
+ * @param second the second-of-minute to represent, from 0 to 59
+ * @param nanoOfSecond the nano-of-second to represent, from 0 to 999,999,999
+ * @return the local date-time formed from this date and the specified time, not null
+ * @throws DateTimeException if the value of any field is out of range
+ */
+ public LocalDateTime atTime(int hour, int minute, int second, int nanoOfSecond) {
+ return atTime(LocalTime.of(hour, minute, second, nanoOfSecond));
+ }
+
+ /**
+ * Returns an offset date formed from this date and the specified offset.
+ *
+ * This combines this date with the specified offset to form an {@code OffsetDate}.
+ * All possible combinations of date and offset are valid.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param offset the offset to combine with, not null
+ * @return the offset date formed from this date and the specified offset, not null
+ */
+ public OffsetDate atOffset(ZoneOffset offset) {
+ return OffsetDate.of(this, offset);
+ }
+
+ /**
+ * Returns a zoned date-time from this date at the earliest valid time according
+ * to the rules in the time-zone.
+ *
+ * Time-zone rules, such as daylight savings, mean that not every local date-time
+ * is valid for the specified zone, thus the local date-time may not be midnight.
+ *
+ * In most cases, there is only one valid offset for a local date-time.
+ * In the case of an overlap, there are two valid offsets, and the earlier one is used,
+ * corresponding to the first occurrence of midnight on the date.
+ * In the case of a gap, the zoned date-time will represent the instant just after the gap.
+ *
+ * If the zone ID is a {@link ZoneOffset}, then the result always has a time of midnight.
+ *
+ * To convert to a specific time in a given time-zone call {@link #atTime(LocalTime)}
+ * followed by {@link LocalDateTime#atZone(ZoneId)}.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param zone the zone ID to use, not null
+ * @return the zoned date-time formed from this date and the earliest valid time for the zone, not null
+ */
+ public ZonedDateTime atStartOfDay(ZoneId zone) {
+ Objects.requireNonNull(zone, "zone");
+ // need to handle case where there is a gap from 11:30 to 00:30
+ // standard ZDT factory would result in 01:00 rather than 00:30
+ LocalDateTime ldt = atTime(LocalTime.MIDNIGHT);
+ if (zone instanceof ZoneOffset == false) {
+ ZoneRules rules = zone.getRules();
+ ZoneOffsetTransition trans = rules.getTransition(ldt);
+ if (trans != null && trans.isGap()) {
+ ldt = trans.getDateTimeAfter();
+ }
+ }
+ return ZonedDateTime.of(ldt, zone);
+ }
+
+ //-----------------------------------------------------------------------
+ @Override
+ public long toEpochDay() {
+ long y = year;
+ long m = month;
+ long total = 0;
+ total += 365 * y;
+ if (y >= 0) {
+ total += (y + 3) / 4 - (y + 99) / 100 + (y + 399) / 400;
+ } else {
+ total -= y / -4 - y / -100 + y / -400;
+ }
+ total += ((367 * m - 362) / 12);
+ total += day - 1;
+ if (m > 2) {
+ total--;
+ if (isLeapYear() == false) {
+ total--;
+ }
+ }
+ return total - DAYS_0000_TO_1970;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Compares this date to another date.
+ *
+ * The comparison is primarily based on the date, from earliest to latest.
+ * It is "consistent with equals", as defined by {@link Comparable}.
+ *
+ * If all the dates being compared are instances of {@code LocalDate},
+ * then the comparison will be entirely based on the date.
+ * If some dates being compared are in different chronologies, then the
+ * chronology is also considered, see {@link java.time.temporal.ChronoLocalDate#compareTo}.
+ *
+ * @param other the other date to compare to, not null
+ * @return the comparator value, negative if less, positive if greater
+ */
+ @Override // override for Javadoc and performance
+ public int compareTo(ChronoLocalDate> other) {
+ if (other instanceof LocalDate) {
+ return compareTo0((LocalDate) other);
+ }
+ return ChronoLocalDate.super.compareTo(other);
+ }
+
+ int compareTo0(LocalDate otherDate) {
+ int cmp = (year - otherDate.year);
+ if (cmp == 0) {
+ cmp = (month - otherDate.month);
+ if (cmp == 0) {
+ cmp = (day - otherDate.day);
+ }
+ }
+ return cmp;
+ }
+
+ /**
+ * Checks if this date is after the specified date.
+ *
+ * This checks to see if this date represents a point on the
+ * local time-line after the other date.
+ *
+ * This method only considers the position of the two dates on the local time-line.
+ * It does not take into account the chronology, or calendar system.
+ * This is different from the comparison in {@link #compareTo(ChronoLocalDate)},
+ * but is the same approach as {@link #DATE_COMPARATOR}.
+ *
+ * @param other the other date to compare to, not null
+ * @return true if this date is after the specified date
+ */
+ @Override // override for Javadoc and performance
+ public boolean isAfter(ChronoLocalDate> other) {
+ if (other instanceof LocalDate) {
+ return compareTo0((LocalDate) other) > 0;
+ }
+ return ChronoLocalDate.super.isAfter(other);
+ }
+
+ /**
+ * Checks if this date is before the specified date.
+ *
+ * This checks to see if this date represents a point on the
+ * local time-line before the other date.
+ *
+ * This method only considers the position of the two dates on the local time-line.
+ * It does not take into account the chronology, or calendar system.
+ * This is different from the comparison in {@link #compareTo(ChronoLocalDate)},
+ * but is the same approach as {@link #DATE_COMPARATOR}.
+ *
+ * @param other the other date to compare to, not null
+ * @return true if this date is before the specified date
+ */
+ @Override // override for Javadoc and performance
+ public boolean isBefore(ChronoLocalDate> other) {
+ if (other instanceof LocalDate) {
+ return compareTo0((LocalDate) other) < 0;
+ }
+ return ChronoLocalDate.super.isBefore(other);
+ }
+
+ /**
+ * Checks if this date is equal to the specified date.
+ *
+ * This checks to see if this date represents the same point on the
+ * local time-line as the other date.
+ *
+ * This method only considers the position of the two dates on the local time-line.
+ * It does not take into account the chronology, or calendar system.
+ * This is different from the comparison in {@link #compareTo(ChronoLocalDate)}
+ * but is the same approach as {@link #DATE_COMPARATOR}.
+ *
+ * @param other the other date to compare to, not null
+ * @return true if this date is equal to the specified date
+ */
+ @Override // override for Javadoc and performance
+ public boolean isEqual(ChronoLocalDate> other) {
+ if (other instanceof LocalDate) {
+ return compareTo0((LocalDate) other) == 0;
+ }
+ return ChronoLocalDate.super.isEqual(other);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks if this date is equal to another date.
+ *
+ * Compares this {@code LocalDate} with another ensuring that the date is the same.
+ *
+ * Only objects of type {@code LocalDate} are compared, other types return false.
+ * To compare the dates of two {@code TemporalAccessor} instances, including dates
+ * in two different chronologies, use {@link ChronoField#EPOCH_DAY} as a comparator.
+ *
+ * @param obj the object to check, null returns false
+ * @return true if this is equal to the other date
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof LocalDate) {
+ return compareTo0((LocalDate) obj) == 0;
+ }
+ return false;
+ }
+
+ /**
+ * A hash code for this date.
+ *
+ * @return a suitable hash code
+ */
+ @Override
+ public int hashCode() {
+ int yearValue = year;
+ int monthValue = month;
+ int dayValue = day;
+ return (yearValue & 0xFFFFF800) ^ ((yearValue << 11) + (monthValue << 6) + (dayValue));
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Outputs this date as a {@code String}, such as {@code 2007-12-03}.
+ *
+ * The output will be in the ISO-8601 format {@code yyyy-MM-dd}.
+ *
+ * @return a string representation of this date, not null
+ */
+ @Override
+ public String toString() {
+ int yearValue = year;
+ int monthValue = month;
+ int dayValue = day;
+ int absYear = Math.abs(yearValue);
+ StringBuilder buf = new StringBuilder(10);
+ if (absYear < 1000) {
+ if (yearValue < 0) {
+ buf.append(yearValue - 10000).deleteCharAt(1);
+ } else {
+ buf.append(yearValue + 10000).deleteCharAt(0);
+ }
+ } else {
+ if (yearValue > 9999) {
+ buf.append('+');
+ }
+ buf.append(yearValue);
+ }
+ return buf.append(monthValue < 10 ? "-0" : "-")
+ .append(monthValue)
+ .append(dayValue < 10 ? "-0" : "-")
+ .append(dayValue)
+ .toString();
+ }
+
+ /**
+ * Outputs this date as a {@code String} using the formatter.
+ *
+ * This date will be passed to the formatter
+ * {@link DateTimeFormatter#print(TemporalAccessor) print method}.
+ *
+ * @param formatter the formatter to use, not null
+ * @return the formatted date string, not null
+ * @throws DateTimeException if an error occurs during printing
+ */
+ @Override // override for Javadoc
+ public String toString(DateTimeFormatter formatter) {
+ return ChronoLocalDate.super.toString(formatter);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Writes the object using a
+ * dedicated serialized form.
+ *
+ * {@code LocalDateTime} is an immutable date-time object that represents a date-time,
+ * often viewed as year-month-day-hour-minute-second. Other date and time fields,
+ * such as day-of-year, day-of-week and week-of-year, can also be accessed.
+ * Time is represented to nanosecond precision.
+ * For example, the value "2nd October 2007 at 13:45.30.123456789" can be
+ * stored in a {@code LocalDateTime}.
+ *
+ * This class does not store or represent a time-zone.
+ * Instead, it is a description of the date, as used for birthdays, combined with
+ * the local time as seen on a wall clock.
+ * It cannot represent an instant on the time-line without additional information
+ * such as an offset or time-zone.
+ *
+ * The ISO-8601 calendar system is the modern civil calendar system used today
+ * in most of the world. It is equivalent to the proleptic Gregorian calendar
+ * system, in which today's rules for leap years are applied for all time.
+ * For most applications written today, the ISO-8601 rules are entirely suitable.
+ * However, any application that makes use of historical dates, and requires them
+ * to be accurate will find the ISO-8601 approach unsuitable.
+ *
+ *
+ * This will query the {@link Clock#systemDefaultZone() system clock} in the default
+ * time-zone to obtain the current date-time.
+ *
+ * Using this method will prevent the ability to use an alternate clock for testing
+ * because the clock is hard-coded.
+ *
+ * @return the current date-time using the system clock and default time-zone, not null
+ */
+ public static LocalDateTime now() {
+ return now(Clock.systemDefaultZone());
+ }
+
+ /**
+ * Obtains the current date-time from the system clock in the specified time-zone.
+ *
+ * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date-time.
+ * Specifying the time-zone avoids dependence on the default time-zone.
+ *
+ * Using this method will prevent the ability to use an alternate clock for testing
+ * because the clock is hard-coded.
+ *
+ * @param zone the zone ID to use, not null
+ * @return the current date-time using the system clock, not null
+ */
+ public static LocalDateTime now(ZoneId zone) {
+ return now(Clock.system(zone));
+ }
+
+ /**
+ * Obtains the current date-time from the specified clock.
+ *
+ * This will query the specified clock to obtain the current date-time.
+ * Using this method allows the use of an alternate clock for testing.
+ * The alternate clock may be introduced using {@link Clock dependency injection}.
+ *
+ * @param clock the clock to use, not null
+ * @return the current date-time, not null
+ */
+ public static LocalDateTime now(Clock clock) {
+ Objects.requireNonNull(clock, "clock");
+ final Instant now = clock.instant(); // called once
+ ZoneOffset offset = clock.getZone().getRules().getOffset(now);
+ return ofEpochSecond(now.getEpochSecond(), now.getNano(), offset);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code LocalDateTime} from year, month,
+ * day, hour and minute, setting the second and nanosecond to zero.
+ *
+ * The day must be valid for the year and month, otherwise an exception will be thrown.
+ * The second and nanosecond fields will be set to zero.
+ *
+ * @param year the year to represent, from MIN_YEAR to MAX_YEAR
+ * @param month the month-of-year to represent, not null
+ * @param dayOfMonth the day-of-month to represent, from 1 to 31
+ * @param hour the hour-of-day to represent, from 0 to 23
+ * @param minute the minute-of-hour to represent, from 0 to 59
+ * @return the local date-time, not null
+ * @throws DateTimeException if the value of any field is out of range
+ * @throws DateTimeException if the day-of-month is invalid for the month-year
+ */
+ public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute) {
+ LocalDate date = LocalDate.of(year, month, dayOfMonth);
+ LocalTime time = LocalTime.of(hour, minute);
+ return new LocalDateTime(date, time);
+ }
+
+ /**
+ * Obtains an instance of {@code LocalDateTime} from year, month,
+ * day, hour, minute and second, setting the nanosecond to zero.
+ *
+ * The day must be valid for the year and month, otherwise an exception will be thrown.
+ * The nanosecond field will be set to zero.
+ *
+ * @param year the year to represent, from MIN_YEAR to MAX_YEAR
+ * @param month the month-of-year to represent, not null
+ * @param dayOfMonth the day-of-month to represent, from 1 to 31
+ * @param hour the hour-of-day to represent, from 0 to 23
+ * @param minute the minute-of-hour to represent, from 0 to 59
+ * @param second the second-of-minute to represent, from 0 to 59
+ * @return the local date-time, not null
+ * @throws DateTimeException if the value of any field is out of range
+ * @throws DateTimeException if the day-of-month is invalid for the month-year
+ */
+ public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute, int second) {
+ LocalDate date = LocalDate.of(year, month, dayOfMonth);
+ LocalTime time = LocalTime.of(hour, minute, second);
+ return new LocalDateTime(date, time);
+ }
+
+ /**
+ * Obtains an instance of {@code LocalDateTime} from year, month,
+ * day, hour, minute, second and nanosecond.
+ *
+ * The day must be valid for the year and month, otherwise an exception will be thrown.
+ *
+ * @param year the year to represent, from MIN_YEAR to MAX_YEAR
+ * @param month the month-of-year to represent, not null
+ * @param dayOfMonth the day-of-month to represent, from 1 to 31
+ * @param hour the hour-of-day to represent, from 0 to 23
+ * @param minute the minute-of-hour to represent, from 0 to 59
+ * @param second the second-of-minute to represent, from 0 to 59
+ * @param nanoOfSecond the nano-of-second to represent, from 0 to 999,999,999
+ * @return the local date-time, not null
+ * @throws DateTimeException if the value of any field is out of range
+ * @throws DateTimeException if the day-of-month is invalid for the month-year
+ */
+ public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond) {
+ LocalDate date = LocalDate.of(year, month, dayOfMonth);
+ LocalTime time = LocalTime.of(hour, minute, second, nanoOfSecond);
+ return new LocalDateTime(date, time);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code LocalDateTime} from year, month,
+ * day, hour and minute, setting the second and nanosecond to zero.
+ *
+ * The day must be valid for the year and month, otherwise an exception will be thrown.
+ * The second and nanosecond fields will be set to zero.
+ *
+ * @param year the year to represent, from MIN_YEAR to MAX_YEAR
+ * @param month the month-of-year to represent, from 1 (January) to 12 (December)
+ * @param dayOfMonth the day-of-month to represent, from 1 to 31
+ * @param hour the hour-of-day to represent, from 0 to 23
+ * @param minute the minute-of-hour to represent, from 0 to 59
+ * @return the local date-time, not null
+ * @throws DateTimeException if the value of any field is out of range
+ * @throws DateTimeException if the day-of-month is invalid for the month-year
+ */
+ public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute) {
+ LocalDate date = LocalDate.of(year, month, dayOfMonth);
+ LocalTime time = LocalTime.of(hour, minute);
+ return new LocalDateTime(date, time);
+ }
+
+ /**
+ * Obtains an instance of {@code LocalDateTime} from year, month,
+ * day, hour, minute and second, setting the nanosecond to zero.
+ *
+ * The day must be valid for the year and month, otherwise an exception will be thrown.
+ * The nanosecond field will be set to zero.
+ *
+ * @param year the year to represent, from MIN_YEAR to MAX_YEAR
+ * @param month the month-of-year to represent, from 1 (January) to 12 (December)
+ * @param dayOfMonth the day-of-month to represent, from 1 to 31
+ * @param hour the hour-of-day to represent, from 0 to 23
+ * @param minute the minute-of-hour to represent, from 0 to 59
+ * @param second the second-of-minute to represent, from 0 to 59
+ * @return the local date-time, not null
+ * @throws DateTimeException if the value of any field is out of range
+ * @throws DateTimeException if the day-of-month is invalid for the month-year
+ */
+ public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second) {
+ LocalDate date = LocalDate.of(year, month, dayOfMonth);
+ LocalTime time = LocalTime.of(hour, minute, second);
+ return new LocalDateTime(date, time);
+ }
+
+ /**
+ * Obtains an instance of {@code LocalDateTime} from year, month,
+ * day, hour, minute, second and nanosecond.
+ *
+ * The day must be valid for the year and month, otherwise an exception will be thrown.
+ *
+ * @param year the year to represent, from MIN_YEAR to MAX_YEAR
+ * @param month the month-of-year to represent, from 1 (January) to 12 (December)
+ * @param dayOfMonth the day-of-month to represent, from 1 to 31
+ * @param hour the hour-of-day to represent, from 0 to 23
+ * @param minute the minute-of-hour to represent, from 0 to 59
+ * @param second the second-of-minute to represent, from 0 to 59
+ * @param nanoOfSecond the nano-of-second to represent, from 0 to 999,999,999
+ * @return the local date-time, not null
+ * @throws DateTimeException if the value of any field is out of range
+ * @throws DateTimeException if the day-of-month is invalid for the month-year
+ */
+ public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond) {
+ LocalDate date = LocalDate.of(year, month, dayOfMonth);
+ LocalTime time = LocalTime.of(hour, minute, second, nanoOfSecond);
+ return new LocalDateTime(date, time);
+ }
+
+ /**
+ * Obtains an instance of {@code LocalDateTime} from a date and time.
+ *
+ * @param date the local date, not null
+ * @param time the local time, not null
+ * @return the local date-time, not null
+ */
+ public static LocalDateTime of(LocalDate date, LocalTime time) {
+ Objects.requireNonNull(date, "date");
+ Objects.requireNonNull(time, "time");
+ return new LocalDateTime(date, time);
+ }
+
+ //-------------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code LocalDateTime} from an {@code Instant} and zone ID.
+ *
+ * This creates a local date-time based on the specified instant.
+ * First, the offset from UTC/Greenwich is obtained using the zone ID and instant,
+ * which is simple as there is only one valid offset for each instant.
+ * Then, the instant and offset are used to calculate the local date-time.
+ *
+ * @param instant the instant to create the date-time from, not null
+ * @param zone the time-zone, which may be an offset, not null
+ * @return the local date-time, not null
+ * @throws DateTimeException if the result exceeds the supported range
+ */
+ public static LocalDateTime ofInstant(Instant instant, ZoneId zone) {
+ Objects.requireNonNull(instant, "instant");
+ Objects.requireNonNull(zone, "zone");
+ ZoneRules rules = zone.getRules();
+ ZoneOffset offset = rules.getOffset(instant);
+ return ofEpochSecond(instant.getEpochSecond(), instant.getNano(), offset);
+ }
+
+ /**
+ * Obtains an instance of {@code LocalDateTime} using seconds from the
+ * epoch of 1970-01-01T00:00:00Z.
+ *
+ * This allows the {@link ChronoField#INSTANT_SECONDS epoch-second} field
+ * to be converted to a local date-time. This is primarily intended for
+ * low-level conversions rather than general application usage.
+ *
+ * @param epochSecond the number of seconds from the epoch of 1970-01-01T00:00:00Z
+ * @param nanoOfSecond the nanosecond within the second, from 0 to 999,999,999
+ * @param offset the zone offset, not null
+ * @return the local date-time, not null
+ * @throws DateTimeException if the result exceeds the supported range
+ */
+ public static LocalDateTime ofEpochSecond(long epochSecond, int nanoOfSecond, ZoneOffset offset) {
+ Objects.requireNonNull(offset, "offset");
+ long localSecond = epochSecond + offset.getTotalSeconds(); // overflow caught later
+ long localEpochDay = Math.floorDiv(localSecond, SECONDS_PER_DAY);
+ int secsOfDay = (int)Math.floorMod(localSecond, SECONDS_PER_DAY);
+ LocalDate date = LocalDate.ofEpochDay(localEpochDay);
+ LocalTime time = LocalTime.ofSecondOfDay(secsOfDay, nanoOfSecond);
+ return new LocalDateTime(date, time);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code LocalDateTime} from a temporal object.
+ *
+ * A {@code TemporalAccessor} represents some form of date and time information.
+ * This factory converts the arbitrary temporal object to an instance of {@code LocalDateTime}.
+ *
+ * The conversion extracts and combines {@code LocalDate} and {@code LocalTime}.
+ *
+ * This method matches the signature of the functional interface {@link TemporalQuery}
+ * allowing it to be used as a query via method reference, {@code LocalDateTime::from}.
+ *
+ * @param temporal the temporal object to convert, not null
+ * @return the local date-time, not null
+ * @throws DateTimeException if unable to convert to a {@code LocalDateTime}
+ */
+ public static LocalDateTime from(TemporalAccessor temporal) {
+ if (temporal instanceof LocalDateTime) {
+ return (LocalDateTime) temporal;
+ } else if (temporal instanceof ZonedDateTime) {
+ return ((ZonedDateTime) temporal).getDateTime();
+ }
+ try {
+ LocalDate date = LocalDate.from(temporal);
+ LocalTime time = LocalTime.from(temporal);
+ return new LocalDateTime(date, time);
+ } catch (DateTimeException ex) {
+ throw new DateTimeException("Unable to obtain LocalDateTime from TemporalAccessor: " + temporal.getClass(), ex);
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code LocalDateTime} from a text string such as {@code 2007-12-03T10:15:30}.
+ *
+ * The string must represent a valid date-time and is parsed using
+ * {@link java.time.format.DateTimeFormatters#isoLocalDateTime()}.
+ *
+ * @param text the text to parse such as "2007-12-03T10:15:30", not null
+ * @return the parsed local date-time, not null
+ * @throws DateTimeParseException if the text cannot be parsed
+ */
+ public static LocalDateTime parse(CharSequence text) {
+ return parse(text, DateTimeFormatters.isoLocalDateTime());
+ }
+
+ /**
+ * Obtains an instance of {@code LocalDateTime} from a text string using a specific formatter.
+ *
+ * The text is parsed using the formatter, returning a date-time.
+ *
+ * @param text the text to parse, not null
+ * @param formatter the formatter to use, not null
+ * @return the parsed local date-time, not null
+ * @throws DateTimeParseException if the text cannot be parsed
+ */
+ public static LocalDateTime parse(CharSequence text, DateTimeFormatter formatter) {
+ Objects.requireNonNull(formatter, "formatter");
+ return formatter.parse(text, LocalDateTime::from);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Constructor.
+ *
+ * @param date the date part of the date-time, validated not null
+ * @param time the time part of the date-time, validated not null
+ */
+ private LocalDateTime(LocalDate date, LocalTime time) {
+ this.date = date;
+ this.time = time;
+ }
+
+ /**
+ * Returns a copy of this date-time with the new date and time, checking
+ * to see if a new object is in fact required.
+ *
+ * @param newDate the date of the new date-time, not null
+ * @param newTime the time of the new date-time, not null
+ * @return the date-time, not null
+ */
+ private LocalDateTime with(LocalDate newDate, LocalTime newTime) {
+ if (date == newDate && time == newTime) {
+ return this;
+ }
+ return new LocalDateTime(newDate, newTime);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks if the specified field is supported.
+ *
+ * This checks if this date-time can be queried for the specified field.
+ * If false, then calling the {@link #range(TemporalField) range} and
+ * {@link #get(TemporalField) get} methods will throw an exception.
+ *
+ * If the field is a {@link ChronoField} then the query is implemented here.
+ * The supported fields are:
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)}
+ * passing {@code this} as the argument.
+ * Whether the field is supported is determined by the field.
+ *
+ * @param field the field to check, null returns false
+ * @return true if the field is supported on this date-time, false if not
+ */
+ @Override
+ public boolean isSupported(TemporalField field) {
+ if (field instanceof ChronoField) {
+ ChronoField f = (ChronoField) field;
+ return f.isDateField() || f.isTimeField();
+ }
+ return field != null && field.doIsSupported(this);
+ }
+
+ /**
+ * Gets the range of valid values for the specified field.
+ *
+ * The range object expresses the minimum and maximum valid values for a field.
+ * This date-time is used to enhance the accuracy of the returned range.
+ * If it is not possible to return the range, because the field is not supported
+ * or for some other reason, an exception is thrown.
+ *
+ * If the field is a {@link ChronoField} then the query is implemented here.
+ * The {@link #isSupported(TemporalField) supported fields} will return
+ * appropriate range instances.
+ * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)}
+ * passing {@code this} as the argument.
+ * Whether the range can be obtained is determined by the field.
+ *
+ * @param field the field to query the range for, not null
+ * @return the range of valid values for the field, not null
+ * @throws DateTimeException if the range for the field cannot be obtained
+ */
+ @Override
+ public ValueRange range(TemporalField field) {
+ if (field instanceof ChronoField) {
+ ChronoField f = (ChronoField) field;
+ return (f.isTimeField() ? time.range(field) : date.range(field));
+ }
+ return field.doRange(this);
+ }
+
+ /**
+ * Gets the value of the specified field from this date-time as an {@code int}.
+ *
+ * This queries this date-time for the value for the specified field.
+ * The returned value will always be within the valid range of values for the field.
+ * If it is not possible to return the value, because the field is not supported
+ * or for some other reason, an exception is thrown.
+ *
+ * If the field is a {@link ChronoField} then the query is implemented here.
+ * The {@link #isSupported(TemporalField) supported fields} will return valid
+ * values based on this date-time, except {@code NANO_OF_DAY}, {@code MICRO_OF_DAY},
+ * {@code EPOCH_DAY} and {@code EPOCH_MONTH} which are too large to fit in
+ * an {@code int} and throw a {@code DateTimeException}.
+ * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+ * passing {@code this} as the argument. Whether the value can be obtained,
+ * and what the value represents, is determined by the field.
+ *
+ * @param field the field to get, not null
+ * @return the value for the field
+ * @throws DateTimeException if a value for the field cannot be obtained
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public int get(TemporalField field) {
+ if (field instanceof ChronoField) {
+ ChronoField f = (ChronoField) field;
+ return (f.isTimeField() ? time.get(field) : date.get(field));
+ }
+ return ChronoLocalDateTime.super.get(field);
+ }
+
+ /**
+ * Gets the value of the specified field from this date-time as a {@code long}.
+ *
+ * This queries this date-time for the value for the specified field.
+ * If it is not possible to return the value, because the field is not supported
+ * or for some other reason, an exception is thrown.
+ *
+ * If the field is a {@link ChronoField} then the query is implemented here.
+ * The {@link #isSupported(TemporalField) supported fields} will return valid
+ * values based on this date-time.
+ * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+ * passing {@code this} as the argument. Whether the value can be obtained,
+ * and what the value represents, is determined by the field.
+ *
+ * @param field the field to get, not null
+ * @return the value for the field
+ * @throws DateTimeException if a value for the field cannot be obtained
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public long getLong(TemporalField field) {
+ if (field instanceof ChronoField) {
+ ChronoField f = (ChronoField) field;
+ return (f.isTimeField() ? time.getLong(field) : date.getLong(field));
+ }
+ return field.doGet(this);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the {@code LocalDate} part of this date-time.
+ *
+ * This returns a {@code LocalDate} with the same year, month and day
+ * as this date-time.
+ *
+ * @return the date part of this date-time, not null
+ */
+ @Override
+ public LocalDate getDate() {
+ return date;
+ }
+
+ /**
+ * Gets the year field.
+ *
+ * This method returns the primitive {@code int} value for the year.
+ *
+ * The year returned by this method is proleptic as per {@code get(YEAR)}.
+ * To obtain the year-of-era, use {@code get(YEAR_OF_ERA}.
+ *
+ * @return the year, from MIN_YEAR to MAX_YEAR
+ */
+ public int getYear() {
+ return date.getYear();
+ }
+
+ /**
+ * Gets the month-of-year field from 1 to 12.
+ *
+ * This method returns the month as an {@code int} from 1 to 12.
+ * Application code is frequently clearer if the enum {@link Month}
+ * is used by calling {@link #getMonth()}.
+ *
+ * @return the month-of-year, from 1 to 12
+ * @see #getMonth()
+ */
+ public int getMonthValue() {
+ return date.getMonthValue();
+ }
+
+ /**
+ * Gets the month-of-year field using the {@code Month} enum.
+ *
+ * This method returns the enum {@link Month} for the month.
+ * This avoids confusion as to what {@code int} values mean.
+ * If you need access to the primitive {@code int} value then the enum
+ * provides the {@link Month#getValue() int value}.
+ *
+ * @return the month-of-year, not null
+ * @see #getMonthValue()
+ */
+ public Month getMonth() {
+ return date.getMonth();
+ }
+
+ /**
+ * Gets the day-of-month field.
+ *
+ * This method returns the primitive {@code int} value for the day-of-month.
+ *
+ * @return the day-of-month, from 1 to 31
+ */
+ public int getDayOfMonth() {
+ return date.getDayOfMonth();
+ }
+
+ /**
+ * Gets the day-of-year field.
+ *
+ * This method returns the primitive {@code int} value for the day-of-year.
+ *
+ * @return the day-of-year, from 1 to 365, or 366 in a leap year
+ */
+ public int getDayOfYear() {
+ return date.getDayOfYear();
+ }
+
+ /**
+ * Gets the day-of-week field, which is an enum {@code DayOfWeek}.
+ *
+ * This method returns the enum {@link DayOfWeek} for the day-of-week.
+ * This avoids confusion as to what {@code int} values mean.
+ * If you need access to the primitive {@code int} value then the enum
+ * provides the {@link DayOfWeek#getValue() int value}.
+ *
+ * Additional information can be obtained from the {@code DayOfWeek}.
+ * This includes textual names of the values.
+ *
+ * @return the day-of-week, not null
+ */
+ public DayOfWeek getDayOfWeek() {
+ return date.getDayOfWeek();
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the {@code LocalTime} part of this date-time.
+ *
+ * This returns a {@code LocalTime} with the same hour, minute, second and
+ * nanosecond as this date-time.
+ *
+ * @return the time part of this date-time, not null
+ */
+ @Override
+ public LocalTime getTime() {
+ return time;
+ }
+
+ /**
+ * Gets the hour-of-day field.
+ *
+ * @return the hour-of-day, from 0 to 23
+ */
+ public int getHour() {
+ return time.getHour();
+ }
+
+ /**
+ * Gets the minute-of-hour field.
+ *
+ * @return the minute-of-hour, from 0 to 59
+ */
+ public int getMinute() {
+ return time.getMinute();
+ }
+
+ /**
+ * Gets the second-of-minute field.
+ *
+ * @return the second-of-minute, from 0 to 59
+ */
+ public int getSecond() {
+ return time.getSecond();
+ }
+
+ /**
+ * Gets the nano-of-second field.
+ *
+ * @return the nano-of-second, from 0 to 999,999,999
+ */
+ public int getNano() {
+ return time.getNano();
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns an adjusted copy of this date-time.
+ *
+ * This returns a new {@code LocalDateTime}, based on this one, with the date-time adjusted.
+ * The adjustment takes place using the specified adjuster strategy object.
+ * Read the documentation of the adjuster to understand what adjustment will be made.
+ *
+ * A simple adjuster might simply set the one of the fields, such as the year field.
+ * A more complex adjuster might set the date to the last day of the month.
+ * A selection of common adjustments is provided in {@link java.time.temporal.Adjusters}.
+ * These include finding the "last day of the month" and "next Wednesday".
+ * Key date-time classes also implement the {@code TemporalAdjuster} interface,
+ * such as {@link Month} and {@link java.time.temporal.MonthDay MonthDay}.
+ * The adjuster is responsible for handling special cases, such as the varying
+ * lengths of month and leap years.
+ *
+ * For example this code returns a date on the last day of July:
+ *
+ * The classes {@link LocalDate} and {@link LocalTime} implement {@code TemporalAdjuster},
+ * thus this method can be used to change the date, time or offset:
+ *
+ * The result of this method is obtained by invoking the
+ * {@link TemporalAdjuster#adjustInto(Temporal)} method on the
+ * specified adjuster passing {@code this} as the argument.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param adjuster the adjuster to use, not null
+ * @return a {@code LocalDateTime} based on {@code this} with the adjustment made, not null
+ * @throws DateTimeException if the adjustment cannot be made
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public LocalDateTime with(TemporalAdjuster adjuster) {
+ // optimizations
+ if (adjuster instanceof LocalDate) {
+ return with((LocalDate) adjuster, time);
+ } else if (adjuster instanceof LocalTime) {
+ return with(date, (LocalTime) adjuster);
+ } else if (adjuster instanceof LocalDateTime) {
+ return (LocalDateTime) adjuster;
+ }
+ return (LocalDateTime) adjuster.adjustInto(this);
+ }
+
+ /**
+ * Returns a copy of this date-time with the specified field set to a new value.
+ *
+ * This returns a new {@code LocalDateTime}, based on this one, with the value
+ * for the specified field changed.
+ * This can be used to change any supported field, such as the year, month or day-of-month.
+ * If it is not possible to set the value, because the field is not supported or for
+ * some other reason, an exception is thrown.
+ *
+ * In some cases, changing the specified field can cause the resulting date-time to become invalid,
+ * such as changing the month from 31st January to February would make the day-of-month invalid.
+ * In cases like this, the field is responsible for resolving the date. Typically it will choose
+ * the previous valid date, which would be the last valid day of February in this example.
+ *
+ * If the field is a {@link ChronoField} then the adjustment is implemented here.
+ * The {@link #isSupported(TemporalField) supported fields} will behave as per
+ * the matching method on {@link LocalDate#with(TemporalField, long) LocalDate}
+ * or {@link LocalTime#with(TemporalField, long) LocalTime}.
+ * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doWith(Temporal, long)}
+ * passing {@code this} as the argument. In this case, the field determines
+ * whether and how to adjust the instant.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param field the field to set in the result, not null
+ * @param newValue the new value of the field in the result
+ * @return a {@code LocalDateTime} based on {@code this} with the specified field set, not null
+ * @throws DateTimeException if the field cannot be set
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public LocalDateTime with(TemporalField field, long newValue) {
+ if (field instanceof ChronoField) {
+ ChronoField f = (ChronoField) field;
+ if (f.isTimeField()) {
+ return with(date, time.with(field, newValue));
+ } else {
+ return with(date.with(field, newValue), time);
+ }
+ }
+ return field.doWith(this, newValue);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this {@code LocalDateTime} with the year altered.
+ * The time does not affect the calculation and will be the same in the result.
+ * If the day-of-month is invalid for the year, it will be changed to the last valid day of the month.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param year the year to set in the result, from MIN_YEAR to MAX_YEAR
+ * @return a {@code LocalDateTime} based on this date-time with the requested year, not null
+ * @throws DateTimeException if the year value is invalid
+ */
+ public LocalDateTime withYear(int year) {
+ return with(date.withYear(year), time);
+ }
+
+ /**
+ * Returns a copy of this {@code LocalDateTime} with the month-of-year altered.
+ * The time does not affect the calculation and will be the same in the result.
+ * If the day-of-month is invalid for the year, it will be changed to the last valid day of the month.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param month the month-of-year to set in the result, from 1 (January) to 12 (December)
+ * @return a {@code LocalDateTime} based on this date-time with the requested month, not null
+ * @throws DateTimeException if the month-of-year value is invalid
+ */
+ public LocalDateTime withMonth(int month) {
+ return with(date.withMonth(month), time);
+ }
+
+ /**
+ * Returns a copy of this {@code LocalDateTime} with the day-of-month altered.
+ * If the resulting {@code LocalDateTime} is invalid, an exception is thrown.
+ * The time does not affect the calculation and will be the same in the result.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param dayOfMonth the day-of-month to set in the result, from 1 to 28-31
+ * @return a {@code LocalDateTime} based on this date-time with the requested day, not null
+ * @throws DateTimeException if the day-of-month value is invalid
+ * @throws DateTimeException if the day-of-month is invalid for the month-year
+ */
+ public LocalDateTime withDayOfMonth(int dayOfMonth) {
+ return with(date.withDayOfMonth(dayOfMonth), time);
+ }
+
+ /**
+ * Returns a copy of this {@code LocalDateTime} with the day-of-year altered.
+ * If the resulting {@code LocalDateTime} is invalid, an exception is thrown.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param dayOfYear the day-of-year to set in the result, from 1 to 365-366
+ * @return a {@code LocalDateTime} based on this date with the requested day, not null
+ * @throws DateTimeException if the day-of-year value is invalid
+ * @throws DateTimeException if the day-of-year is invalid for the year
+ */
+ public LocalDateTime withDayOfYear(int dayOfYear) {
+ return with(date.withDayOfYear(dayOfYear), time);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this {@code LocalDateTime} with the hour-of-day value altered.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param hour the hour-of-day to set in the result, from 0 to 23
+ * @return a {@code LocalDateTime} based on this date-time with the requested hour, not null
+ * @throws DateTimeException if the hour value is invalid
+ */
+ public LocalDateTime withHour(int hour) {
+ LocalTime newTime = time.withHour(hour);
+ return with(date, newTime);
+ }
+
+ /**
+ * Returns a copy of this {@code LocalDateTime} with the minute-of-hour value altered.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param minute the minute-of-hour to set in the result, from 0 to 59
+ * @return a {@code LocalDateTime} based on this date-time with the requested minute, not null
+ * @throws DateTimeException if the minute value is invalid
+ */
+ public LocalDateTime withMinute(int minute) {
+ LocalTime newTime = time.withMinute(minute);
+ return with(date, newTime);
+ }
+
+ /**
+ * Returns a copy of this {@code LocalDateTime} with the second-of-minute value altered.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param second the second-of-minute to set in the result, from 0 to 59
+ * @return a {@code LocalDateTime} based on this date-time with the requested second, not null
+ * @throws DateTimeException if the second value is invalid
+ */
+ public LocalDateTime withSecond(int second) {
+ LocalTime newTime = time.withSecond(second);
+ return with(date, newTime);
+ }
+
+ /**
+ * Returns a copy of this {@code LocalDateTime} with the nano-of-second value altered.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param nanoOfSecond the nano-of-second to set in the result, from 0 to 999,999,999
+ * @return a {@code LocalDateTime} based on this date-time with the requested nanosecond, not null
+ * @throws DateTimeException if the nano value is invalid
+ */
+ public LocalDateTime withNano(int nanoOfSecond) {
+ LocalTime newTime = time.withNano(nanoOfSecond);
+ return with(date, newTime);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this {@code LocalDateTime} with the time truncated.
+ *
+ * Truncation returns a copy of the original date-time with fields
+ * smaller than the specified unit set to zero.
+ * For example, truncating with the {@link ChronoUnit#MINUTES minutes} unit
+ * will set the second-of-minute and nano-of-second field to zero.
+ *
+ * Not all units are accepted. The {@link ChronoUnit#DAYS days} unit and time
+ * units with an exact duration can be used, other units throw an exception.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param unit the unit to truncate to, not null
+ * @return a {@code LocalDateTime} based on this date-time with the time truncated, not null
+ * @throws DateTimeException if unable to truncate
+ */
+ public LocalDateTime truncatedTo(TemporalUnit unit) {
+ return with(date, time.truncatedTo(unit));
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this date-time with the specified period added.
+ *
+ * This method returns a new date-time based on this time with the specified period added.
+ * The adder is typically {@link Period} but may be any other type implementing
+ * the {@link TemporalAdder} interface.
+ * The calculation is delegated to the specified adjuster, which typically calls
+ * back to {@link #plus(long, TemporalUnit)}.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param adder the adder to use, not null
+ * @return a {@code LocalDateTime} based on this date-time with the addition made, not null
+ * @throws DateTimeException if the addition cannot be made
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public LocalDateTime plus(TemporalAdder adder) {
+ return (LocalDateTime) adder.addTo(this);
+ }
+
+ /**
+ * Returns a copy of this date-time with the specified period added.
+ *
+ * This method returns a new date-time based on this date-time with the specified period added.
+ * This can be used to add any period that is defined by a unit, for example to add years, months or days.
+ * The unit is responsible for the details of the calculation, including the resolution
+ * of any edge cases in the calculation.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param amountToAdd the amount of the unit to add to the result, may be negative
+ * @param unit the unit of the period to add, not null
+ * @return a {@code LocalDateTime} based on this date-time with the specified period added, not null
+ * @throws DateTimeException if the unit cannot be added to this type
+ */
+ @Override
+ public LocalDateTime plus(long amountToAdd, TemporalUnit unit) {
+ if (unit instanceof ChronoUnit) {
+ ChronoUnit f = (ChronoUnit) unit;
+ switch (f) {
+ case NANOS: return plusNanos(amountToAdd);
+ case MICROS: return plusDays(amountToAdd / MICROS_PER_DAY).plusNanos((amountToAdd % MICROS_PER_DAY) * 1000);
+ case MILLIS: return plusDays(amountToAdd / MILLIS_PER_DAY).plusNanos((amountToAdd % MILLIS_PER_DAY) * 1000_000);
+ case SECONDS: return plusSeconds(amountToAdd);
+ case MINUTES: return plusMinutes(amountToAdd);
+ case HOURS: return plusHours(amountToAdd);
+ case HALF_DAYS: return plusDays(amountToAdd / 256).plusHours((amountToAdd % 256) * 12); // no overflow (256 is multiple of 2)
+ }
+ return with(date.plus(amountToAdd, unit), time);
+ }
+ return unit.doPlus(this, amountToAdd);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this {@code LocalDateTime} with the specified period in years added.
+ *
+ * This method adds the specified amount to the years field in three steps:
+ *
+ * For example, 2008-02-29 (leap year) plus one year would result in the
+ * invalid date 2009-02-29 (standard year). Instead of returning an invalid
+ * result, the last valid day of the month, 2009-02-28, is selected instead.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param years the years to add, may be negative
+ * @return a {@code LocalDateTime} based on this date-time with the years added, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public LocalDateTime plusYears(long years) {
+ LocalDate newDate = date.plusYears(years);
+ return with(newDate, time);
+ }
+
+ /**
+ * Returns a copy of this {@code LocalDateTime} with the specified period in months added.
+ *
+ * This method adds the specified amount to the months field in three steps:
+ *
+ * For example, 2007-03-31 plus one month would result in the invalid date
+ * 2007-04-31. Instead of returning an invalid result, the last valid day
+ * of the month, 2007-04-30, is selected instead.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param months the months to add, may be negative
+ * @return a {@code LocalDateTime} based on this date-time with the months added, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public LocalDateTime plusMonths(long months) {
+ LocalDate newDate = date.plusMonths(months);
+ return with(newDate, time);
+ }
+
+ /**
+ * Returns a copy of this {@code LocalDateTime} with the specified period in weeks added.
+ *
+ * This method adds the specified amount in weeks to the days field incrementing
+ * the month and year fields as necessary to ensure the result remains valid.
+ * The result is only invalid if the maximum/minimum year is exceeded.
+ *
+ * For example, 2008-12-31 plus one week would result in 2009-01-07.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param weeks the weeks to add, may be negative
+ * @return a {@code LocalDateTime} based on this date-time with the weeks added, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public LocalDateTime plusWeeks(long weeks) {
+ LocalDate newDate = date.plusWeeks(weeks);
+ return with(newDate, time);
+ }
+
+ /**
+ * Returns a copy of this {@code LocalDateTime} with the specified period in days added.
+ *
+ * This method adds the specified amount to the days field incrementing the
+ * month and year fields as necessary to ensure the result remains valid.
+ * The result is only invalid if the maximum/minimum year is exceeded.
+ *
+ * For example, 2008-12-31 plus one day would result in 2009-01-01.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param days the days to add, may be negative
+ * @return a {@code LocalDateTime} based on this date-time with the days added, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public LocalDateTime plusDays(long days) {
+ LocalDate newDate = date.plusDays(days);
+ return with(newDate, time);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this {@code LocalDateTime} with the specified period in hours added.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param hours the hours to add, may be negative
+ * @return a {@code LocalDateTime} based on this date-time with the hours added, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public LocalDateTime plusHours(long hours) {
+ return plusWithOverflow(date, hours, 0, 0, 0, 1);
+ }
+
+ /**
+ * Returns a copy of this {@code LocalDateTime} with the specified period in minutes added.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param minutes the minutes to add, may be negative
+ * @return a {@code LocalDateTime} based on this date-time with the minutes added, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public LocalDateTime plusMinutes(long minutes) {
+ return plusWithOverflow(date, 0, minutes, 0, 0, 1);
+ }
+
+ /**
+ * Returns a copy of this {@code LocalDateTime} with the specified period in seconds added.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param seconds the seconds to add, may be negative
+ * @return a {@code LocalDateTime} based on this date-time with the seconds added, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public LocalDateTime plusSeconds(long seconds) {
+ return plusWithOverflow(date, 0, 0, seconds, 0, 1);
+ }
+
+ /**
+ * Returns a copy of this {@code LocalDateTime} with the specified period in nanoseconds added.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param nanos the nanos to add, may be negative
+ * @return a {@code LocalDateTime} based on this date-time with the nanoseconds added, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public LocalDateTime plusNanos(long nanos) {
+ return plusWithOverflow(date, 0, 0, 0, nanos, 1);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this date-time with the specified period subtracted.
+ *
+ * This method returns a new date-time based on this time with the specified period subtracted.
+ * The subtractor is typically {@link Period} but may be any other type implementing
+ * the {@link TemporalSubtractor} interface.
+ * The calculation is delegated to the specified adjuster, which typically calls
+ * back to {@link #minus(long, TemporalUnit)}.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param subtractor the subtractor to use, not null
+ * @return a {@code LocalDateTime} based on this date-time with the subtraction made, not null
+ * @throws DateTimeException if the subtraction cannot be made
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public LocalDateTime minus(TemporalSubtractor subtractor) {
+ return (LocalDateTime) subtractor.subtractFrom(this);
+ }
+
+ /**
+ * Returns a copy of this date-time with the specified period subtracted.
+ *
+ * This method returns a new date-time based on this date-time with the specified period subtracted.
+ * This can be used to subtract any period that is defined by a unit, for example to subtract years, months or days.
+ * The unit is responsible for the details of the calculation, including the resolution
+ * of any edge cases in the calculation.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param amountToSubtract the amount of the unit to subtract from the result, may be negative
+ * @param unit the unit of the period to subtract, not null
+ * @return a {@code LocalDateTime} based on this date-time with the specified period subtracted, not null
+ * @throws DateTimeException if the unit cannot be added to this type
+ */
+ @Override
+ public LocalDateTime minus(long amountToSubtract, TemporalUnit unit) {
+ return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this {@code LocalDateTime} with the specified period in years subtracted.
+ *
+ * This method subtracts the specified amount from the years field in three steps:
+ *
+ * For example, 2008-02-29 (leap year) minus one year would result in the
+ * invalid date 2009-02-29 (standard year). Instead of returning an invalid
+ * result, the last valid day of the month, 2009-02-28, is selected instead.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param years the years to subtract, may be negative
+ * @return a {@code LocalDateTime} based on this date-time with the years subtracted, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public LocalDateTime minusYears(long years) {
+ return (years == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-years));
+ }
+
+ /**
+ * Returns a copy of this {@code LocalDateTime} with the specified period in months subtracted.
+ *
+ * This method subtracts the specified amount from the months field in three steps:
+ *
+ * For example, 2007-03-31 minus one month would result in the invalid date
+ * 2007-04-31. Instead of returning an invalid result, the last valid day
+ * of the month, 2007-04-30, is selected instead.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param months the months to subtract, may be negative
+ * @return a {@code LocalDateTime} based on this date-time with the months subtracted, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public LocalDateTime minusMonths(long months) {
+ return (months == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-months));
+ }
+
+ /**
+ * Returns a copy of this {@code LocalDateTime} with the specified period in weeks subtracted.
+ *
+ * This method subtracts the specified amount in weeks from the days field decrementing
+ * the month and year fields as necessary to ensure the result remains valid.
+ * The result is only invalid if the maximum/minimum year is exceeded.
+ *
+ * For example, 2009-01-07 minus one week would result in 2008-12-31.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param weeks the weeks to subtract, may be negative
+ * @return a {@code LocalDateTime} based on this date-time with the weeks subtracted, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public LocalDateTime minusWeeks(long weeks) {
+ return (weeks == Long.MIN_VALUE ? plusWeeks(Long.MAX_VALUE).plusWeeks(1) : plusWeeks(-weeks));
+ }
+
+ /**
+ * Returns a copy of this {@code LocalDateTime} with the specified period in days subtracted.
+ *
+ * This method subtracts the specified amount from the days field incrementing the
+ * month and year fields as necessary to ensure the result remains valid.
+ * The result is only invalid if the maximum/minimum year is exceeded.
+ *
+ * For example, 2009-01-01 minus one day would result in 2008-12-31.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param days the days to subtract, may be negative
+ * @return a {@code LocalDateTime} based on this date-time with the days subtracted, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public LocalDateTime minusDays(long days) {
+ return (days == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-days));
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this {@code LocalDateTime} with the specified period in hours subtracted.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param hours the hours to subtract, may be negative
+ * @return a {@code LocalDateTime} based on this date-time with the hours subtracted, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public LocalDateTime minusHours(long hours) {
+ return plusWithOverflow(date, hours, 0, 0, 0, -1);
+ }
+
+ /**
+ * Returns a copy of this {@code LocalDateTime} with the specified period in minutes subtracted.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param minutes the minutes to subtract, may be negative
+ * @return a {@code LocalDateTime} based on this date-time with the minutes subtracted, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public LocalDateTime minusMinutes(long minutes) {
+ return plusWithOverflow(date, 0, minutes, 0, 0, -1);
+ }
+
+ /**
+ * Returns a copy of this {@code LocalDateTime} with the specified period in seconds subtracted.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param seconds the seconds to subtract, may be negative
+ * @return a {@code LocalDateTime} based on this date-time with the seconds subtracted, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public LocalDateTime minusSeconds(long seconds) {
+ return plusWithOverflow(date, 0, 0, seconds, 0, -1);
+ }
+
+ /**
+ * Returns a copy of this {@code LocalDateTime} with the specified period in nanoseconds subtracted.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param nanos the nanos to subtract, may be negative
+ * @return a {@code LocalDateTime} based on this date-time with the nanoseconds subtracted, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public LocalDateTime minusNanos(long nanos) {
+ return plusWithOverflow(date, 0, 0, 0, nanos, -1);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this {@code LocalDateTime} with the specified period added.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param newDate the new date to base the calculation on, not null
+ * @param hours the hours to add, may be negative
+ * @param minutes the minutes to add, may be negative
+ * @param seconds the seconds to add, may be negative
+ * @param nanos the nanos to add, may be negative
+ * @param sign the sign to determine add or subtract
+ * @return the combined result, not null
+ */
+ private LocalDateTime plusWithOverflow(LocalDate newDate, long hours, long minutes, long seconds, long nanos, int sign) {
+ // 9223372036854775808 long, 2147483648 int
+ if ((hours | minutes | seconds | nanos) == 0) {
+ return with(newDate, time);
+ }
+ long totDays = nanos / NANOS_PER_DAY + // max/24*60*60*1B
+ seconds / SECONDS_PER_DAY + // max/24*60*60
+ minutes / MINUTES_PER_DAY + // max/24*60
+ hours / HOURS_PER_DAY; // max/24
+ totDays *= sign; // total max*0.4237...
+ long totNanos = nanos % NANOS_PER_DAY + // max 86400000000000
+ (seconds % SECONDS_PER_DAY) * NANOS_PER_SECOND + // max 86400000000000
+ (minutes % MINUTES_PER_DAY) * NANOS_PER_MINUTE + // max 86400000000000
+ (hours % HOURS_PER_DAY) * NANOS_PER_HOUR; // max 86400000000000
+ long curNoD = time.toNanoOfDay(); // max 86400000000000
+ totNanos = totNanos * sign + curNoD; // total 432000000000000
+ totDays += Math.floorDiv(totNanos, NANOS_PER_DAY);
+ long newNoD = Math.floorMod(totNanos, NANOS_PER_DAY);
+ LocalTime newTime = (newNoD == curNoD ? time : LocalTime.ofNanoOfDay(newNoD));
+ return with(newDate.plusDays(totDays), newTime);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Queries this date-time using the specified query.
+ *
+ * This queries this date-time using the specified query strategy object.
+ * The {@code TemporalQuery} object defines the logic to be used to
+ * obtain the result. Read the documentation of the query to understand
+ * what the result of this method will be.
+ *
+ * The result of this method is obtained by invoking the
+ * {@link java.time.temporal.TemporalQuery#queryFrom(TemporalAccessor)} method on the
+ * specified query passing {@code this} as the argument.
+ *
+ * @param
+ * This returns a temporal object of the same observable type as the input
+ * with the date and time changed to be the same as this.
+ *
+ * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+ * twice, passing {@link ChronoField#EPOCH_DAY} and
+ * {@link ChronoField#NANO_OF_DAY} as the fields.
+ *
+ * In most cases, it is clearer to reverse the calling pattern by using
+ * {@link Temporal#with(TemporalAdjuster)}:
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param temporal the target object to be adjusted, not null
+ * @return the adjusted object, not null
+ * @throws DateTimeException if unable to make the adjustment
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override // override for Javadoc
+ public Temporal adjustInto(Temporal temporal) {
+ return ChronoLocalDateTime.super.adjustInto(temporal);
+ }
+
+ /**
+ * Calculates the period between this date-time and another date-time in
+ * terms of the specified unit.
+ *
+ * This calculates the period between two date-times in terms of a single unit.
+ * The start and end points are {@code this} and the specified date-time.
+ * The result will be negative if the end is before the start.
+ * The {@code Temporal} passed to this method must be a {@code LocalDateTime}.
+ * For example, the period in days between two date-times can be calculated
+ * using {@code startDateTime.periodUntil(endDateTime, DAYS)}.
+ *
+ * The calculation returns a whole number, representing the number of
+ * complete units between the two date-times.
+ * For example, the period in months between 2012-06-15T00:00 and 2012-08-14T23:59
+ * will only be one month as it is one minute short of two months.
+ *
+ * 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:
+ *
+ * The calculation is implemented in this method for {@link ChronoUnit}.
+ * The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS},
+ * {@code MINUTES}, {@code HOURS} and {@code HALF_DAYS}, {@code DAYS},
+ * {@code WEEKS}, {@code MONTHS}, {@code YEARS}, {@code DECADES},
+ * {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS} are supported.
+ * Other {@code ChronoUnit} values will throw an exception.
+ *
+ * If the unit is not a {@code ChronoUnit}, then the result of this method
+ * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
+ * passing {@code this} as the first argument and the input temporal as
+ * the second argument.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param endDateTime the end date-time, which must be a {@code LocalDateTime}, not null
+ * @param unit the unit to measure the period in, not null
+ * @return the amount of the period between this date-time and the end date-time
+ * @throws DateTimeException if the period cannot be calculated
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public long periodUntil(Temporal endDateTime, TemporalUnit unit) {
+ if (endDateTime instanceof LocalDateTime == false) {
+ Objects.requireNonNull(endDateTime, "endDateTime");
+ throw new DateTimeException("Unable to calculate period between objects of two different types");
+ }
+ LocalDateTime end = (LocalDateTime) endDateTime;
+ if (unit instanceof ChronoUnit) {
+ ChronoUnit f = (ChronoUnit) unit;
+ if (f.isTimeUnit()) {
+ long amount = date.daysUntil(end.date);
+ switch (f) {
+ case NANOS: amount = Math.multiplyExact(amount, NANOS_PER_DAY); break;
+ case MICROS: amount = Math.multiplyExact(amount, MICROS_PER_DAY); break;
+ case MILLIS: amount = Math.multiplyExact(amount, MILLIS_PER_DAY); break;
+ case SECONDS: amount = Math.multiplyExact(amount, SECONDS_PER_DAY); break;
+ case MINUTES: amount = Math.multiplyExact(amount, MINUTES_PER_DAY); break;
+ case HOURS: amount = Math.multiplyExact(amount, HOURS_PER_DAY); break;
+ case HALF_DAYS: amount = Math.multiplyExact(amount, 2); break;
+ }
+ return Math.addExact(amount, time.periodUntil(end.time, unit));
+ }
+ LocalDate endDate = end.date;
+ if (end.time.isBefore(time)) {
+ endDate = endDate.minusDays(1);
+ }
+ return date.periodUntil(endDate, unit);
+ }
+ return unit.between(this, endDateTime).getAmount();
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns an offset date-time formed from this date-time and the specified offset.
+ *
+ * This combines this date-time with the specified offset to form an {@code OffsetDateTime}.
+ * All possible combinations of date-time and offset are valid.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param offset the offset to combine with, not null
+ * @return the offset date-time formed from this date-time and the specified offset, not null
+ */
+ public OffsetDateTime atOffset(ZoneOffset offset) {
+ return OffsetDateTime.of(this, offset);
+ }
+
+ /**
+ * Returns a zoned date-time formed from this date-time and the specified time-zone.
+ *
+ * This creates a zoned date-time matching the input date-time as closely as possible.
+ * Time-zone rules, such as daylight savings, mean that not every local date-time
+ * is valid for the specified zone, thus the local date-time may be adjusted.
+ *
+ * The local date-time is resolved to a single instant on the time-line.
+ * This is achieved by finding a valid offset from UTC/Greenwich for the local
+ * date-time as defined by the {@link ZoneRules rules} of the zone ID.
+ *
+ * In most cases, there is only one valid offset for a local date-time.
+ * In the case of an overlap, where clocks are set back, there are two valid offsets.
+ * This method uses the earlier offset typically corresponding to "summer".
+ *
+ * In the case of a gap, where clocks jump forward, there is no valid offset.
+ * Instead, the local date-time is adjusted to be later by the length of the gap.
+ * For a typical one hour daylight savings change, the local date-time will be
+ * moved one hour later into the offset typically corresponding to "summer".
+ *
+ * To obtain the later offset during an overlap, call
+ * {@link ZonedDateTime#withLaterOffsetAtOverlap()} on the result of this method.
+ * To throw an exception when there is a gap or overlap, use
+ * {@link ZonedDateTime#ofStrict(LocalDateTime, ZoneOffset, ZoneId)}.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param zone the time-zone to use, not null
+ * @return the zoned date-time formed from this date-time, not null
+ */
+ @Override
+ public ZonedDateTime atZone(ZoneId zone) {
+ return ZonedDateTime.of(this, zone);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Compares this date-time to another date-time.
+ *
+ * The comparison is primarily based on the date-time, from earliest to latest.
+ * It is "consistent with equals", as defined by {@link Comparable}.
+ *
+ * If all the date-times being compared are instances of {@code LocalDateTime},
+ * then the comparison will be entirely based on the date-time.
+ * If some dates being compared are in different chronologies, then the
+ * chronology is also considered, see {@link ChronoLocalDateTime#compareTo}.
+ *
+ * @param other the other date-time to compare to, not null
+ * @return the comparator value, negative if less, positive if greater
+ */
+ @Override // override for Javadoc and performance
+ public int compareTo(ChronoLocalDateTime> other) {
+ if (other instanceof LocalDateTime) {
+ return compareTo0((LocalDateTime) other);
+ }
+ return ChronoLocalDateTime.super.compareTo(other);
+ }
+
+ private int compareTo0(LocalDateTime other) {
+ int cmp = date.compareTo0(other.getDate());
+ if (cmp == 0) {
+ cmp = time.compareTo(other.getTime());
+ }
+ return cmp;
+ }
+
+ /**
+ * Checks if this date-time is after the specified date-time.
+ *
+ * This checks to see if this date-time represents a point on the
+ * local time-line after the other date-time.
+ *
+ * This method only considers the position of the two date-times on the local time-line.
+ * It does not take into account the chronology, or calendar system.
+ * This is different from the comparison in {@link #compareTo(ChronoLocalDateTime)},
+ * but is the same approach as {@link #DATE_TIME_COMPARATOR}.
+ *
+ * @param other the other date-time to compare to, not null
+ * @return true if this date-time is after the specified date-time
+ */
+ @Override // override for Javadoc and performance
+ public boolean isAfter(ChronoLocalDateTime> other) {
+ if (other instanceof LocalDateTime) {
+ return compareTo0((LocalDateTime) other) > 0;
+ }
+ return ChronoLocalDateTime.super.isAfter(other);
+ }
+
+ /**
+ * Checks if this date-time is before the specified date-time.
+ *
+ * This checks to see if this date-time represents a point on the
+ * local time-line before the other date-time.
+ *
+ * This method only considers the position of the two date-times on the local time-line.
+ * It does not take into account the chronology, or calendar system.
+ * This is different from the comparison in {@link #compareTo(ChronoLocalDateTime)},
+ * but is the same approach as {@link #DATE_TIME_COMPARATOR}.
+ *
+ * @param other the other date-time to compare to, not null
+ * @return true if this date-time is before the specified date-time
+ */
+ @Override // override for Javadoc and performance
+ public boolean isBefore(ChronoLocalDateTime> other) {
+ if (other instanceof LocalDateTime) {
+ return compareTo0((LocalDateTime) other) < 0;
+ }
+ return ChronoLocalDateTime.super.isBefore(other);
+ }
+
+ /**
+ * Checks if this date-time is equal to the specified date-time.
+ *
+ * This checks to see if this date-time represents the same point on the
+ * local time-line as the other date-time.
+ *
+ * This method only considers the position of the two date-times on the local time-line.
+ * It does not take into account the chronology, or calendar system.
+ * This is different from the comparison in {@link #compareTo(ChronoLocalDateTime)},
+ * but is the same approach as {@link #DATE_TIME_COMPARATOR}.
+ *
+ * @param other the other date-time to compare to, not null
+ * @return true if this date-time is equal to the specified date-time
+ */
+ @Override // override for Javadoc and performance
+ public boolean isEqual(ChronoLocalDateTime> other) {
+ if (other instanceof LocalDateTime) {
+ return compareTo0((LocalDateTime) other) == 0;
+ }
+ return ChronoLocalDateTime.super.isEqual(other);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks if this date-time is equal to another date-time.
+ *
+ * Compares this {@code LocalDateTime} with another ensuring that the date-time is the same.
+ * Only objects of type {@code LocalDateTime} are compared, other types return false.
+ *
+ * @param obj the object to check, null returns false
+ * @return true if this is equal to the other date-time
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof LocalDateTime) {
+ LocalDateTime other = (LocalDateTime) obj;
+ return date.equals(other.date) && time.equals(other.time);
+ }
+ return false;
+ }
+
+ /**
+ * A hash code for this date-time.
+ *
+ * @return a suitable hash code
+ */
+ @Override
+ public int hashCode() {
+ return date.hashCode() ^ time.hashCode();
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Outputs this date-time as a {@code String}, such as {@code 2007-12-03T10:15:30}.
+ *
+ * The output will be one of the following ISO-8601 formats:
+ *
+ * The format used will be the shortest that outputs the full value of
+ * the time where the omitted parts are implied to be zero.
+ *
+ * @return a string representation of this date-time, not null
+ */
+ @Override
+ public String toString() {
+ return date.toString() + 'T' + time.toString();
+ }
+
+ /**
+ * Outputs this date-time as a {@code String} using the formatter.
+ *
+ * This date-time will be passed to the formatter
+ * {@link DateTimeFormatter#print(TemporalAccessor) print method}.
+ *
+ * @param formatter the formatter to use, not null
+ * @return the formatted date-time string, not null
+ * @throws DateTimeException if an error occurs during printing
+ */
+ @Override // override for Javadoc
+ public String toString(DateTimeFormatter formatter) {
+ return ChronoLocalDateTime.super.toString(formatter);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Writes the object using a
+ * dedicated serialized form.
+ *
+ * {@code LocalTime} is an immutable date-time object that represents a time,
+ * often viewed as hour-minute-second.
+ * Time is represented to nanosecond precision.
+ * For example, the value "13:45.30.123456789" can be stored in a {@code LocalTime}.
+ *
+ * It does not store or represent a date or time-zone.
+ * Instead, it is a description of the local time as seen on a wall clock.
+ * It cannot represent an instant on the time-line without additional information
+ * such as an offset or time-zone.
+ *
+ * The ISO-8601 calendar system is the modern civil calendar system used today
+ * in most of the world. This API assumes that all calendar systems use the same
+ * representation, this class, for time-of-day.
+ *
+ *
+ * This will query the {@link Clock#systemDefaultZone() system clock} in the default
+ * time-zone to obtain the current time.
+ *
+ * Using this method will prevent the ability to use an alternate clock for testing
+ * because the clock is hard-coded.
+ *
+ * @return the current time using the system clock and default time-zone, not null
+ */
+ public static LocalTime now() {
+ return now(Clock.systemDefaultZone());
+ }
+
+ /**
+ * Obtains the current time from the system clock in the specified time-zone.
+ *
+ * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current time.
+ * Specifying the time-zone avoids dependence on the default time-zone.
+ *
+ * Using this method will prevent the ability to use an alternate clock for testing
+ * because the clock is hard-coded.
+ *
+ * @param zone the zone ID to use, not null
+ * @return the current time using the system clock, not null
+ */
+ public static LocalTime now(ZoneId zone) {
+ return now(Clock.system(zone));
+ }
+
+ /**
+ * Obtains the current time from the specified clock.
+ *
+ * This will query the specified clock to obtain the current time.
+ * Using this method allows the use of an alternate clock for testing.
+ * The alternate clock may be introduced using {@link Clock dependency injection}.
+ *
+ * @param clock the clock to use, not null
+ * @return the current time, not null
+ */
+ public static LocalTime now(Clock clock) {
+ Objects.requireNonNull(clock, "clock");
+ // inline OffsetTime factory to avoid creating object and InstantProvider checks
+ final Instant now = clock.instant(); // called once
+ ZoneOffset offset = clock.getZone().getRules().getOffset(now);
+ long secsOfDay = now.getEpochSecond() % SECONDS_PER_DAY;
+ secsOfDay = (secsOfDay + offset.getTotalSeconds()) % SECONDS_PER_DAY;
+ if (secsOfDay < 0) {
+ secsOfDay += SECONDS_PER_DAY;
+ }
+ return LocalTime.ofSecondOfDay(secsOfDay, now.getNano());
+ }
+
+ //------------------------get-----------------------------------------------
+ /**
+ * Obtains an instance of {@code LocalTime} from an hour and minute.
+ *
+ * The second and nanosecond fields will be set to zero by this factory method.
+ *
+ * This factory may return a cached value, but applications must not rely on this.
+ *
+ * @param hour the hour-of-day to represent, from 0 to 23
+ * @param minute the minute-of-hour to represent, from 0 to 59
+ * @return the local time, not null
+ * @throws DateTimeException if the value of any field is out of range
+ */
+ public static LocalTime of(int hour, int minute) {
+ HOUR_OF_DAY.checkValidValue(hour);
+ if (minute == 0) {
+ return HOURS[hour]; // for performance
+ }
+ MINUTE_OF_HOUR.checkValidValue(minute);
+ return new LocalTime(hour, minute, 0, 0);
+ }
+
+ /**
+ * Obtains an instance of {@code LocalTime} from an hour, minute and second.
+ *
+ * The nanosecond field will be set to zero by this factory method.
+ *
+ * This factory may return a cached value, but applications must not rely on this.
+ *
+ * @param hour the hour-of-day to represent, from 0 to 23
+ * @param minute the minute-of-hour to represent, from 0 to 59
+ * @param second the second-of-minute to represent, from 0 to 59
+ * @return the local time, not null
+ * @throws DateTimeException if the value of any field is out of range
+ */
+ public static LocalTime of(int hour, int minute, int second) {
+ HOUR_OF_DAY.checkValidValue(hour);
+ if ((minute | second) == 0) {
+ return HOURS[hour]; // for performance
+ }
+ MINUTE_OF_HOUR.checkValidValue(minute);
+ SECOND_OF_MINUTE.checkValidValue(second);
+ return new LocalTime(hour, minute, second, 0);
+ }
+
+ /**
+ * Obtains an instance of {@code LocalTime} from an hour, minute, second and nanosecond.
+ *
+ * This factory may return a cached value, but applications must not rely on this.
+ *
+ * @param hour the hour-of-day to represent, from 0 to 23
+ * @param minute the minute-of-hour to represent, from 0 to 59
+ * @param second the second-of-minute to represent, from 0 to 59
+ * @param nanoOfSecond the nano-of-second to represent, from 0 to 999,999,999
+ * @return the local time, not null
+ * @throws DateTimeException if the value of any field is out of range
+ */
+ public static LocalTime of(int hour, int minute, int second, int nanoOfSecond) {
+ HOUR_OF_DAY.checkValidValue(hour);
+ MINUTE_OF_HOUR.checkValidValue(minute);
+ SECOND_OF_MINUTE.checkValidValue(second);
+ NANO_OF_SECOND.checkValidValue(nanoOfSecond);
+ return create(hour, minute, second, nanoOfSecond);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code LocalTime} from a second-of-day value.
+ *
+ * This factory may return a cached value, but applications must not rely on this.
+ *
+ * @param secondOfDay the second-of-day, from {@code 0} to {@code 24 * 60 * 60 - 1}
+ * @return the local time, not null
+ * @throws DateTimeException if the second-of-day value is invalid
+ */
+ public static LocalTime ofSecondOfDay(long secondOfDay) {
+ SECOND_OF_DAY.checkValidValue(secondOfDay);
+ int hours = (int) (secondOfDay / SECONDS_PER_HOUR);
+ secondOfDay -= hours * SECONDS_PER_HOUR;
+ int minutes = (int) (secondOfDay / SECONDS_PER_MINUTE);
+ secondOfDay -= minutes * SECONDS_PER_MINUTE;
+ return create(hours, minutes, (int) secondOfDay, 0);
+ }
+
+ /**
+ * Obtains an instance of {@code LocalTime} from a second-of-day value, with
+ * associated nanos of second.
+ *
+ * This factory may return a cached value, but applications must not rely on this.
+ *
+ * @param secondOfDay the second-of-day, from {@code 0} to {@code 24 * 60 * 60 - 1}
+ * @param nanoOfSecond the nano-of-second, from 0 to 999,999,999
+ * @return the local time, not null
+ * @throws DateTimeException if the either input value is invalid
+ */
+ public static LocalTime ofSecondOfDay(long secondOfDay, int nanoOfSecond) {
+ SECOND_OF_DAY.checkValidValue(secondOfDay);
+ NANO_OF_SECOND.checkValidValue(nanoOfSecond);
+ int hours = (int) (secondOfDay / SECONDS_PER_HOUR);
+ secondOfDay -= hours * SECONDS_PER_HOUR;
+ int minutes = (int) (secondOfDay / SECONDS_PER_MINUTE);
+ secondOfDay -= minutes * SECONDS_PER_MINUTE;
+ return create(hours, minutes, (int) secondOfDay, nanoOfSecond);
+ }
+
+ /**
+ * Obtains an instance of {@code LocalTime} from a nanos-of-day value.
+ *
+ * This factory may return a cached value, but applications must not rely on this.
+ *
+ * @param nanoOfDay the nano of day, from {@code 0} to {@code 24 * 60 * 60 * 1,000,000,000 - 1}
+ * @return the local time, not null
+ * @throws DateTimeException if the nanos of day value is invalid
+ */
+ public static LocalTime ofNanoOfDay(long nanoOfDay) {
+ NANO_OF_DAY.checkValidValue(nanoOfDay);
+ int hours = (int) (nanoOfDay / NANOS_PER_HOUR);
+ nanoOfDay -= hours * NANOS_PER_HOUR;
+ int minutes = (int) (nanoOfDay / NANOS_PER_MINUTE);
+ nanoOfDay -= minutes * NANOS_PER_MINUTE;
+ int seconds = (int) (nanoOfDay / NANOS_PER_SECOND);
+ nanoOfDay -= seconds * NANOS_PER_SECOND;
+ return create(hours, minutes, seconds, (int) nanoOfDay);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code LocalTime} from a temporal object.
+ *
+ * A {@code TemporalAccessor} represents some form of date and time information.
+ * This factory converts the arbitrary temporal object to an instance of {@code LocalTime}.
+ *
+ * The conversion extracts the {@link ChronoField#NANO_OF_DAY NANO_OF_DAY} field.
+ *
+ * This method matches the signature of the functional interface {@link TemporalQuery}
+ * allowing it to be used in queries via method reference, {@code LocalTime::from}.
+ *
+ * @param temporal the temporal object to convert, not null
+ * @return the local time, not null
+ * @throws DateTimeException if unable to convert to a {@code LocalTime}
+ */
+ public static LocalTime from(TemporalAccessor temporal) {
+ if (temporal instanceof LocalTime) {
+ return (LocalTime) temporal;
+ } else if (temporal instanceof ChronoLocalDateTime) {
+ return ((ChronoLocalDateTime) temporal).getTime();
+ } else if (temporal instanceof ChronoZonedDateTime) {
+ return ((ChronoZonedDateTime) temporal).getTime();
+ }
+ // handle builder as a special case
+ if (temporal instanceof DateTimeBuilder) {
+ DateTimeBuilder builder = (DateTimeBuilder) temporal;
+ LocalTime time = builder.extract(LocalTime.class);
+ if (time != null) {
+ return time;
+ }
+ }
+ try {
+ return ofNanoOfDay(temporal.getLong(NANO_OF_DAY));
+ } catch (DateTimeException ex) {
+ throw new DateTimeException("Unable to obtain LocalTime from TemporalAccessor: " + temporal.getClass(), ex);
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code LocalTime} from a text string such as {@code 10:15}.
+ *
+ * The string must represent a valid time and is parsed using
+ * {@link java.time.format.DateTimeFormatters#isoLocalTime()}.
+ *
+ * @param text the text to parse such as "10:15:30", not null
+ * @return the parsed local time, not null
+ * @throws DateTimeParseException if the text cannot be parsed
+ */
+ public static LocalTime parse(CharSequence text) {
+ return parse(text, DateTimeFormatters.isoLocalTime());
+ }
+
+ /**
+ * Obtains an instance of {@code LocalTime} from a text string using a specific formatter.
+ *
+ * The text is parsed using the formatter, returning a time.
+ *
+ * @param text the text to parse, not null
+ * @param formatter the formatter to use, not null
+ * @return the parsed local time, not null
+ * @throws DateTimeParseException if the text cannot be parsed
+ */
+ public static LocalTime parse(CharSequence text, DateTimeFormatter formatter) {
+ Objects.requireNonNull(formatter, "formatter");
+ return formatter.parse(text, LocalTime::from);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Creates a local time from the hour, minute, second and nanosecond fields.
+ *
+ * This factory may return a cached value, but applications must not rely on this.
+ *
+ * @param hour the hour-of-day to represent, validated from 0 to 23
+ * @param minute the minute-of-hour to represent, validated from 0 to 59
+ * @param second the second-of-minute to represent, validated from 0 to 59
+ * @param nanoOfSecond the nano-of-second to represent, validated from 0 to 999,999,999
+ * @return the local time, not null
+ */
+ private static LocalTime create(int hour, int minute, int second, int nanoOfSecond) {
+ if ((minute | second | nanoOfSecond) == 0) {
+ return HOURS[hour];
+ }
+ return new LocalTime(hour, minute, second, nanoOfSecond);
+ }
+
+ /**
+ * Constructor, previously validated.
+ *
+ * @param hour the hour-of-day to represent, validated from 0 to 23
+ * @param minute the minute-of-hour to represent, validated from 0 to 59
+ * @param second the second-of-minute to represent, validated from 0 to 59
+ * @param nanoOfSecond the nano-of-second to represent, validated from 0 to 999,999,999
+ */
+ private LocalTime(int hour, int minute, int second, int nanoOfSecond) {
+ this.hour = (byte) hour;
+ this.minute = (byte) minute;
+ this.second = (byte) second;
+ this.nano = nanoOfSecond;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks if the specified field is supported.
+ *
+ * This checks if this time can be queried for the specified field.
+ * If false, then calling the {@link #range(TemporalField) range} and
+ * {@link #get(TemporalField) get} methods will throw an exception.
+ *
+ * If the field is a {@link ChronoField} then the query is implemented here.
+ * The supported fields are:
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)}
+ * passing {@code this} as the argument.
+ * Whether the field is supported is determined by the field.
+ *
+ * @param field the field to check, null returns false
+ * @return true if the field is supported on this time, false if not
+ */
+ @Override
+ public boolean isSupported(TemporalField field) {
+ if (field instanceof ChronoField) {
+ return ((ChronoField) field).isTimeField();
+ }
+ return field != null && field.doIsSupported(this);
+ }
+
+ /**
+ * Gets the range of valid values for the specified field.
+ *
+ * The range object expresses the minimum and maximum valid values for a field.
+ * This time is used to enhance the accuracy of the returned range.
+ * If it is not possible to return the range, because the field is not supported
+ * or for some other reason, an exception is thrown.
+ *
+ * If the field is a {@link ChronoField} then the query is implemented here.
+ * The {@link #isSupported(TemporalField) supported fields} will return
+ * appropriate range instances.
+ * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)}
+ * passing {@code this} as the argument.
+ * Whether the range can be obtained is determined by the field.
+ *
+ * @param field the field to query the range for, not null
+ * @return the range of valid values for the field, not null
+ * @throws DateTimeException if the range for the field cannot be obtained
+ */
+ @Override // override for Javadoc
+ public ValueRange range(TemporalField field) {
+ return Temporal.super.range(field);
+ }
+
+ /**
+ * Gets the value of the specified field from this time as an {@code int}.
+ *
+ * This queries this time for the value for the specified field.
+ * The returned value will always be within the valid range of values for the field.
+ * If it is not possible to return the value, because the field is not supported
+ * or for some other reason, an exception is thrown.
+ *
+ * If the field is a {@link ChronoField} then the query is implemented here.
+ * The {@link #isSupported(TemporalField) supported fields} will return valid
+ * values based on this time, except {@code NANO_OF_DAY} and {@code MICRO_OF_DAY}
+ * which are too large to fit in an {@code int} and throw a {@code DateTimeException}.
+ * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+ * passing {@code this} as the argument. Whether the value can be obtained,
+ * and what the value represents, is determined by the field.
+ *
+ * @param field the field to get, not null
+ * @return the value for the field
+ * @throws DateTimeException if a value for the field cannot be obtained
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override // override for Javadoc and performance
+ public int get(TemporalField field) {
+ if (field instanceof ChronoField) {
+ return get0(field);
+ }
+ return Temporal.super.get(field);
+ }
+
+ /**
+ * Gets the value of the specified field from this time as a {@code long}.
+ *
+ * This queries this time for the value for the specified field.
+ * If it is not possible to return the value, because the field is not supported
+ * or for some other reason, an exception is thrown.
+ *
+ * If the field is a {@link ChronoField} then the query is implemented here.
+ * The {@link #isSupported(TemporalField) supported fields} will return valid
+ * values based on this time.
+ * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+ * passing {@code this} as the argument. Whether the value can be obtained,
+ * and what the value represents, is determined by the field.
+ *
+ * @param field the field to get, not null
+ * @return the value for the field
+ * @throws DateTimeException if a value for the field cannot be obtained
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public long getLong(TemporalField field) {
+ if (field instanceof ChronoField) {
+ if (field == NANO_OF_DAY) {
+ return toNanoOfDay();
+ }
+ if (field == MICRO_OF_DAY) {
+ return toNanoOfDay() / 1000;
+ }
+ return get0(field);
+ }
+ return field.doGet(this);
+ }
+
+ private int get0(TemporalField field) {
+ switch ((ChronoField) field) {
+ case NANO_OF_SECOND: return nano;
+ case NANO_OF_DAY: throw new DateTimeException("Field too large for an int: " + field);
+ case MICRO_OF_SECOND: return nano / 1000;
+ case MICRO_OF_DAY: throw new DateTimeException("Field too large for an int: " + field);
+ case MILLI_OF_SECOND: return nano / 1000_000;
+ case MILLI_OF_DAY: return (int) (toNanoOfDay() / 1000_000);
+ case SECOND_OF_MINUTE: return second;
+ case SECOND_OF_DAY: return toSecondOfDay();
+ case MINUTE_OF_HOUR: return minute;
+ case MINUTE_OF_DAY: return hour * 60 + minute;
+ case HOUR_OF_AMPM: return hour % 12;
+ case CLOCK_HOUR_OF_AMPM: int ham = hour % 12; return (ham % 12 == 0 ? 12 : ham);
+ case HOUR_OF_DAY: return hour;
+ case CLOCK_HOUR_OF_DAY: return (hour == 0 ? 24 : hour);
+ case AMPM_OF_DAY: return hour / 12;
+ }
+ throw new DateTimeException("Unsupported field: " + field.getName());
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the hour-of-day field.
+ *
+ * @return the hour-of-day, from 0 to 23
+ */
+ public int getHour() {
+ return hour;
+ }
+
+ /**
+ * Gets the minute-of-hour field.
+ *
+ * @return the minute-of-hour, from 0 to 59
+ */
+ public int getMinute() {
+ return minute;
+ }
+
+ /**
+ * Gets the second-of-minute field.
+ *
+ * @return the second-of-minute, from 0 to 59
+ */
+ public int getSecond() {
+ return second;
+ }
+
+ /**
+ * Gets the nano-of-second field.
+ *
+ * @return the nano-of-second, from 0 to 999,999,999
+ */
+ public int getNano() {
+ return nano;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns an adjusted copy of this time.
+ *
+ * This returns a new {@code LocalTime}, based on this one, with the time adjusted.
+ * The adjustment takes place using the specified adjuster strategy object.
+ * Read the documentation of the adjuster to understand what adjustment will be made.
+ *
+ * A simple adjuster might simply set the one of the fields, such as the hour field.
+ * A more complex adjuster might set the time to the last hour of the day.
+ *
+ * The result of this method is obtained by invoking the
+ * {@link TemporalAdjuster#adjustInto(Temporal)} method on the
+ * specified adjuster passing {@code this} as the argument.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param adjuster the adjuster to use, not null
+ * @return a {@code LocalTime} based on {@code this} with the adjustment made, not null
+ * @throws DateTimeException if the adjustment cannot be made
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public LocalTime with(TemporalAdjuster adjuster) {
+ // optimizations
+ if (adjuster instanceof LocalTime) {
+ return (LocalTime) adjuster;
+ }
+ return (LocalTime) adjuster.adjustInto(this);
+ }
+
+ /**
+ * Returns a copy of this time with the specified field set to a new value.
+ *
+ * This returns a new {@code LocalTime}, based on this one, with the value
+ * for the specified field changed.
+ * This can be used to change any supported field, such as the hour, minute or second.
+ * If it is not possible to set the value, because the field is not supported or for
+ * some other reason, an exception is thrown.
+ *
+ * If the field is a {@link ChronoField} then the adjustment is implemented here.
+ * The supported fields behave as follows:
+ *
+ * In all cases, if the new value is outside the valid range of values for the field
+ * then a {@code DateTimeException} will be thrown.
+ *
+ * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doWith(Temporal, long)}
+ * passing {@code this} as the argument. In this case, the field determines
+ * whether and how to adjust the instant.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param field the field to set in the result, not null
+ * @param newValue the new value of the field in the result
+ * @return a {@code LocalTime} based on {@code this} with the specified field set, not null
+ * @throws DateTimeException if the field cannot be set
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public LocalTime with(TemporalField field, long newValue) {
+ if (field instanceof ChronoField) {
+ ChronoField f = (ChronoField) field;
+ f.checkValidValue(newValue);
+ switch (f) {
+ case NANO_OF_SECOND: return withNano((int) newValue);
+ case NANO_OF_DAY: return LocalTime.ofNanoOfDay(newValue);
+ case MICRO_OF_SECOND: return withNano((int) newValue * 1000);
+ case MICRO_OF_DAY: return plusNanos((newValue - toNanoOfDay() / 1000) * 1000);
+ case MILLI_OF_SECOND: return withNano((int) newValue * 1000_000);
+ case MILLI_OF_DAY: return plusNanos((newValue - toNanoOfDay() / 1000_000) * 1000_000);
+ case SECOND_OF_MINUTE: return withSecond((int) newValue);
+ case SECOND_OF_DAY: return plusSeconds(newValue - toSecondOfDay());
+ case MINUTE_OF_HOUR: return withMinute((int) newValue);
+ case MINUTE_OF_DAY: return plusMinutes(newValue - (hour * 60 + minute));
+ case HOUR_OF_AMPM: return plusHours(newValue - (hour % 12));
+ case CLOCK_HOUR_OF_AMPM: return plusHours((newValue == 12 ? 0 : newValue) - (hour % 12));
+ case HOUR_OF_DAY: return withHour((int) newValue);
+ case CLOCK_HOUR_OF_DAY: return withHour((int) (newValue == 24 ? 0 : newValue));
+ case AMPM_OF_DAY: return plusHours((newValue - (hour / 12)) * 12);
+ }
+ throw new DateTimeException("Unsupported field: " + field.getName());
+ }
+ return field.doWith(this, newValue);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this {@code LocalTime} with the hour-of-day value altered.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param hour the hour-of-day to set in the result, from 0 to 23
+ * @return a {@code LocalTime} based on this time with the requested hour, not null
+ * @throws DateTimeException if the hour value is invalid
+ */
+ public LocalTime withHour(int hour) {
+ if (this.hour == hour) {
+ return this;
+ }
+ HOUR_OF_DAY.checkValidValue(hour);
+ return create(hour, minute, second, nano);
+ }
+
+ /**
+ * Returns a copy of this {@code LocalTime} with the minute-of-hour value altered.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param minute the minute-of-hour to set in the result, from 0 to 59
+ * @return a {@code LocalTime} based on this time with the requested minute, not null
+ * @throws DateTimeException if the minute value is invalid
+ */
+ public LocalTime withMinute(int minute) {
+ if (this.minute == minute) {
+ return this;
+ }
+ MINUTE_OF_HOUR.checkValidValue(minute);
+ return create(hour, minute, second, nano);
+ }
+
+ /**
+ * Returns a copy of this {@code LocalTime} with the second-of-minute value altered.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param second the second-of-minute to set in the result, from 0 to 59
+ * @return a {@code LocalTime} based on this time with the requested second, not null
+ * @throws DateTimeException if the second value is invalid
+ */
+ public LocalTime withSecond(int second) {
+ if (this.second == second) {
+ return this;
+ }
+ SECOND_OF_MINUTE.checkValidValue(second);
+ return create(hour, minute, second, nano);
+ }
+
+ /**
+ * Returns a copy of this {@code LocalTime} with the nano-of-second value altered.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param nanoOfSecond the nano-of-second to set in the result, from 0 to 999,999,999
+ * @return a {@code LocalTime} based on this time with the requested nanosecond, not null
+ * @throws DateTimeException if the nanos value is invalid
+ */
+ public LocalTime withNano(int nanoOfSecond) {
+ if (this.nano == nanoOfSecond) {
+ return this;
+ }
+ NANO_OF_SECOND.checkValidValue(nanoOfSecond);
+ return create(hour, minute, second, nanoOfSecond);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this {@code LocalTime} with the time truncated.
+ *
+ * Truncating the time returns a copy of the original time with fields
+ * smaller than the specified unit set to zero.
+ * For example, truncating with the {@link ChronoUnit#MINUTES minutes} unit
+ * will set the second-of-minute and nano-of-second field to zero.
+ *
+ * Not all units are accepted. The {@link ChronoUnit#DAYS days} unit and time
+ * units with an exact duration can be used, other units throw an exception.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param unit the unit to truncate to, not null
+ * @return a {@code LocalTime} based on this time with the time truncated, not null
+ * @throws DateTimeException if unable to truncate
+ */
+ public LocalTime truncatedTo(TemporalUnit unit) {
+ if (unit == ChronoUnit.NANOS) {
+ return this;
+ } else if (unit == ChronoUnit.DAYS) {
+ return MIDNIGHT;
+ } else if (unit.isDurationEstimated()) {
+ throw new DateTimeException("Unit must not have an estimated duration");
+ }
+ long nod = toNanoOfDay();
+ long dur = unit.getDuration().toNanos();
+ if (dur >= NANOS_PER_DAY) {
+ throw new DateTimeException("Unit must not be a date unit");
+ }
+ nod = (nod / dur) * dur;
+ return ofNanoOfDay(nod);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this date with the specified period added.
+ *
+ * This method returns a new time based on this time with the specified period added.
+ * The adder is typically {@link Period} but may be any other type implementing
+ * the {@link TemporalAdder} interface.
+ * The calculation is delegated to the specified adjuster, which typically calls
+ * back to {@link #plus(long, TemporalUnit)}.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param adder the adder to use, not null
+ * @return a {@code LocalTime} based on this time with the addition made, not null
+ * @throws DateTimeException if the addition cannot be made
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public LocalTime plus(TemporalAdder adder) {
+ return (LocalTime) adder.addTo(this);
+ }
+
+ /**
+ * Returns a copy of this time with the specified period added.
+ *
+ * This method returns a new time based on this time with the specified period added.
+ * This can be used to add any period that is defined by a unit, for example to add hours, minutes or seconds.
+ * The unit is responsible for the details of the calculation, including the resolution
+ * of any edge cases in the calculation.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param amountToAdd the amount of the unit to add to the result, may be negative
+ * @param unit the unit of the period to add, not null
+ * @return a {@code LocalTime} based on this time with the specified period added, not null
+ * @throws DateTimeException if the unit cannot be added to this type
+ */
+ @Override
+ public LocalTime plus(long amountToAdd, TemporalUnit unit) {
+ if (unit instanceof ChronoUnit) {
+ ChronoUnit f = (ChronoUnit) unit;
+ switch (f) {
+ case NANOS: return plusNanos(amountToAdd);
+ case MICROS: return plusNanos((amountToAdd % MICROS_PER_DAY) * 1000);
+ case MILLIS: return plusNanos((amountToAdd % MILLIS_PER_DAY) * 1000_000);
+ case SECONDS: return plusSeconds(amountToAdd);
+ case MINUTES: return plusMinutes(amountToAdd);
+ case HOURS: return plusHours(amountToAdd);
+ case HALF_DAYS: return plusHours((amountToAdd % 2) * 12);
+ case DAYS: return this;
+ }
+ throw new DateTimeException("Unsupported unit: " + unit.getName());
+ }
+ return unit.doPlus(this, amountToAdd);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this {@code LocalTime} with the specified period in hours added.
+ *
+ * This adds the specified number of hours to this time, returning a new time.
+ * The calculation wraps around midnight.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param hoursToAdd the hours to add, may be negative
+ * @return a {@code LocalTime} based on this time with the hours added, not null
+ */
+ public LocalTime plusHours(long hoursToAdd) {
+ if (hoursToAdd == 0) {
+ return this;
+ }
+ int newHour = ((int) (hoursToAdd % HOURS_PER_DAY) + hour + HOURS_PER_DAY) % HOURS_PER_DAY;
+ return create(newHour, minute, second, nano);
+ }
+
+ /**
+ * Returns a copy of this {@code LocalTime} with the specified period in minutes added.
+ *
+ * This adds the specified number of minutes to this time, returning a new time.
+ * The calculation wraps around midnight.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param minutesToAdd the minutes to add, may be negative
+ * @return a {@code LocalTime} based on this time with the minutes added, not null
+ */
+ public LocalTime plusMinutes(long minutesToAdd) {
+ if (minutesToAdd == 0) {
+ return this;
+ }
+ int mofd = hour * MINUTES_PER_HOUR + minute;
+ int newMofd = ((int) (minutesToAdd % MINUTES_PER_DAY) + mofd + MINUTES_PER_DAY) % MINUTES_PER_DAY;
+ if (mofd == newMofd) {
+ return this;
+ }
+ int newHour = newMofd / MINUTES_PER_HOUR;
+ int newMinute = newMofd % MINUTES_PER_HOUR;
+ return create(newHour, newMinute, second, nano);
+ }
+
+ /**
+ * Returns a copy of this {@code LocalTime} with the specified period in seconds added.
+ *
+ * This adds the specified number of seconds to this time, returning a new time.
+ * The calculation wraps around midnight.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param secondstoAdd the seconds to add, may be negative
+ * @return a {@code LocalTime} based on this time with the seconds added, not null
+ */
+ public LocalTime plusSeconds(long secondstoAdd) {
+ if (secondstoAdd == 0) {
+ return this;
+ }
+ int sofd = hour * SECONDS_PER_HOUR +
+ minute * SECONDS_PER_MINUTE + second;
+ int newSofd = ((int) (secondstoAdd % SECONDS_PER_DAY) + sofd + SECONDS_PER_DAY) % SECONDS_PER_DAY;
+ if (sofd == newSofd) {
+ return this;
+ }
+ int newHour = newSofd / SECONDS_PER_HOUR;
+ int newMinute = (newSofd / SECONDS_PER_MINUTE) % MINUTES_PER_HOUR;
+ int newSecond = newSofd % SECONDS_PER_MINUTE;
+ return create(newHour, newMinute, newSecond, nano);
+ }
+
+ /**
+ * Returns a copy of this {@code LocalTime} with the specified period in nanoseconds added.
+ *
+ * This adds the specified number of nanoseconds to this time, returning a new time.
+ * The calculation wraps around midnight.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param nanosToAdd the nanos to add, may be negative
+ * @return a {@code LocalTime} based on this time with the nanoseconds added, not null
+ */
+ public LocalTime plusNanos(long nanosToAdd) {
+ if (nanosToAdd == 0) {
+ return this;
+ }
+ long nofd = toNanoOfDay();
+ long newNofd = ((nanosToAdd % NANOS_PER_DAY) + nofd + NANOS_PER_DAY) % NANOS_PER_DAY;
+ if (nofd == newNofd) {
+ return this;
+ }
+ int newHour = (int) (newNofd / NANOS_PER_HOUR);
+ int newMinute = (int) ((newNofd / NANOS_PER_MINUTE) % MINUTES_PER_HOUR);
+ int newSecond = (int) ((newNofd / NANOS_PER_SECOND) % SECONDS_PER_MINUTE);
+ int newNano = (int) (newNofd % NANOS_PER_SECOND);
+ return create(newHour, newMinute, newSecond, newNano);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this time with the specified period subtracted.
+ *
+ * This method returns a new time based on this time with the specified period subtracted.
+ * The subtractor is typically {@link Period} but may be any other type implementing
+ * the {@link TemporalSubtractor} interface.
+ * The calculation is delegated to the specified adjuster, which typically calls
+ * back to {@link #minus(long, TemporalUnit)}.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param subtractor the subtractor to use, not null
+ * @return a {@code LocalTime} based on this time with the subtraction made, not null
+ * @throws DateTimeException if the subtraction cannot be made
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public LocalTime minus(TemporalSubtractor subtractor) {
+ return (LocalTime) subtractor.subtractFrom(this);
+ }
+
+ /**
+ * Returns a copy of this time with the specified period subtracted.
+ *
+ * This method returns a new time based on this time with the specified period subtracted.
+ * This can be used to subtract any period that is defined by a unit, for example to subtract hours, minutes or seconds.
+ * The unit is responsible for the details of the calculation, including the resolution
+ * of any edge cases in the calculation.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param amountToSubtract the amount of the unit to subtract from the result, may be negative
+ * @param unit the unit of the period to subtract, not null
+ * @return a {@code LocalTime} based on this time with the specified period subtracted, not null
+ * @throws DateTimeException if the unit cannot be added to this type
+ */
+ @Override
+ public LocalTime minus(long amountToSubtract, TemporalUnit unit) {
+ return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this {@code LocalTime} with the specified period in hours subtracted.
+ *
+ * This subtracts the specified number of hours from this time, returning a new time.
+ * The calculation wraps around midnight.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param hoursToSubtract the hours to subtract, may be negative
+ * @return a {@code LocalTime} based on this time with the hours subtracted, not null
+ */
+ public LocalTime minusHours(long hoursToSubtract) {
+ return plusHours(-(hoursToSubtract % HOURS_PER_DAY));
+ }
+
+ /**
+ * Returns a copy of this {@code LocalTime} with the specified period in minutes subtracted.
+ *
+ * This subtracts the specified number of minutes from this time, returning a new time.
+ * The calculation wraps around midnight.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param minutesToSubtract the minutes to subtract, may be negative
+ * @return a {@code LocalTime} based on this time with the minutes subtracted, not null
+ */
+ public LocalTime minusMinutes(long minutesToSubtract) {
+ return plusMinutes(-(minutesToSubtract % MINUTES_PER_DAY));
+ }
+
+ /**
+ * Returns a copy of this {@code LocalTime} with the specified period in seconds subtracted.
+ *
+ * This subtracts the specified number of seconds from this time, returning a new time.
+ * The calculation wraps around midnight.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param secondsToSubtract the seconds to subtract, may be negative
+ * @return a {@code LocalTime} based on this time with the seconds subtracted, not null
+ */
+ public LocalTime minusSeconds(long secondsToSubtract) {
+ return plusSeconds(-(secondsToSubtract % SECONDS_PER_DAY));
+ }
+
+ /**
+ * Returns a copy of this {@code LocalTime} with the specified period in nanoseconds subtracted.
+ *
+ * This subtracts the specified number of nanoseconds from this time, returning a new time.
+ * The calculation wraps around midnight.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param nanosToSubtract the nanos to subtract, may be negative
+ * @return a {@code LocalTime} based on this time with the nanoseconds subtracted, not null
+ */
+ public LocalTime minusNanos(long nanosToSubtract) {
+ return plusNanos(-(nanosToSubtract % NANOS_PER_DAY));
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Queries this time using the specified query.
+ *
+ * This queries this time using the specified query strategy object.
+ * The {@code TemporalQuery} object defines the logic to be used to
+ * obtain the result. Read the documentation of the query to understand
+ * what the result of this method will be.
+ *
+ * The result of this method is obtained by invoking the
+ * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
+ * specified query passing {@code this} as the argument.
+ *
+ * @param
+ * This returns a temporal object of the same observable type as the input
+ * with the time changed to be the same as this.
+ *
+ * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+ * passing {@link ChronoField#NANO_OF_DAY} as the field.
+ *
+ * In most cases, it is clearer to reverse the calling pattern by using
+ * {@link Temporal#with(TemporalAdjuster)}:
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param temporal the target object to be adjusted, not null
+ * @return the adjusted object, not null
+ * @throws DateTimeException if unable to make the adjustment
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public Temporal adjustInto(Temporal temporal) {
+ return temporal.with(NANO_OF_DAY, toNanoOfDay());
+ }
+
+ /**
+ * Calculates the period between this time and another time in
+ * terms of the specified unit.
+ *
+ * This calculates the period between two times in terms of a single unit.
+ * The start and end points are {@code this} and the specified time.
+ * The result will be negative if the end is before the start.
+ * The {@code Temporal} passed to this method must be a {@code LocalTime}.
+ * For example, the period in hours between two times can be calculated
+ * using {@code startTime.periodUntil(endTime, HOURS)}.
+ *
+ * The calculation returns a whole number, representing the number of
+ * complete units between the two times.
+ * For example, the period in hours between 11:30 and 13:29 will only
+ * be one hour as it is one minute short of two hours.
+ *
+ * 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:
+ *
+ * The calculation is implemented in this method for {@link ChronoUnit}.
+ * The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS},
+ * {@code MINUTES}, {@code HOURS} and {@code HALF_DAYS} are supported.
+ * Other {@code ChronoUnit} values will throw an exception.
+ *
+ * If the unit is not a {@code ChronoUnit}, then the result of this method
+ * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
+ * passing {@code this} as the first argument and the input temporal as
+ * the second argument.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param endTime the end time, which must be a {@code LocalTime}, not null
+ * @param unit the unit to measure the period in, not null
+ * @return the amount of the period between this time and the end time
+ * @throws DateTimeException if the period cannot be calculated
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public long periodUntil(Temporal endTime, TemporalUnit unit) {
+ if (endTime instanceof LocalTime == false) {
+ Objects.requireNonNull(endTime, "endTime");
+ throw new DateTimeException("Unable to calculate period between objects of two different types");
+ }
+ LocalTime end = (LocalTime) endTime;
+ if (unit instanceof ChronoUnit) {
+ long nanosUntil = end.toNanoOfDay() - toNanoOfDay(); // no overflow
+ switch ((ChronoUnit) unit) {
+ case NANOS: return nanosUntil;
+ case MICROS: return nanosUntil / 1000;
+ case MILLIS: return nanosUntil / 1000_000;
+ case SECONDS: return nanosUntil / NANOS_PER_SECOND;
+ case MINUTES: return nanosUntil / NANOS_PER_MINUTE;
+ case HOURS: return nanosUntil / NANOS_PER_HOUR;
+ case HALF_DAYS: return nanosUntil / (12 * NANOS_PER_HOUR);
+ }
+ throw new DateTimeException("Unsupported unit: " + unit.getName());
+ }
+ return unit.between(this, endTime).getAmount();
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a local date-time formed from this time at the specified date.
+ *
+ * This combines this time with the specified date to form a {@code LocalDateTime}.
+ * All possible combinations of date and time are valid.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param date the date to combine with, not null
+ * @return the local date-time formed from this time and the specified date, not null
+ */
+ public LocalDateTime atDate(LocalDate date) {
+ return LocalDateTime.of(date, this);
+ }
+
+ /**
+ * Returns an offset time formed from this time and the specified offset.
+ *
+ * This combines this time with the specified offset to form an {@code OffsetTime}.
+ * All possible combinations of time and offset are valid.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param offset the offset to combine with, not null
+ * @return the offset time formed from this time and the specified offset, not null
+ */
+ public OffsetTime atOffset(ZoneOffset offset) {
+ return OffsetTime.of(this, offset);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Extracts the time as seconds of day,
+ * from {@code 0} to {@code 24 * 60 * 60 - 1}.
+ *
+ * @return the second-of-day equivalent to this time
+ */
+ public int toSecondOfDay() {
+ int total = hour * SECONDS_PER_HOUR;
+ total += minute * SECONDS_PER_MINUTE;
+ total += second;
+ return total;
+ }
+
+ /**
+ * Extracts the time as nanos of day,
+ * from {@code 0} to {@code 24 * 60 * 60 * 1,000,000,000 - 1}.
+ *
+ * @return the nano of day equivalent to this time
+ */
+ public long toNanoOfDay() {
+ long total = hour * NANOS_PER_HOUR;
+ total += minute * NANOS_PER_MINUTE;
+ total += second * NANOS_PER_SECOND;
+ total += nano;
+ return total;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Compares this {@code LocalTime} to another time.
+ *
+ * The comparison is based on the time-line position of the local times within a day.
+ * It is "consistent with equals", as defined by {@link Comparable}.
+ *
+ * @param other the other time to compare to, not null
+ * @return the comparator value, negative if less, positive if greater
+ * @throws NullPointerException if {@code other} is null
+ */
+ @Override
+ public int compareTo(LocalTime other) {
+ int cmp = Integer.compare(hour, other.hour);
+ if (cmp == 0) {
+ cmp = Integer.compare(minute, other.minute);
+ if (cmp == 0) {
+ cmp = Integer.compare(second, other.second);
+ if (cmp == 0) {
+ cmp = Integer.compare(nano, other.nano);
+ }
+ }
+ }
+ return cmp;
+ }
+
+ /**
+ * Checks if this {@code LocalTime} is after the specified time.
+ *
+ * The comparison is based on the time-line position of the time within a day.
+ *
+ * @param other the other time to compare to, not null
+ * @return true if this is after the specified time
+ * @throws NullPointerException if {@code other} is null
+ */
+ public boolean isAfter(LocalTime other) {
+ return compareTo(other) > 0;
+ }
+
+ /**
+ * Checks if this {@code LocalTime} is before the specified time.
+ *
+ * The comparison is based on the time-line position of the time within a day.
+ *
+ * @param other the other time to compare to, not null
+ * @return true if this point is before the specified time
+ * @throws NullPointerException if {@code other} is null
+ */
+ public boolean isBefore(LocalTime other) {
+ return compareTo(other) < 0;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks if this time is equal to another time.
+ *
+ * The comparison is based on the time-line position of the time within a day.
+ *
+ * Only objects of type {@code LocalTime} are compared, other types return false.
+ * To compare the date of two {@code TemporalAccessor} instances, use
+ * {@link ChronoField#NANO_OF_DAY} as a comparator.
+ *
+ * @param obj the object to check, null returns false
+ * @return true if this is equal to the other time
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof LocalTime) {
+ LocalTime other = (LocalTime) obj;
+ return hour == other.hour && minute == other.minute &&
+ second == other.second && nano == other.nano;
+ }
+ return false;
+ }
+
+ /**
+ * A hash code for this time.
+ *
+ * @return a suitable hash code
+ */
+ @Override
+ public int hashCode() {
+ long nod = toNanoOfDay();
+ return (int) (nod ^ (nod >>> 32));
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Outputs this time as a {@code String}, such as {@code 10:15}.
+ *
+ * The output will be one of the following ISO-8601 formats:
+ *
+ * The format used will be the shortest that outputs the full value of
+ * the time where the omitted parts are implied to be zero.
+ *
+ * @return a string representation of this time, not null
+ */
+ @Override
+ public String toString() {
+ StringBuilder buf = new StringBuilder(18);
+ int hourValue = hour;
+ int minuteValue = minute;
+ int secondValue = second;
+ int nanoValue = nano;
+ buf.append(hourValue < 10 ? "0" : "").append(hourValue)
+ .append(minuteValue < 10 ? ":0" : ":").append(minuteValue);
+ if (secondValue > 0 || nanoValue > 0) {
+ buf.append(secondValue < 10 ? ":0" : ":").append(secondValue);
+ if (nanoValue > 0) {
+ buf.append('.');
+ if (nanoValue % 1000_000 == 0) {
+ buf.append(Integer.toString((nanoValue / 1000_000) + 1000).substring(1));
+ } else if (nanoValue % 1000 == 0) {
+ buf.append(Integer.toString((nanoValue / 1000) + 1000_000).substring(1));
+ } else {
+ buf.append(Integer.toString((nanoValue) + 1000_000_000).substring(1));
+ }
+ }
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Outputs this time as a {@code String} using the formatter.
+ *
+ * This time will be passed to the formatter
+ * {@link DateTimeFormatter#print(TemporalAccessor) print method}.
+ *
+ * @param formatter the formatter to use, not null
+ * @return the formatted time string, not null
+ * @throws DateTimeException if an error occurs during printing
+ */
+ public String toString(DateTimeFormatter formatter) {
+ Objects.requireNonNull(formatter, "formatter");
+ return formatter.print(this);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Writes the object using a
+ * dedicated serialized form.
+ *
+ * {@code Month} is an enum representing the 12 months of the year -
+ * January, February, March, April, May, June, July, August, September, October,
+ * November and December.
+ *
+ * In addition to the textual enum name, each month-of-year has an {@code int} value.
+ * The {@code int} value follows normal usage and the ISO-8601 standard,
+ * from 1 (January) to 12 (December). It is recommended that applications use the enum
+ * rather than the {@code int} value to ensure code clarity.
+ *
+ * Do not use {@code ordinal()} to obtain the numeric representation of {@code Month}.
+ * Use {@code getValue()} instead.
+ *
+ * This enum represents a common concept that is found in many calendar systems.
+ * As such, this enum may be used by any calendar system that has the month-of-year
+ * concept defined exactly equivalent to the ISO-8601 calendar system.
+ *
+ *
+ * {@code Month} is an enum representing the 12 months of the year.
+ * This factory allows the enum to be obtained from the {@code int} value.
+ * The {@code int} value follows the ISO-8601 standard, from 1 (January) to 12 (December).
+ *
+ * @param month the month-of-year to represent, from 1 (January) to 12 (December)
+ * @return the month-of-year, not null
+ * @throws DateTimeException if the month-of-year is invalid
+ */
+ public static Month of(int month) {
+ if (month < 1 || month > 12) {
+ throw new DateTimeException("Invalid value for MonthOfYear: " + month);
+ }
+ return ENUMS[month - 1];
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code Month} from a temporal object.
+ *
+ * A {@code TemporalAccessor} represents some form of date and time information.
+ * This factory converts the arbitrary temporal object to an instance of {@code Month}.
+ *
+ * The conversion extracts the {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} field.
+ * The extraction is only permitted if the temporal object has an ISO
+ * chronology, or can be converted to a {@code LocalDate}.
+ *
+ * This method matches the signature of the functional interface {@link TemporalQuery}
+ * allowing it to be used in queries via method reference, {@code Month::from}.
+ *
+ * @param temporal the temporal object to convert, not null
+ * @return the month-of-year, not null
+ * @throws DateTimeException if unable to convert to a {@code Month}
+ */
+ public static Month from(TemporalAccessor temporal) {
+ if (temporal instanceof Month) {
+ return (Month) temporal;
+ }
+ try {
+ if (ISOChrono.INSTANCE.equals(Chrono.from(temporal)) == false) {
+ temporal = LocalDate.from(temporal);
+ }
+ return of(temporal.get(MONTH_OF_YEAR));
+ } catch (DateTimeException ex) {
+ throw new DateTimeException("Unable to obtain Month from TemporalAccessor: " + temporal.getClass(), ex);
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the month-of-year {@code int} value.
+ *
+ * The values are numbered following the ISO-8601 standard,
+ * from 1 (January) to 12 (December).
+ *
+ * @return the month-of-year, from 1 (January) to 12 (December)
+ */
+ public int getValue() {
+ return ordinal() + 1;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the textual representation, such as 'Jan' or 'December'.
+ *
+ * This returns the textual name used to identify the month-of-year.
+ * The parameters control the length of the returned text and the locale.
+ *
+ * If no textual mapping is found then the {@link #getValue() numeric value} is returned.
+ *
+ * @param style the length of the text required, not null
+ * @param locale the locale to use, not null
+ * @return the text value of the month-of-year, not null
+ */
+ public String getText(TextStyle style, Locale locale) {
+ return new DateTimeFormatterBuilder().appendText(MONTH_OF_YEAR, style).toFormatter(locale).print(this);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks if the specified field is supported.
+ *
+ * This checks if this month-of-year can be queried for the specified field.
+ * If false, then calling the {@link #range(TemporalField) range} and
+ * {@link #get(TemporalField) get} methods will throw an exception.
+ *
+ * If the field is {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} then
+ * this method returns true.
+ * All other {@code ChronoField} instances will return false.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)}
+ * passing {@code this} as the argument.
+ * Whether the field is supported is determined by the field.
+ *
+ * @param field the field to check, null returns false
+ * @return true if the field is supported on this month-of-year, false if not
+ */
+ @Override
+ public boolean isSupported(TemporalField field) {
+ if (field instanceof ChronoField) {
+ return field == MONTH_OF_YEAR;
+ }
+ return field != null && field.doIsSupported(this);
+ }
+
+ /**
+ * Gets the range of valid values for the specified field.
+ *
+ * The range object expresses the minimum and maximum valid values for a field.
+ * This month is used to enhance the accuracy of the returned range.
+ * If it is not possible to return the range, because the field is not supported
+ * or for some other reason, an exception is thrown.
+ *
+ * If the field is {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} then the
+ * range of the month-of-year, from 1 to 12, will be returned.
+ * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)}
+ * passing {@code this} as the argument.
+ * Whether the range can be obtained is determined by the field.
+ *
+ * @param field the field to query the range for, not null
+ * @return the range of valid values for the field, not null
+ * @throws DateTimeException if the range for the field cannot be obtained
+ */
+ @Override
+ public ValueRange range(TemporalField field) {
+ if (field == MONTH_OF_YEAR) {
+ return field.range();
+ }
+ return TemporalAccessor.super.range(field);
+ }
+
+ /**
+ * Gets the value of the specified field from this month-of-year as an {@code int}.
+ *
+ * This queries this month for the value for the specified field.
+ * The returned value will always be within the valid range of values for the field.
+ * If it is not possible to return the value, because the field is not supported
+ * or for some other reason, an exception is thrown.
+ *
+ * If the field is {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} then the
+ * value of the month-of-year, from 1 to 12, will be returned.
+ * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+ * passing {@code this} as the argument. Whether the value can be obtained,
+ * and what the value represents, is determined by the field.
+ *
+ * @param field the field to get, not null
+ * @return the value for the field, within the valid range of values
+ * @throws DateTimeException if a value for the field cannot be obtained
+ * @throws DateTimeException if the range of valid values for the field exceeds an {@code int}
+ * @throws DateTimeException if the value is outside the range of valid values for the field
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public int get(TemporalField field) {
+ if (field == MONTH_OF_YEAR) {
+ return getValue();
+ }
+ return TemporalAccessor.super.get(field);
+ }
+
+ /**
+ * Gets the value of the specified field from this month-of-year as a {@code long}.
+ *
+ * This queries this month for the value for the specified field.
+ * If it is not possible to return the value, because the field is not supported
+ * or for some other reason, an exception is thrown.
+ *
+ * If the field is {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} then the
+ * value of the month-of-year, from 1 to 12, will be returned.
+ * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+ * passing {@code this} as the argument. Whether the value can be obtained,
+ * and what the value represents, is determined by the field.
+ *
+ * @param field the field to get, not null
+ * @return the value for the field
+ * @throws DateTimeException if a value for the field cannot be obtained
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public long getLong(TemporalField field) {
+ if (field == MONTH_OF_YEAR) {
+ return getValue();
+ } else if (field instanceof ChronoField) {
+ throw new DateTimeException("Unsupported field: " + field.getName());
+ }
+ return field.doGet(this);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns the month-of-year that is the specified number of quarters after this one.
+ *
+ * The calculation rolls around the end of the year from December to January.
+ * The specified period may be negative.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param months the months to add, positive or negative
+ * @return the resulting month, not null
+ */
+ public Month plus(long months) {
+ int amount = (int) (months % 12);
+ return ENUMS[(ordinal() + (amount + 12)) % 12];
+ }
+
+ /**
+ * Returns the month-of-year that is the specified number of months before this one.
+ *
+ * The calculation rolls around the start of the year from January to December.
+ * The specified period may be negative.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param months the months to subtract, positive or negative
+ * @return the resulting month, not null
+ */
+ public Month minus(long months) {
+ return plus(-(months % 12));
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the length of this month in days.
+ *
+ * This takes a flag to determine whether to return the length for a leap year or not.
+ *
+ * February has 28 days in a standard year and 29 days in a leap year.
+ * April, June, September and November have 30 days.
+ * All other months have 31 days.
+ *
+ * @param leapYear true if the length is required for a leap year
+ * @return the length of this month in days, from 28 to 31
+ */
+ public int length(boolean leapYear) {
+ switch (this) {
+ case FEBRUARY:
+ return (leapYear ? 29 : 28);
+ case APRIL:
+ case JUNE:
+ case SEPTEMBER:
+ case NOVEMBER:
+ return 30;
+ default:
+ return 31;
+ }
+ }
+
+ /**
+ * Gets the minimum length of this month in days.
+ *
+ * February has a minimum length of 28 days.
+ * April, June, September and November have 30 days.
+ * All other months have 31 days.
+ *
+ * @return the minimum length of this month in days, from 28 to 31
+ */
+ public int minLength() {
+ switch (this) {
+ case FEBRUARY:
+ return 28;
+ case APRIL:
+ case JUNE:
+ case SEPTEMBER:
+ case NOVEMBER:
+ return 30;
+ default:
+ return 31;
+ }
+ }
+
+ /**
+ * Gets the maximum length of this month in days.
+ *
+ * February has a maximum length of 29 days.
+ * April, June, September and November have 30 days.
+ * All other months have 31 days.
+ *
+ * @return the maximum length of this month in days, from 29 to 31
+ */
+ public int maxLength() {
+ switch (this) {
+ case FEBRUARY:
+ return 29;
+ case APRIL:
+ case JUNE:
+ case SEPTEMBER:
+ case NOVEMBER:
+ return 30;
+ default:
+ return 31;
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the day-of-year corresponding to the first day of this month.
+ *
+ * This returns the day-of-year that this month begins on, using the leap
+ * year flag to determine the length of February.
+ *
+ * @param leapYear true if the length is required for a leap year
+ * @return the day of year corresponding to the first day of this month, from 1 to 336
+ */
+ public int firstDayOfYear(boolean leapYear) {
+ int leap = leapYear ? 1 : 0;
+ switch (this) {
+ case JANUARY:
+ return 1;
+ case FEBRUARY:
+ return 32;
+ case MARCH:
+ return 60 + leap;
+ case APRIL:
+ return 91 + leap;
+ case MAY:
+ return 121 + leap;
+ case JUNE:
+ return 152 + leap;
+ case JULY:
+ return 182 + leap;
+ case AUGUST:
+ return 213 + leap;
+ case SEPTEMBER:
+ return 244 + leap;
+ case OCTOBER:
+ return 274 + leap;
+ case NOVEMBER:
+ return 305 + leap;
+ case DECEMBER:
+ default:
+ return 335 + leap;
+ }
+ }
+
+ /**
+ * Gets the month corresponding to the first month of this quarter.
+ *
+ * The year can be divided into four quarters.
+ * This method returns the first month of the quarter for the base month.
+ * January, February and March return January.
+ * April, May and June return April.
+ * July, August and September return July.
+ * October, November and December return October.
+ *
+ * @return the first month of the quarter corresponding to this month, not null
+ */
+ public Month firstMonthOfQuarter() {
+ return ENUMS[(ordinal() / 3) * 3];
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Queries this month-of-year using the specified query.
+ *
+ * This queries this month-of-year using the specified query strategy object.
+ * The {@code TemporalQuery} object defines the logic to be used to
+ * obtain the result. Read the documentation of the query to understand
+ * what the result of this method will be.
+ *
+ * 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
+ * This returns a temporal object of the same observable type as the input
+ * with the month-of-year changed to be the same as this.
+ *
+ * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+ * passing {@link ChronoField#MONTH_OF_YEAR} as the field.
+ * If the specified temporal object does not use the ISO calendar system then
+ * a {@code DateTimeException} is thrown.
+ *
+ * In most cases, it is clearer to reverse the calling pattern by using
+ * {@link Temporal#with(TemporalAdjuster)}:
+ *
+ * For example, given a date in May, the following are output:
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param temporal the target object to be adjusted, not null
+ * @return the adjusted object, not null
+ * @throws DateTimeException if unable to make the adjustment
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public Temporal adjustInto(Temporal temporal) {
+ if (Chrono.from(temporal).equals(ISOChrono.INSTANCE) == false) {
+ throw new DateTimeException("Adjustment only supported on ISO date-time");
+ }
+ return temporal.with(MONTH_OF_YEAR, getValue());
+ }
+
+}
diff --git a/src/share/classes/java/time/Period.java b/src/share/classes/java/time/Period.java
new file mode 100644
index 0000000000000000000000000000000000000000..a04aab6a52ccc099217ee384f30fd1368a0422be
--- /dev/null
+++ b/src/share/classes/java/time/Period.java
@@ -0,0 +1,1187 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import static java.time.LocalTime.NANOS_PER_DAY;
+import static java.time.LocalTime.NANOS_PER_HOUR;
+import static java.time.LocalTime.NANOS_PER_MINUTE;
+import static java.time.LocalTime.NANOS_PER_SECOND;
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.EPOCH_MONTH;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.NANO_OF_DAY;
+import static java.time.temporal.ChronoField.YEAR;
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.MONTHS;
+import static java.time.temporal.ChronoUnit.NANOS;
+import static java.time.temporal.ChronoUnit.YEARS;
+
+import java.io.Serializable;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.Chrono;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdder;
+import java.time.temporal.TemporalSubtractor;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.ValueRange;
+import java.util.Objects;
+
+/**
+ * A period of time, measured using the most common units, such as '3 Months, 4 Days and 7 Hours'.
+ *
+ * A {@code Period} represents an amount of time measured in terms of the most commonly used units:
+ *
+ * The period may be used with any calendar system with the exception is methods with an "ISO" suffix.
+ * The meaning of a "year" or a "month" is only applied when the object is added to a date.
+ *
+ * The period is modeled as a directed amount of time, meaning that individual parts of the
+ * period may be negative.
+ *
+ *
+ * This creates an instance based on years, months, days, hours, minutes and seconds.
+ * Within a period, the time fields are always normalized.
+ *
+ * @param years the amount of years, may be negative
+ * @param months the amount of months, may be negative
+ * @param days the amount of days, may be negative
+ * @param hours the amount of hours, may be negative
+ * @param minutes the amount of minutes, may be negative
+ * @param seconds the amount of seconds, may be negative
+ * @return the period, not null
+ */
+ public static Period of(int years, int months, int days, int hours, int minutes, int seconds) {
+ return of(years, months, days, hours, minutes, seconds, 0);
+ }
+
+ /**
+ * Obtains a {@code Period} from date-based and time-based fields.
+ *
+ * This creates an instance based on years, months, days, hours, minutes, seconds and nanoseconds.
+ * Within a period, the time fields are always normalized.
+ *
+ * @param years the amount of years, may be negative
+ * @param months the amount of months, may be negative
+ * @param days the amount of days, may be negative
+ * @param hours the amount of hours, may be negative
+ * @param minutes the amount of minutes, may be negative
+ * @param seconds the amount of seconds, may be negative
+ * @param nanos the amount of nanos, may be negative
+ * @return the period, not null
+ */
+ public static Period of(int years, int months, int days, int hours, int minutes, int seconds, long nanos) {
+ if ((years | months | days | hours | minutes | seconds | nanos) == 0) {
+ return ZERO;
+ }
+ long totSecs = Math.addExact(hours * 3600L, minutes * 60L) + seconds;
+ long totNanos = Math.addExact(Math.multiplyExact(totSecs, 1_000_000_000L), nanos);
+ return create(years, months, days, totNanos);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains a {@code Period} from date-based fields.
+ *
+ * This creates an instance based on years, months and days.
+ *
+ * @param years the amount of years, may be negative
+ * @param months the amount of months, may be negative
+ * @param days the amount of days, may be negative
+ * @return the period, not null
+ */
+ public static Period ofDate(int years, int months, int days) {
+ return of(years, months, days, 0, 0, 0, 0);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains a {@code Period} from time-based fields.
+ *
+ * This creates an instance based on hours, minutes and seconds.
+ * Within a period, the time fields are always normalized.
+ *
+ * @param hours the amount of hours, may be negative
+ * @param minutes the amount of minutes, may be negative
+ * @param seconds the amount of seconds, may be negative
+ * @return the period, not null
+ */
+ public static Period ofTime(int hours, int minutes, int seconds) {
+ return of(0, 0, 0, hours, minutes, seconds, 0);
+ }
+
+ /**
+ * Obtains a {@code Period} from time-based fields.
+ *
+ * This creates an instance based on hours, minutes, seconds and nanoseconds.
+ * Within a period, the time fields are always normalized.
+ *
+ * @param hours the amount of hours, may be negative
+ * @param minutes the amount of minutes, may be negative
+ * @param seconds the amount of seconds, may be negative
+ * @param nanos the amount of nanos, may be negative
+ * @return the period, not null
+ */
+ public static Period ofTime(int hours, int minutes, int seconds, long nanos) {
+ return of(0, 0, 0, hours, minutes, seconds, nanos);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code Period} from a period in the specified unit.
+ *
+ * The parameters represent the two parts of a phrase like '6 Days'. For example:
+ *
+ * This converts the duration to a period.
+ * Within a period, the time fields are always normalized.
+ * The years, months and days fields will be zero.
+ *
+ * To populate the days field, call {@link #normalizedHoursToDays()} on the created period.
+ *
+ * @param duration the duration to convert, not null
+ * @return the period, not null
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ public static Period of(Duration duration) {
+ Objects.requireNonNull(duration, "duration");
+ if (duration.isZero()) {
+ return ZERO;
+ }
+ return new Period(0, 0, 0, duration.toNanos());
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a {@code Period} consisting of the number of years, months, days,
+ * hours, minutes, seconds, and nanoseconds between two {@code TemporalAccessor} instances.
+ *
+ * The start date is included, but the end date is not. Only whole years count.
+ * For example, from {@code 2010-01-15} to {@code 2011-03-18} is one year, two months and three days.
+ *
+ * This method examines the {@link ChronoField fields} {@code YEAR}, {@code MONTH_OF_YEAR},
+ * {@code DAY_OF_MONTH} and {@code NANO_OF_DAY}
+ * The difference between each of the fields is calculated independently from the others.
+ * At least one of the four fields must be present.
+ *
+ * The four units are typically retained without normalization.
+ * However, years and months are normalized if the range of months is fixed, as it is with ISO.
+ *
+ * The result of this method can be a negative period if the end is before the start.
+ * The negative sign can be different in each of the four major units.
+ *
+ * @param start the start date, inclusive, not null
+ * @param end the end date, exclusive, not null
+ * @return the period between the date-times, not null
+ * @throws DateTimeException if the two date-times do have similar available fields
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ public static Period between(TemporalAccessor start, TemporalAccessor end) {
+ if (Chrono.from(start).equals(Chrono.from(end)) == false) {
+ throw new DateTimeException("Unable to calculate period as date-times have different chronologies");
+ }
+ int years = 0;
+ int months = 0;
+ int days = 0;
+ long nanos = 0;
+ boolean valid = false;
+ if (start.isSupported(YEAR)) {
+ years = Math.toIntExact(Math.subtractExact(end.getLong(YEAR), start.getLong(YEAR)));
+ valid = true;
+ }
+ if (start.isSupported(MONTH_OF_YEAR)) {
+ months = Math.toIntExact(Math.subtractExact(end.getLong(MONTH_OF_YEAR), start.getLong(MONTH_OF_YEAR)));
+ ValueRange startRange = Chrono.from(start).range(MONTH_OF_YEAR);
+ ValueRange endRange = Chrono.from(end).range(MONTH_OF_YEAR);
+ if (startRange.isFixed() && startRange.isIntValue() && startRange.equals(endRange)) {
+ int monthCount = (int) (startRange.getMaximum() - startRange.getMinimum() + 1);
+ long totMonths = ((long) months) + years * monthCount;
+ months = (int) (totMonths % monthCount);
+ years = Math.toIntExact(totMonths / monthCount);
+ }
+ valid = true;
+ }
+ if (start.isSupported(DAY_OF_MONTH)) {
+ days = Math.toIntExact(Math.subtractExact(end.getLong(DAY_OF_MONTH), start.getLong(DAY_OF_MONTH)));
+ valid = true;
+ }
+ if (start.isSupported(NANO_OF_DAY)) {
+ nanos = Math.subtractExact(end.getLong(NANO_OF_DAY), start.getLong(NANO_OF_DAY));
+ valid = true;
+ }
+ if (valid == false) {
+ throw new DateTimeException("Unable to calculate period as date-times do not have any valid fields");
+ }
+ return create(years, months, days, nanos);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains a {@code Period} consisting of the number of years, months,
+ * and days between two dates.
+ *
+ * The start date is included, but the end date is not.
+ * The period is calculated by removing complete months, then calculating
+ * the remaining number of days, adjusting to ensure that both have the same sign.
+ * The number of months is then split into years and months based on a 12 month year.
+ * A month is considered if the end day-of-month is greater than or equal to the start day-of-month.
+ * For example, from {@code 2010-01-15} to {@code 2011-03-18} is one year, two months and three days.
+ *
+ * The result of this method can be a negative period if the end is before the start.
+ * The negative sign will be the same in each of year, month and day.
+ *
+ * @param startDate the start date, inclusive, not null
+ * @param endDate the end date, exclusive, not null
+ * @return the period between the dates, not null
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ public static Period betweenISO(LocalDate startDate, LocalDate endDate) {
+ long startMonth = startDate.getLong(EPOCH_MONTH);
+ long endMonth = endDate.getLong(EPOCH_MONTH);
+ long totalMonths = endMonth - startMonth; // safe
+ int days = endDate.getDayOfMonth() - startDate.getDayOfMonth();
+ if (totalMonths > 0 && days < 0) {
+ totalMonths--;
+ LocalDate calcDate = startDate.plusMonths(totalMonths);
+ days = (int) (endDate.toEpochDay() - calcDate.toEpochDay()); // safe
+ } else if (totalMonths < 0 && days > 0) {
+ totalMonths++;
+ days -= endDate.lengthOfMonth();
+ }
+ long years = totalMonths / 12; // safe
+ int months = (int) (totalMonths % 12); // safe
+ return ofDate(Math.toIntExact(years), months, days);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains a {@code Period} consisting of the number of hours, minutes,
+ * seconds and nanoseconds between two times.
+ *
+ * The start time is included, but the end time is not.
+ * The period is calculated from the difference between the nano-of-day values
+ * of the two times. For example, from {@code 13:45:00} to {@code 14:50:30.123456789}
+ * is {@code P1H5M30.123456789S}.
+ *
+ * The result of this method can be a negative period if the end is before the start.
+ *
+ * @param startTime the start time, inclusive, not null
+ * @param endTime the end time, exclusive, not null
+ * @return the period between the times, not null
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ public static Period betweenISO(LocalTime startTime, LocalTime endTime) {
+ return create(0, 0, 0, endTime.toNanoOfDay() - startTime.toNanoOfDay());
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains a {@code Period} from a text string such as {@code PnYnMnDTnHnMn.nS}.
+ *
+ * This will parse the string produced by {@code toString()} which is
+ * a subset of the ISO-8601 period format {@code PnYnMnDTnHnMn.nS}.
+ *
+ * The string consists of a series of numbers with a suffix identifying their meaning.
+ * The values, and suffixes, must be in the sequence year, month, day, hour, minute, second.
+ * Any of the number/suffix pairs may be omitted providing at least one is present.
+ * If the period is zero, the value is normally represented as {@code PT0S}.
+ * The numbers must consist of ASCII digits.
+ * Any of the numbers may be negative. Negative zero is not accepted.
+ * The number of nanoseconds is expressed as an optional fraction of the seconds.
+ * There must be at least one digit before any decimal point.
+ * There must be between 1 and 9 inclusive digits after any decimal point.
+ * The letters will all be accepted in upper or lower case.
+ * The decimal point may be either a dot or a comma.
+ *
+ * @param text the text to parse, not null
+ * @return the parsed period, not null
+ * @throws DateTimeParseException if the text cannot be parsed to a period
+ */
+ public static Period parse(final CharSequence text) {
+ Objects.requireNonNull(text, "text");
+ return new PeriodParser(text).parse();
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Creates an instance.
+ *
+ * @param years the amount
+ * @param months the amount
+ * @param days the amount
+ * @param nanos the amount
+ */
+ private static Period create(int years, int months, int days, long nanos) {
+ if ((years | months | days | nanos) == 0) {
+ return ZERO;
+ }
+ return new Period(years, months, days, nanos);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param years the amount
+ * @param months the amount
+ * @param days the amount
+ * @param nanos the amount
+ */
+ private Period(int years, int months, int days, long nanos) {
+ this.years = years;
+ this.months = months;
+ this.days = days;
+ this.nanos = nanos;
+ }
+
+ /**
+ * Resolves singletons.
+ *
+ * @return the resolved instance
+ */
+ private Object readResolve() {
+ if ((years | months | days | nanos) == 0) {
+ return ZERO;
+ }
+ return this;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks if this period is zero-length.
+ *
+ * @return true if this period is zero-length
+ */
+ public boolean isZero() {
+ return (this == ZERO);
+ }
+
+ /**
+ * Checks if this period is fully positive, excluding zero.
+ *
+ * This checks whether all the amounts in the period are positive,
+ * defined as greater than zero.
+ *
+ * @return true if this period is fully positive excluding zero
+ */
+ public boolean isPositive() {
+ return ((years | months | days | nanos) > 0);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the amount of years of this period.
+ *
+ * @return the amount of years of this period
+ */
+ public int getYears() {
+ return years;
+ }
+
+ /**
+ * Gets the amount of months of this period.
+ *
+ * @return the amount of months of this period
+ */
+ public int getMonths() {
+ return months;
+ }
+
+ /**
+ * Gets the amount of days of this period.
+ *
+ * @return the amount of days of this period
+ */
+ public int getDays() {
+ return days;
+ }
+
+ /**
+ * Gets the amount of hours of this period.
+ *
+ * Within a period, the time fields are always normalized.
+ *
+ * @return the amount of hours of this period
+ */
+ public int getHours() {
+ return (int) (nanos / NANOS_PER_HOUR);
+ }
+
+ /**
+ * Gets the amount of minutes within an hour of this period.
+ *
+ * Within a period, the time fields are always normalized.
+ *
+ * @return the amount of minutes within an hour of this period
+ */
+ public int getMinutes() {
+ return (int) ((nanos / NANOS_PER_MINUTE) % 60);
+ }
+
+ /**
+ * Gets the amount of seconds within a minute of this period.
+ *
+ * Within a period, the time fields are always normalized.
+ *
+ * @return the amount of seconds within a minute of this period
+ */
+ public int getSeconds() {
+ return (int) ((nanos / NANOS_PER_SECOND) % 60);
+ }
+
+ /**
+ * Gets the amount of nanoseconds within a second of this period.
+ *
+ * Within a period, the time fields are always normalized.
+ *
+ * @return the amount of nanoseconds within a second of this period
+ */
+ public int getNanos() {
+ return (int) (nanos % NANOS_PER_SECOND); // safe from overflow
+ }
+
+ /**
+ * Gets the total amount of the time units of this period, measured in nanoseconds.
+ *
+ * Within a period, the time fields are always normalized.
+ *
+ * @return the total amount of time unit nanoseconds of this period
+ */
+ public long getTimeNanos() {
+ return nanos;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this period with the specified amount of years.
+ *
+ * This method will only affect the years field.
+ * All other units are unaffected.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param years the years to represent
+ * @return a {@code Period} based on this period with the requested years, not null
+ */
+ public Period withYears(int years) {
+ if (years == this.years) {
+ return this;
+ }
+ return create(years, months, days, nanos);
+ }
+
+ /**
+ * Returns a copy of this period with the specified amount of months.
+ *
+ * This method will only affect the months field.
+ * All other units are unaffected.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param months the months to represent
+ * @return a {@code Period} based on this period with the requested months, not null
+ */
+ public Period withMonths(int months) {
+ if (months == this.months) {
+ return this;
+ }
+ return create(years, months, days, nanos);
+ }
+
+ /**
+ * Returns a copy of this period with the specified amount of days.
+ *
+ * This method will only affect the days field.
+ * All other units are unaffected.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param days the days to represent
+ * @return a {@code Period} based on this period with the requested days, not null
+ */
+ public Period withDays(int days) {
+ if (days == this.days) {
+ return this;
+ }
+ return create(years, months, days, nanos);
+ }
+
+ /**
+ * Returns a copy of this period with the specified total amount of time units
+ * expressed in nanoseconds.
+ *
+ * Within a period, the time fields are always normalized.
+ * This method will affect all the time units - hours, minutes, seconds and nanos.
+ * The date units are unaffected.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param nanos the nanoseconds to represent
+ * @return a {@code Period} based on this period with the requested nanoseconds, not null
+ */
+ public Period withTimeNanos(long nanos) {
+ if (nanos == this.nanos) {
+ return this;
+ }
+ return create(years, months, days, nanos);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this period with the specified period added.
+ *
+ * This operates separately on the years, months, days and the normalized time.
+ * There is no further normalization beyond the normalized time.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param other the period to add, not null
+ * @return a {@code Period} based on this period with the requested period added, not null
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ public Period plus(Period other) {
+ return create(
+ Math.addExact(years, other.years),
+ Math.addExact(months, other.months),
+ Math.addExact(days, other.days),
+ Math.addExact(nanos, other.nanos));
+ }
+
+ /**
+ * Returns a copy of this period with the specified period added.
+ *
+ * The specified unit must be one of the supported units from {@link ChronoUnit},
+ * {@code YEARS}, {@code MONTHS} or {@code DAYS} or be a time unit with an
+ * {@linkplain TemporalUnit#isDurationEstimated() exact duration}.
+ * Other units throw an exception.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param amount the amount to add, positive or negative
+ * @param unit the unit that the amount is expressed in, not null
+ * @return a {@code Period} based on this period with the requested amount added, not null
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ public Period plus(long amount, TemporalUnit unit) {
+ Objects.requireNonNull(unit, "unit");
+ if (unit instanceof ChronoUnit) {
+ if (unit == YEARS || unit == MONTHS || unit == DAYS || unit.isDurationEstimated() == false) {
+ if (amount == 0) {
+ return this;
+ }
+ switch((ChronoUnit) unit) {
+ case NANOS: return plusNanos(amount);
+ case MICROS: return plusNanos(Math.multiplyExact(amount, 1000L));
+ case MILLIS: return plusNanos(Math.multiplyExact(amount, 1000_000L));
+ case SECONDS: return plusSeconds(amount);
+ case MINUTES: return plusMinutes(amount);
+ case HOURS: return plusHours(amount);
+ case HALF_DAYS: return plusNanos(Math.multiplyExact(amount, 12 * NANOS_PER_HOUR));
+ case DAYS: return plusDays(amount);
+ case MONTHS: return plusMonths(amount);
+ case YEARS: return plusYears(amount);
+ default: throw new DateTimeException("Unsupported unit: " + unit.getName());
+ }
+ }
+ }
+ if (unit.isDurationEstimated()) {
+ throw new DateTimeException("Unsupported unit: " + unit.getName());
+ }
+ return plusNanos(Duration.of(amount, unit).toNanos());
+ }
+
+ public Period plusYears(long amount) {
+ return create(Math.toIntExact(Math.addExact(years, amount)), months, days, nanos);
+ }
+
+ public Period plusMonths(long amount) {
+ return create(years, Math.toIntExact(Math.addExact(months, amount)), days, nanos);
+ }
+
+ public Period plusDays(long amount) {
+ return create(years, months, Math.toIntExact(Math.addExact(days, amount)), nanos);
+ }
+
+ public Period plusHours(long amount) {
+ return plusNanos(Math.multiplyExact(amount, NANOS_PER_HOUR));
+ }
+
+ public Period plusMinutes(long amount) {
+ return plusNanos(Math.multiplyExact(amount, NANOS_PER_MINUTE));
+ }
+
+ public Period plusSeconds(long amount) {
+ return plusNanos(Math.multiplyExact(amount, NANOS_PER_SECOND));
+ }
+
+ public Period plusNanos(long amount) {
+ return create(years, months, days, Math.addExact(nanos, amount));
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this period with the specified period subtracted.
+ *
+ * This operates separately on the years, months, days and the normalized time.
+ * There is no further normalization beyond the normalized time.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param other the period to subtract, not null
+ * @return a {@code Period} based on this period with the requested period subtracted, not null
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ public Period minus(Period other) {
+ return create(
+ Math.subtractExact(years, other.years),
+ Math.subtractExact(months, other.months),
+ Math.subtractExact(days, other.days),
+ Math.subtractExact(nanos, other.nanos));
+ }
+
+ /**
+ * Returns a copy of this period with the specified period subtracted.
+ *
+ * The specified unit must be one of the supported units from {@link ChronoUnit},
+ * {@code YEARS}, {@code MONTHS} or {@code DAYS} or be a time unit with an
+ * {@linkplain TemporalUnit#isDurationEstimated() exact duration}.
+ * Other units throw an exception.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param amount the amount to subtract, positive or negative
+ * @param unit the unit that the amount is expressed in, not null
+ * @return a {@code Period} based on this period with the requested amount subtracted, not null
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ public Period minus(long amount, TemporalUnit unit) {
+ return (amount == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amount, unit));
+ }
+
+ public Period minusYears(long amount) {
+ return (amount == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-amount));
+ }
+
+ public Period minusMonths(long amount) {
+ return (amount == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-amount));
+ }
+
+ public Period minusDays(long amount) {
+ return (amount == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-amount));
+ }
+
+ public Period minusHours(long amount) {
+ return (amount == Long.MIN_VALUE ? plusHours(Long.MAX_VALUE).plusHours(1) : plusHours(-amount));
+ }
+
+ public Period minusMinutes(long amount) {
+ return (amount == Long.MIN_VALUE ? plusMinutes(Long.MAX_VALUE).plusMinutes(1) : plusMinutes(-amount));
+ }
+
+ public Period minusSeconds(long amount) {
+ return (amount == Long.MIN_VALUE ? plusSeconds(Long.MAX_VALUE).plusSeconds(1) : plusSeconds(-amount));
+ }
+
+ public Period minusNanos(long amount) {
+ return (amount == Long.MIN_VALUE ? plusNanos(Long.MAX_VALUE).plusNanos(1) : plusNanos(-amount));
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a new instance with each element in this period multiplied
+ * by the specified scalar.
+ *
+ * This simply multiplies each field, years, months, days and normalized time,
+ * by the scalar. No normalization is performed.
+ *
+ * @param scalar the scalar to multiply by, not null
+ * @return a {@code Period} based on this period with the amounts multiplied by the scalar, not null
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ public Period multipliedBy(int scalar) {
+ if (this == ZERO || scalar == 1) {
+ return this;
+ }
+ return create(
+ Math.multiplyExact(years, scalar),
+ Math.multiplyExact(months, scalar),
+ Math.multiplyExact(days, scalar),
+ Math.multiplyExact(nanos, scalar));
+ }
+
+ /**
+ * Returns a new instance with each amount in this period negated.
+ *
+ * @return a {@code Period} based on this period with the amounts negated, not null
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ public Period negated() {
+ return multipliedBy(-1);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this period with the days and hours normalized using a 24 hour day.
+ *
+ * This normalizes the days and hours units, leaving years and months unchanged.
+ * The hours unit is adjusted to have an absolute value less than 23,
+ * with the days unit being adjusted to compensate.
+ * For example, a period of {@code P1DT27H} will be normalized to {@code P2DT3H}.
+ *
+ * The sign of the days and hours units will be the same after normalization.
+ * For example, a period of {@code P1DT-51H} will be normalized to {@code P-1DT-3H}.
+ * Since all time units are always normalized, if the hours units changes sign then
+ * other time units will also be affected.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @return a {@code Period} based on this period with excess hours normalized to days, not null
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ public Period normalizedHoursToDays() {
+ // logic uses if statements to normalize signs to avoid unnecessary overflows
+ long totalDays = (nanos / NANOS_PER_DAY) + days; // no overflow
+ long splitNanos = nanos % NANOS_PER_DAY;
+ if (totalDays > 0 && splitNanos < 0) {
+ splitNanos += NANOS_PER_DAY;
+ totalDays--;
+ } else if (totalDays < 0 && splitNanos > 0) {
+ splitNanos -= NANOS_PER_DAY;
+ totalDays++;
+ }
+ if (totalDays == days && splitNanos == nanos) {
+ return this;
+ }
+ return create(years, months, Math.toIntExact(totalDays), splitNanos);
+ }
+
+ /**
+ * Returns a copy of this period with any days converted to hours using a 24 hour day.
+ *
+ * The days unit is reduced to zero, with the hours unit increased by 24 times the
+ * days unit to compensate. Other units are unaffected.
+ * For example, a period of {@code P2DT4H} will be normalized to {@code PT52H}.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @return a {@code Period} based on this period with days normalized to hours, not null
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ public Period normalizedDaysToHours() {
+ if (days == 0) {
+ return this;
+ }
+ return create(years, months, 0, Math.addExact(Math.multiplyExact(days, NANOS_PER_DAY), nanos));
+ }
+
+ /**
+ * Returns a copy of this period with the years and months normalized using a 12 month year.
+ *
+ * This normalizes the years and months units, leaving other units unchanged.
+ * The months unit is adjusted to have an absolute value less than 11,
+ * with the years unit being adjusted to compensate.
+ * For example, a period of {@code P1Y15M} will be normalized to {@code P2Y3M}.
+ *
+ * The sign of the years and months units will be the same after normalization.
+ * For example, a period of {@code P1Y-25M} will be normalized to {@code P-1Y-1M}.
+ *
+ * This normalization uses a 12 month year it is not valid for all calendar systems.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @return a {@code Period} based on this period with years and months normalized, not null
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ public Period normalizedMonthsISO() {
+ long totalMonths = years * 12L + months; // no overflow
+ long splitYears = totalMonths / 12;
+ int splitMonths = (int) (totalMonths % 12); // no overflow
+ if (splitYears == years && splitMonths == months) {
+ return this;
+ }
+ return create(Math.toIntExact(splitYears), splitMonths, days, nanos);
+ }
+
+ //-------------------------------------------------------------------------
+ /**
+ * Converts this period to one that only has date units.
+ *
+ * The resulting period will have the same years, months and days as this period
+ * but the time units will all be zero. No normalization occurs in the calculation.
+ * For example, a period of {@code P1Y3MT12H} will be converted to {@code P1Y3M}.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @return a {@code Period} based on this period with the time units set to zero, not null
+ */
+ public Period toDateOnly() {
+ if (nanos == 0) {
+ return this;
+ }
+ return create(years, months, days, 0);
+ }
+
+ //-------------------------------------------------------------------------
+ /**
+ * Adds this period to the specified temporal object.
+ *
+ * This returns a temporal object of the same observable type as the input
+ * with this period added.
+ *
+ * In most cases, it is clearer to reverse the calling pattern by using
+ * {@link Temporal#plus(TemporalAdder)}.
+ *
+ * The calculation will add the years, then months, then days, then nanos.
+ * Only non-zero amounts will be added.
+ * If the date-time has a calendar system with a fixed number of months in a
+ * year, then the years and months will be combined before being added.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param temporal the temporal object to adjust, not null
+ * @return an object of the same type with the adjustment made, not null
+ * @throws DateTimeException if unable to add
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public Temporal addTo(Temporal temporal) {
+ Objects.requireNonNull(temporal, "temporal");
+ if ((years | months) != 0) {
+ ValueRange startRange = Chrono.from(temporal).range(MONTH_OF_YEAR);
+ if (startRange.isFixed() && startRange.isIntValue()) {
+ long monthCount = startRange.getMaximum() - startRange.getMinimum() + 1;
+ temporal = temporal.plus(years * monthCount + months, MONTHS);
+ } else {
+ if (years != 0) {
+ temporal = temporal.plus(years, YEARS);
+ }
+ if (months != 0) {
+ temporal = temporal.plus(months, MONTHS);
+ }
+ }
+ }
+ if (days != 0) {
+ temporal = temporal.plus(days, DAYS);
+ }
+ if (nanos != 0) {
+ temporal = temporal.plus(nanos, NANOS);
+ }
+ return temporal;
+ }
+
+ /**
+ * Subtracts this period from the specified temporal object.
+ *
+ * This returns a temporal object of the same observable type as the input
+ * with this period subtracted.
+ *
+ * In most cases, it is clearer to reverse the calling pattern by using
+ * {@link Temporal#minus(TemporalSubtractor)}.
+ *
+ * The calculation will subtract the years, then months, then days, then nanos.
+ * Only non-zero amounts will be subtracted.
+ * If the date-time has a calendar system with a fixed number of months in a
+ * year, then the years and months will be combined before being subtracted.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param temporal the temporal object to adjust, not null
+ * @return an object of the same type with the adjustment made, not null
+ * @throws DateTimeException if unable to subtract
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public Temporal subtractFrom(Temporal temporal) {
+ Objects.requireNonNull(temporal, "temporal");
+ if ((years | months) != 0) {
+ ValueRange startRange = Chrono.from(temporal).range(MONTH_OF_YEAR);
+ if (startRange.isFixed() && startRange.isIntValue()) {
+ long monthCount = startRange.getMaximum() - startRange.getMinimum() + 1;
+ temporal = temporal.minus(years * monthCount + months, MONTHS);
+ } else {
+ if (years != 0) {
+ temporal = temporal.minus(years, YEARS);
+ }
+ if (months != 0) {
+ temporal = temporal.minus(months, MONTHS);
+ }
+ }
+ }
+ if (days != 0) {
+ temporal = temporal.minus(days, DAYS);
+ }
+ if (nanos != 0) {
+ temporal = temporal.minus(nanos, NANOS);
+ }
+ return temporal;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Converts this period to one that only has time units.
+ *
+ * The resulting period will have the same time units as this period
+ * but the date units will all be zero. No normalization occurs in the calculation.
+ * For example, a period of {@code P1Y3MT12H} will be converted to {@code PT12H}.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @return a {@code Period} based on this period with the date units set to zero, not null
+ */
+ public Period toTimeOnly() {
+ if ((years | months | days) == 0) {
+ return this;
+ }
+ return create(0, 0, 0, nanos);
+ }
+
+ //-------------------------------------------------------------------------
+ /**
+ * Calculates the duration of this period.
+ *
+ * The calculation uses the hours, minutes, seconds and nanoseconds fields.
+ * If years, months or days are present an exception is thrown.
+ * See {@link #toTimeOnly()} for a way to remove the date units and
+ * {@link #normalizedDaysToHours()} for a way to convert days to hours.
+ *
+ * @return a {@code Duration} equivalent to this period, not null
+ * @throws DateTimeException if the period cannot be converted as it contains years, months or days
+ */
+ public Duration toDuration() {
+ if ((years | months | days) != 0) {
+ throw new DateTimeException("Unable to convert period to duration as years/months/days are present: " + this);
+ }
+ return Duration.ofNanos(nanos);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks if this period is equal to another period.
+ *
+ * The comparison is based on the amounts held in the period.
+ * To be equal, the years, months, days and normalized time fields must be equal.
+ *
+ * @param obj the object to check, null returns false
+ * @return true if this is equal to the other period
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof Period) {
+ Period other = (Period) obj;
+ return years == other.years && months == other.months &&
+ days == other.days && nanos == other.nanos;
+ }
+ return false;
+ }
+
+ /**
+ * A hash code for this period.
+ *
+ * @return a suitable hash code
+ */
+ @Override
+ public int hashCode() {
+ // ordered such that overflow from one field doesn't immediately affect the next field
+ return ((years << 27) | (years >>> 5)) ^
+ ((days << 21) | (days >>> 11)) ^
+ ((months << 17) | (months >>> 15)) ^
+ ((int) (nanos ^ (nanos >>> 32)));
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Outputs this period as a {@code String}, such as {@code P6Y3M1DT12H}.
+ *
+ * The output will be in the ISO-8601 period format.
+ *
+ * @return a string representation of this period, not null
+ */
+ @Override
+ public String toString() {
+ if (this == ZERO) {
+ return "PT0S";
+ } else {
+ StringBuilder buf = new StringBuilder();
+ buf.append('P');
+ if (years != 0) {
+ buf.append(years).append('Y');
+ }
+ if (months != 0) {
+ buf.append(months).append('M');
+ }
+ if (days != 0) {
+ buf.append(days).append('D');
+ }
+ if (nanos != 0) {
+ buf.append('T');
+ if (getHours() != 0) {
+ buf.append(getHours()).append('H');
+ }
+ if (getMinutes() != 0) {
+ buf.append(getMinutes()).append('M');
+ }
+ int secondPart = getSeconds();
+ int nanoPart = getNanos();
+ int secsNanosOr = secondPart | nanoPart;
+ if (secsNanosOr != 0) { // if either non-zero
+ if ((secsNanosOr & Integer.MIN_VALUE) != 0) { // if either less than zero
+ buf.append('-');
+ secondPart = Math.abs(secondPart);
+ nanoPart = Math.abs(nanoPart);
+ }
+ buf.append(secondPart);
+ if (nanoPart != 0) {
+ int dotPos = buf.length();
+ nanoPart += 1000_000_000;
+ while (nanoPart % 10 == 0) {
+ nanoPart /= 10;
+ }
+ buf.append(nanoPart);
+ buf.setCharAt(dotPos, '.');
+ }
+ buf.append('S');
+ }
+ }
+ return buf.toString();
+ }
+ }
+
+}
diff --git a/src/share/classes/java/time/PeriodParser.java b/src/share/classes/java/time/PeriodParser.java
new file mode 100644
index 0000000000000000000000000000000000000000..6a424ae778261a799ebfc0e913b29fe94f24e586
--- /dev/null
+++ b/src/share/classes/java/time/PeriodParser.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import java.time.format.DateTimeParseException;
+
+/**
+ * A period parser that creates an instance of {@code Period} from a string.
+ * This parses the ISO-8601 period format {@code PnYnMnDTnHnMn.nS}.
+ *
+ * This class is mutable and intended for use by a single thread.
+ *
+ * @since 1.8
+ */
+final class PeriodParser {
+
+ /**
+ * Used to validate the correct sequence of tokens.
+ */
+ private static final String TOKEN_SEQUENCE = "PYMDTHMS";
+ /**
+ * The standard string representing a zero period.
+ */
+ private static final String ZERO = "PT0S";
+
+ /**
+ * The number of years.
+ */
+ private int years;
+ /**
+ * The number of months.
+ */
+ private int months;
+ /**
+ * The number of days.
+ */
+ private int days;
+ /**
+ * The number of hours.
+ */
+ private int hours;
+ /**
+ * The number of minutes.
+ */
+ private int minutes;
+ /**
+ * The number of seconds.
+ */
+ private int seconds;
+ /**
+ * The number of nanoseconds.
+ */
+ private long nanos;
+ /**
+ * Whether the seconds were negative.
+ */
+ private boolean negativeSecs;
+ /**
+ * Parser position index.
+ */
+ private int index;
+ /**
+ * Original text.
+ */
+ private CharSequence text;
+
+ /**
+ * Constructor.
+ *
+ * @param text the text to parse, not null
+ */
+ PeriodParser(CharSequence text) {
+ this.text = text;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Performs the parse.
+ *
+ * This parses the text set in the constructor in the format PnYnMnDTnHnMn.nS.
+ *
+ * @return the created Period, not null
+ * @throws DateTimeParseException if the text cannot be parsed to a Period
+ */
+ Period parse() {
+ // force to upper case and coerce the comma to dot
+
+ String s = text.toString().toUpperCase().replace(',', '.');
+ // check for zero and skip parse
+ if (ZERO.equals(s)) {
+ return Period.ZERO;
+ }
+ if (s.length() < 3 || s.charAt(0) != 'P') {
+ throw new DateTimeParseException("Period could not be parsed: " + text, text, 0);
+ }
+ validateCharactersAndOrdering(s, text);
+
+ // strip off the leading P
+ String[] datetime = s.substring(1).split("T");
+ switch (datetime.length) {
+ case 2:
+ parseDate(datetime[0], 1);
+ parseTime(datetime[1], datetime[0].length() + 2);
+ break;
+ case 1:
+ parseDate(datetime[0], 1);
+ break;
+ }
+ return toPeriod();
+ }
+
+ private void parseDate(String s, int baseIndex) {
+ index = 0;
+ while (index < s.length()) {
+ String value = parseNumber(s);
+ if (index < s.length()) {
+ char c = s.charAt(index);
+ switch(c) {
+ case 'Y': years = parseInt(value, baseIndex) ; break;
+ case 'M': months = parseInt(value, baseIndex) ; break;
+ case 'D': days = parseInt(value, baseIndex) ; break;
+ default:
+ throw new DateTimeParseException("Period could not be parsed, unrecognized letter '" +
+ c + ": " + text, text, baseIndex + index);
+ }
+ index++;
+ }
+ }
+ }
+
+ private void parseTime(String s, int baseIndex) {
+ index = 0;
+ s = prepareTime(s, baseIndex);
+ while (index < s.length()) {
+ String value = parseNumber(s);
+ if (index < s.length()) {
+ char c = s.charAt(index);
+ switch(c) {
+ case 'H': hours = parseInt(value, baseIndex) ; break;
+ case 'M': minutes = parseInt(value, baseIndex) ; break;
+ case 'S': seconds = parseInt(value, baseIndex) ; break;
+ case 'N': nanos = parseNanos(value, baseIndex); break;
+ default:
+ throw new DateTimeParseException("Period could not be parsed, unrecognized letter '" +
+ c + "': " + text, text, baseIndex + index);
+ }
+ index++;
+ }
+ }
+ }
+
+ private long parseNanos(String s, int baseIndex) {
+ if (s.length() > 9) {
+ throw new DateTimeParseException("Period could not be parsed, nanosecond range exceeded: " +
+ text, text, baseIndex + index - s.length());
+ }
+ // pad to the right to create 10**9, then trim
+ return Long.parseLong((s + "000000000").substring(0, 9));
+ }
+
+ private String prepareTime(String s, int baseIndex) {
+ if (s.contains(".")) {
+ int i = s.indexOf(".") + 1;
+
+ // verify that the first character after the dot is a digit
+ if (Character.isDigit(s.charAt(i))) {
+ i++;
+ } else {
+ throw new DateTimeParseException("Period could not be parsed, invalid decimal number: " +
+ text, text, baseIndex + index);
+ }
+
+ // verify that only digits follow the decimal point followed by an S
+ while (i < s.length()) {
+ // || !Character.isDigit(s.charAt(i))
+ char c = s.charAt(i);
+ if (Character.isDigit(c) || c == 'S') {
+ i++;
+ } else {
+ throw new DateTimeParseException("Period could not be parsed, invalid decimal number: " +
+ text, text, baseIndex + index);
+ }
+ }
+ s = s.replace('S', 'N').replace('.', 'S');
+ if (s.contains("-0S")) {
+ negativeSecs = true;
+ s = s.replace("-0S", "0S");
+ }
+ }
+ return s;
+ }
+
+ private int parseInt(String s, int baseIndex) {
+ try {
+ int value = Integer.parseInt(s);
+ if (s.charAt(0) == '-' && value == 0) {
+ throw new DateTimeParseException("Period could not be parsed, invalid number '" +
+ s + "': " + text, text, baseIndex + index - s.length());
+ }
+ return value;
+ } catch (NumberFormatException ex) {
+ throw new DateTimeParseException("Period could not be parsed, invalid number '" +
+ s + "': " + text, text, baseIndex + index - s.length());
+ }
+ }
+
+ private String parseNumber(String s) {
+ int start = index;
+ while (index < s.length()) {
+ char c = s.charAt(index);
+ if ((c < '0' || c > '9') && c != '-') {
+ break;
+ }
+ index++;
+ }
+ return s.substring(start, index);
+ }
+
+ private void validateCharactersAndOrdering(String s, CharSequence text) {
+ char[] chars = s.toCharArray();
+ int tokenPos = 0;
+ boolean lastLetter = false;
+ for (int i = 0; i < chars.length; i++) {
+ if (tokenPos >= TOKEN_SEQUENCE.length()) {
+ throw new DateTimeParseException("Period could not be parsed, characters after last 'S': " + text, text, i);
+ }
+ char c = chars[i];
+ if ((c < '0' || c > '9') && c != '-' && c != '.') {
+ tokenPos = TOKEN_SEQUENCE.indexOf(c, tokenPos);
+ if (tokenPos < 0) {
+ throw new DateTimeParseException("Period could not be parsed, invalid character '" + c + "': " + text, text, i);
+ }
+ tokenPos++;
+ lastLetter = true;
+ } else {
+ lastLetter = false;
+ }
+ }
+ if (lastLetter == false) {
+ throw new DateTimeParseException("Period could not be parsed, invalid last character: " + text, text, s.length() - 1);
+ }
+ }
+
+ private Period toPeriod() {
+ return Period.of(years, months, days, hours, minutes, seconds, negativeSecs || seconds < 0 ? -nanos : nanos);
+ }
+
+}
diff --git a/src/share/classes/java/time/Ser.java b/src/share/classes/java/time/Ser.java
new file mode 100644
index 0000000000000000000000000000000000000000..d665ccf7580b5a52bf18cde95d4d7da1974844d7
--- /dev/null
+++ b/src/share/classes/java/time/Ser.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.InvalidClassException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.StreamCorruptedException;
+
+/**
+ * The shared serialization delegate for this package.
+ *
+ *
+ * In order to serialise the object it writes its byte and then calls back to the appropriate class where
+ * the serialisation is performed. In order to deserialise the object it read in the type byte, switching
+ * in order to select which class to call back into.
+ *
+ * The serialisation format is determined on a per class basis. In the case of field based classes each
+ * of the fields is written out with an appropriate size format in descending order of the field's size. For
+ * example in the case of {@link LocalDate} year is written before month. Composite classes, such as
+ * {@link LocalDateTime} are serialised as one object.
+ *
+ * This class is mutable and should be created once per serialization.
+ *
+ * @serial include
+ * @since 1.8
+ */
+final class Ser implements Externalizable {
+
+ /**
+ * Serialization version.
+ */
+ private static final long serialVersionUID = -7683839454370182990L;
+
+ static final byte DURATION_TYPE = 1;
+ static final byte INSTANT_TYPE = 2;
+ static final byte LOCAL_DATE_TYPE = 3;
+ static final byte LOCAL_TIME_TYPE = 4;
+ static final byte LOCAL_DATE_TIME_TYPE = 5;
+ static final byte ZONE_DATE_TIME_TYPE = 6;
+ static final byte ZONE_REGION_TYPE = 7;
+ static final byte ZONE_OFFSET_TYPE = 8;
+
+ /** The type being serialized. */
+ private byte type;
+ /** The object being serialized. */
+ private Object object;
+
+ /**
+ * Constructor for deserialization.
+ */
+ public Ser() {
+ }
+
+ /**
+ * Creates an instance for serialization.
+ *
+ * @param type the type
+ * @param object the object
+ */
+ Ser(byte type, Object object) {
+ this.type = type;
+ this.object = object;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Implements the {@code Externalizable} interface to write the object.
+ *
+ * @param out the data stream to write to, not null
+ */
+ public void writeExternal(ObjectOutput out) throws IOException {
+ writeInternal(type, object, out);
+ }
+
+ static void writeInternal(byte type, Object object, DataOutput out) throws IOException {
+ out.writeByte(type);
+ switch (type) {
+ case DURATION_TYPE:
+ ((Duration) object).writeExternal(out);
+ break;
+ case INSTANT_TYPE:
+ ((Instant) object).writeExternal(out);
+ break;
+ case LOCAL_DATE_TYPE:
+ ((LocalDate) object).writeExternal(out);
+ break;
+ case LOCAL_DATE_TIME_TYPE:
+ ((LocalDateTime) object).writeExternal(out);
+ break;
+ case LOCAL_TIME_TYPE:
+ ((LocalTime) object).writeExternal(out);
+ break;
+ case ZONE_REGION_TYPE:
+ ((ZoneRegion) object).writeExternal(out);
+ break;
+ case ZONE_OFFSET_TYPE:
+ ((ZoneOffset) object).writeExternal(out);
+ break;
+ case ZONE_DATE_TIME_TYPE:
+ ((ZonedDateTime) object).writeExternal(out);
+ break;
+ default:
+ throw new InvalidClassException("Unknown serialized type");
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Implements the {@code Externalizable} interface to read the object.
+ *
+ * @param in the data to read, not null
+ */
+ public void readExternal(ObjectInput in) throws IOException {
+ type = in.readByte();
+ object = readInternal(type, in);
+ }
+
+ static Object read(DataInput in) throws IOException {
+ byte type = in.readByte();
+ return readInternal(type, in);
+ }
+
+ private static Object readInternal(byte type, DataInput in) throws IOException {
+ switch (type) {
+ case DURATION_TYPE: return Duration.readExternal(in);
+ case INSTANT_TYPE: return Instant.readExternal(in);
+ case LOCAL_DATE_TYPE: return LocalDate.readExternal(in);
+ case LOCAL_DATE_TIME_TYPE: return LocalDateTime.readExternal(in);
+ case LOCAL_TIME_TYPE: return LocalTime.readExternal(in);
+ case ZONE_DATE_TIME_TYPE: return ZonedDateTime.readExternal(in);
+ case ZONE_OFFSET_TYPE: return ZoneOffset.readExternal(in);
+ case ZONE_REGION_TYPE: return ZoneRegion.readExternal(in);
+ default:
+ throw new StreamCorruptedException("Unknown serialized type");
+ }
+ }
+
+ /**
+ * Returns the object that will replace this one.
+ *
+ * @return the read object, should never be null
+ */
+ private Object readResolve() {
+ return object;
+ }
+
+}
diff --git a/src/share/classes/java/time/ZoneId.java b/src/share/classes/java/time/ZoneId.java
new file mode 100644
index 0000000000000000000000000000000000000000..cc7d83c1465d24886cacf4eee39228b7f3206fab
--- /dev/null
+++ b/src/share/classes/java/time/ZoneId.java
@@ -0,0 +1,518 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.Serializable;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.TextStyle;
+import java.time.temporal.Queries;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQuery;
+import java.time.zone.ZoneRules;
+import java.time.zone.ZoneRulesProvider;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Objects;
+import java.util.TimeZone;
+
+/**
+ * A time-zone ID, such as {@code Europe/Paris}.
+ *
+ * A {@code ZoneId} is used to identify the rules used to convert between
+ * an {@link Instant} and a {@link LocalDateTime}.
+ * There are two distinct types of ID:
+ *
+ * Most fixed offsets are represented by {@link ZoneOffset}.
+ *
+ * The actual rules, describing when and how the offset changes, are defined by {@link ZoneRules}.
+ * This class is simply an ID used to obtain the underlying rules.
+ * This approach is taken because rules are defined by governments and change
+ * frequently, whereas the ID is stable.
+ *
+ * The distinction has other effects. Serializing the {@code ZoneId} will only send
+ * the ID, whereas serializing the rules sends the entire data set.
+ * Similarly, a comparison of two IDs only examines the ID, whereas
+ * a comparison of two rules examines the entire data set.
+ *
+ * The code supports loading a {@code ZoneId} on a JVM which does not have available rules
+ * for that ID. This allows the date-time object, such as {@link ZonedDateTime},
+ * to still be queried.
+ *
+ *
+ * An ID is parsed as an offset ID if it starts with 'UTC', 'GMT', '+' or '-', or
+ * is a single letter.
+ * For example, 'Z', '+02:00', '-05:00', 'UTC+05' and 'GMT-6' are all valid offset IDs.
+ * Note that some IDs, such as 'D' or '+ABC' meet the criteria, but are invalid.
+ *
+ * All other IDs are considered to be region IDs.
+ *
+ * Region IDs are defined by configuration, which can be thought of as a {@code Map}
+ * from region ID to {@code ZoneRules}, see {@link ZoneRulesProvider}.
+ *
+ * Time-zones are defined by governments and change frequently. There are a number of
+ * organizations, known here as groups, that monitor time-zone changes and collate them.
+ * The default group is the IANA Time Zone Database (TZDB).
+ * Other organizations include IATA (the airline industry body) and Microsoft.
+ *
+ * Each group defines its own format for region ID.
+ * The TZDB group defines IDs such as 'Europe/London' or 'America/New_York'.
+ * TZDB IDs take precedence over other groups.
+ *
+ * It is strongly recommended that the group name is included in all Ids supplied by
+ * groups other than TZDB to avoid conflicts. For example, IATA airline time-zone
+ * region IDs are typically the same as the three letter airport code.
+ * However, the airport of Utrecht has the code 'UTC', which is obviously a conflict.
+ * The recommended format for region IDs from groups other than TZDB is 'group~region'.
+ * Thus if IATA data were defined, Utrecht airport would be 'IATA~UTC'.
+ *
+ *
+ * This maps as follows:
+ *
+ * The map is unmodifiable.
+ */
+ public static final Map
+ * This maps as follows:
+ *
+ * The map is unmodifiable.
+ */
+ public static final Map
+ * This queries {@link TimeZone#getDefault()} to find the default time-zone
+ * and converts it to a {@code ZoneId}. If the system default time-zone is changed,
+ * then the result of this method will also change.
+ *
+ * @return the zone ID, not null
+ * @throws DateTimeException if the converted zone ID has an invalid format
+ * @throws java.time.zone.ZoneRulesException if the converted zone region ID cannot be found
+ */
+ public static ZoneId systemDefault() {
+ return ZoneId.of(TimeZone.getDefault().getID(), OLD_IDS_POST_2005);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code ZoneId} using its ID using a map
+ * of aliases to supplement the standard zone IDs.
+ *
+ * Many users of time-zones use short abbreviations, such as PST for
+ * 'Pacific Standard Time' and PDT for 'Pacific Daylight Time'.
+ * These abbreviations are not unique, and so cannot be used as IDs.
+ * This method allows a map of string to time-zone to be setup and reused
+ * within an application.
+ *
+ * @param zoneId the time-zone ID, not null
+ * @param aliasMap a map of alias zone IDs (typically abbreviations) to real zone IDs, not null
+ * @return the zone ID, not null
+ * @throws DateTimeException if the zone ID has an invalid format
+ * @throws java.time.zone.ZoneRulesException if the zone region ID cannot be found
+ */
+ public static ZoneId of(String zoneId, Map
+ * This method parses the ID, applies any appropriate normalization, and validates it
+ * against the known set of IDs for which rules are available.
+ *
+ * An ID is parsed as though it is an offset ID if it starts with 'UTC', 'GMT', '+'
+ * or '-', or if it has less then two letters.
+ * The offset of {@link ZoneOffset#UTC zero} may be represented in multiple ways,
+ * including 'Z', 'UTC', 'GMT', 'UTC0' 'GMT0', '+00:00', '-00:00' and 'UTC+00:00'.
+ *
+ * Eight forms of ID are recognized, where '{offset}' means to parse using {@link ZoneOffset#of(String)}:
+ *
+ * Region IDs must match the regular expression
+ * The detailed format of the region ID depends on the group supplying the data.
+ * The default set of data is supplied by the IANA Time Zone Database (TZDB)
+ * This has region IDs of the form '{area}/{city}', such as 'Europe/Paris' or 'America/New_York'.
+ * This is compatible with most IDs from {@link java.util.TimeZone}.
+ *
+ * @param zoneId the time-zone ID, not null
+ * @return the zone ID, not null
+ * @throws DateTimeException if the zone ID has an invalid format
+ * @throws java.time.zone.ZoneRulesException if the zone region ID cannot be found
+ */
+ public static ZoneId of(String zoneId) {
+ Objects.requireNonNull(zoneId, "zoneId");
+ if (zoneId.length() <= 1 || zoneId.startsWith("+") || zoneId.startsWith("-")) {
+ return ZoneOffset.of(zoneId);
+ } else if (zoneId.startsWith("UTC") || zoneId.startsWith("GMT")) {
+ if (zoneId.length() == 3 || (zoneId.length() == 4 && zoneId.charAt(3) == '0')) {
+ return ZoneOffset.UTC;
+ }
+ return ZoneOffset.of(zoneId.substring(3));
+ }
+ return ZoneRegion.ofId(zoneId, true);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code ZoneId} from a temporal object.
+ *
+ * A {@code TemporalAccessor} represents some form of date and time information.
+ * This factory converts the arbitrary temporal object to an instance of {@code ZoneId}.
+ *
+ * The conversion will try to obtain the zone in a way that favours region-based
+ * zones over offset-based zones using {@link Queries#zone()}.
+ *
+ * This method matches the signature of the functional interface {@link TemporalQuery}
+ * allowing it to be used in queries via method reference, {@code ZoneId::from}.
+ *
+ * @param temporal the temporal object to convert, not null
+ * @return the zone ID, not null
+ * @throws DateTimeException if unable to convert to a {@code ZoneId}
+ */
+ public static ZoneId from(TemporalAccessor temporal) {
+ ZoneId obj = temporal.query(Queries.zone());
+ if (obj == null) {
+ throw new DateTimeException("Unable to obtain ZoneId from TemporalAccessor: " + temporal.getClass());
+ }
+ return obj;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Constructor only accessible within the package.
+ */
+ ZoneId() {
+ if (getClass() != ZoneOffset.class && getClass() != ZoneRegion.class) {
+ throw new AssertionError("Invalid subclass");
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the unique time-zone ID.
+ *
+ * This ID uniquely defines this object.
+ * The format of an offset based ID is defined by {@link ZoneOffset#getId()}.
+ *
+ * @return the time-zone unique ID, not null
+ */
+ public abstract String getId();
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the time-zone rules for this ID allowing calculations to be performed.
+ *
+ * The rules provide the functionality associated with a time-zone,
+ * such as finding the offset for a given instant or local date-time.
+ *
+ * A time-zone can be invalid if it is deserialized in a JVM which does not
+ * have the same rules loaded as the JVM that stored it. In this case, calling
+ * this method will throw an exception.
+ *
+ * The rules are supplied by {@link ZoneRulesProvider}. An advanced provider may
+ * support dynamic updates to the rules without restarting the JVM.
+ * If so, then the result of this method may change over time.
+ * Each individual call will be still remain thread-safe.
+ *
+ * {@link ZoneOffset} will always return a set of rules where the offset never changes.
+ *
+ * @return the rules, not null
+ * @throws DateTimeException if no rules are available for this ID
+ */
+ public abstract ZoneRules getRules();
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the textual representation of the zone, such as 'British Time' or
+ * '+02:00'.
+ *
+ * This returns a textual description for the time-zone ID.
+ *
+ * If no textual mapping is found then the {@link #getId() full ID} is returned.
+ *
+ * @param style the length of the text required, not null
+ * @param locale the locale to use, not null
+ * @return the text value of the zone, not null
+ */
+ public String getText(TextStyle style, Locale locale) {
+ return new DateTimeFormatterBuilder().appendZoneText(style).toFormatter(locale).print(new TemporalAccessor() {
+ @Override
+ public boolean isSupported(TemporalField field) {
+ return false;
+ }
+ @Override
+ public long getLong(TemporalField field) {
+ throw new DateTimeException("Unsupported field: " + field);
+ }
+ @SuppressWarnings("unchecked")
+ @Override
+ public
+ * The comparison is based on the ID.
+ *
+ * @param obj the object to check, null returns false
+ * @return true if this is equal to the other time-zone ID
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof ZoneId) {
+ ZoneId other = (ZoneId) obj;
+ return getId().equals(other.getId());
+ }
+ return false;
+ }
+
+ /**
+ * A hash code for this time-zone ID.
+ *
+ * @return a suitable hash code
+ */
+ @Override
+ public int hashCode() {
+ return getId().hashCode();
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Outputs this zone as a {@code String}, using the ID.
+ *
+ * @return a string representation of this time-zone ID, not null
+ */
+ @Override
+ public String toString() {
+ return getId();
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Writes the object using a
+ * dedicated serialized form.
+ *
+ * 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.
+ *
+ * Different parts of the world have different time-zone offsets.
+ * The rules for how offsets vary by place and time of year are captured in the
+ * {@link ZoneId} class.
+ *
+ * For example, Paris is one hour ahead of Greenwich/UTC in winter and two hours
+ * ahead in summer. The {@code ZoneId} instance for Paris will reference two
+ * {@code ZoneOffset} instances - a {@code +01:00} instance for winter,
+ * and a {@code +02:00} instance for summer.
+ *
+ * In 2008, time-zone offsets around the world extended from -12:00 to +14:00.
+ * To prevent any problems with that range being extended, yet still provide
+ * validation, the range of offsets is restricted to -18:00 to 18:00 inclusive.
+ *
+ * This class is designed for use with the ISO calendar system.
+ * The fields of hours, minutes and seconds make assumptions that are valid for the
+ * standard ISO definitions of those fields. This class may be used with other
+ * calendar systems providing the definition of the time fields matches those
+ * of the ISO calendar system.
+ *
+ * Instances of {@code ZoneOffset} must be compared using {@link #equals}.
+ * Implementations may choose to cache certain common offsets, however
+ * applications must not rely on such caching.
+ *
+ *
+ * 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:
+ *
+ * Note that ± means either the plus or minus symbol.
+ *
+ * The ID of the returned offset will be normalized to one of the formats
+ * described by {@link #getId()}.
+ *
+ * The maximum supported range is from +18:00 to -18:00 inclusive.
+ *
+ * @param offsetId the offset ID, not null
+ * @return the zone-offset, not null
+ * @throws DateTimeException if the offset ID is invalid
+ */
+ @SuppressWarnings("fallthrough")
+ public static ZoneOffset of(String offsetId) {
+ Objects.requireNonNull(offsetId, "offsetId");
+ // "Z" is always in the cache
+ ZoneOffset offset = ID_CACHE.get(offsetId);
+ if (offset != null) {
+ return offset;
+ }
+
+ // parse - +h, +hh, +hhmm, +hh:mm, +hhmmss, +hh:mm:ss
+ final int hours, minutes, seconds;
+ switch (offsetId.length()) {
+ case 2:
+ offsetId = offsetId.charAt(0) + "0" + offsetId.charAt(1); // fallthru
+ case 3:
+ hours = parseNumber(offsetId, 1, false);
+ minutes = 0;
+ seconds = 0;
+ break;
+ case 5:
+ hours = parseNumber(offsetId, 1, false);
+ minutes = parseNumber(offsetId, 3, false);
+ seconds = 0;
+ break;
+ case 6:
+ hours = parseNumber(offsetId, 1, false);
+ minutes = parseNumber(offsetId, 4, true);
+ seconds = 0;
+ break;
+ case 7:
+ hours = parseNumber(offsetId, 1, false);
+ minutes = parseNumber(offsetId, 3, false);
+ seconds = parseNumber(offsetId, 5, false);
+ break;
+ case 9:
+ hours = parseNumber(offsetId, 1, false);
+ minutes = parseNumber(offsetId, 4, true);
+ seconds = parseNumber(offsetId, 7, true);
+ break;
+ default:
+ throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid");
+ }
+ char first = offsetId.charAt(0);
+ if (first != '+' && first != '-') {
+ throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid: Plus/minus not found when expected");
+ }
+ if (first == '-') {
+ return ofHoursMinutesSeconds(-hours, -minutes, -seconds);
+ } else {
+ return ofHoursMinutesSeconds(hours, minutes, seconds);
+ }
+ }
+
+ /**
+ * Parse a two digit zero-prefixed number.
+ *
+ * @param offsetId the offset ID, not null
+ * @param pos the position to parse, valid
+ * @param precededByColon should this number be prefixed by a precededByColon
+ * @return the parsed number, from 0 to 99
+ */
+ private static int parseNumber(CharSequence offsetId, int pos, boolean precededByColon) {
+ if (precededByColon && offsetId.charAt(pos - 1) != ':') {
+ throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid: Colon not found when expected");
+ }
+ char ch1 = offsetId.charAt(pos);
+ char ch2 = offsetId.charAt(pos + 1);
+ if (ch1 < '0' || ch1 > '9' || ch2 < '0' || ch2 > '9') {
+ throw new DateTimeException("Zone offset ID '" + offsetId + "' is invalid: Non numeric characters found");
+ }
+ return (ch1 - 48) * 10 + (ch2 - 48);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code ZoneOffset} using an offset in hours.
+ *
+ * @param hours the time-zone offset in hours, from -18 to +18
+ * @return the zone-offset, not null
+ * @throws DateTimeException if the offset is not in the required range
+ */
+ public static ZoneOffset ofHours(int hours) {
+ return ofHoursMinutesSeconds(hours, 0, 0);
+ }
+
+ /**
+ * Obtains an instance of {@code ZoneOffset} using an offset in
+ * hours and minutes.
+ *
+ * The sign of the hours and minutes components must match.
+ * Thus, if the hours is negative, the minutes must be negative or zero.
+ * If the hours is zero, the minutes may be positive, negative or zero.
+ *
+ * @param hours the time-zone offset in hours, from -18 to +18
+ * @param minutes the time-zone offset in minutes, from 0 to ±59, sign matches hours
+ * @return the zone-offset, not null
+ * @throws DateTimeException if the offset is not in the required range
+ */
+ public static ZoneOffset ofHoursMinutes(int hours, int minutes) {
+ return ofHoursMinutesSeconds(hours, minutes, 0);
+ }
+
+ /**
+ * Obtains an instance of {@code ZoneOffset} using an offset in
+ * hours, minutes and seconds.
+ *
+ * The sign of the hours, minutes and seconds components must match.
+ * Thus, if the hours is negative, the minutes and seconds must be negative or zero.
+ *
+ * @param hours the time-zone offset in hours, from -18 to +18
+ * @param minutes the time-zone offset in minutes, from 0 to ±59, sign matches hours and seconds
+ * @param seconds the time-zone offset in seconds, from 0 to ±59, sign matches hours and minutes
+ * @return the zone-offset, not null
+ * @throws DateTimeException if the offset is not in the required range
+ */
+ public static ZoneOffset ofHoursMinutesSeconds(int hours, int minutes, int seconds) {
+ validate(hours, minutes, seconds);
+ int totalSeconds = totalSeconds(hours, minutes, seconds);
+ return ofTotalSeconds(totalSeconds);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code ZoneOffset} from a temporal object.
+ *
+ * A {@code TemporalAccessor} represents some form of date and time information.
+ * This factory converts the arbitrary temporal object to an instance of {@code ZoneOffset}.
+ *
+ * The conversion extracts the {@link ChronoField#OFFSET_SECONDS offset-seconds} field.
+ *
+ * This method matches the signature of the functional interface {@link TemporalQuery}
+ * allowing it to be used in queries via method reference, {@code ZoneOffset::from}.
+ *
+ * @param temporal the temporal object to convert, not null
+ * @return the zone-offset, not null
+ * @throws DateTimeException if unable to convert to an {@code ZoneOffset}
+ */
+ public static ZoneOffset from(TemporalAccessor temporal) {
+ if (temporal instanceof ZoneOffset) {
+ return (ZoneOffset) temporal;
+ }
+ try {
+ return ofTotalSeconds(temporal.get(OFFSET_SECONDS));
+ } catch (DateTimeException ex) {
+ throw new DateTimeException("Unable to obtain ZoneOffset from TemporalAccessor: " + temporal.getClass(), ex);
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Validates the offset fields.
+ *
+ * @param hours the time-zone offset in hours, from -18 to +18
+ * @param minutes the time-zone offset in minutes, from 0 to ±59
+ * @param seconds the time-zone offset in seconds, from 0 to ±59
+ * @throws DateTimeException if the offset is not in the required range
+ */
+ private static void validate(int hours, int minutes, int seconds) {
+ if (hours < -18 || hours > 18) {
+ throw new DateTimeException("Zone offset hours not in valid range: value " + hours +
+ " is not in the range -18 to 18");
+ }
+ if (hours > 0) {
+ if (minutes < 0 || seconds < 0) {
+ throw new DateTimeException("Zone offset minutes and seconds must be positive because hours is positive");
+ }
+ } else if (hours < 0) {
+ if (minutes > 0 || seconds > 0) {
+ throw new DateTimeException("Zone offset minutes and seconds must be negative because hours is negative");
+ }
+ } else if ((minutes > 0 && seconds < 0) || (minutes < 0 && seconds > 0)) {
+ throw new DateTimeException("Zone offset minutes and seconds must have the same sign");
+ }
+ if (Math.abs(minutes) > 59) {
+ throw new DateTimeException("Zone offset minutes not in valid range: abs(value) " +
+ Math.abs(minutes) + " is not in the range 0 to 59");
+ }
+ if (Math.abs(seconds) > 59) {
+ throw new DateTimeException("Zone offset seconds not in valid range: abs(value) " +
+ Math.abs(seconds) + " is not in the range 0 to 59");
+ }
+ if (Math.abs(hours) == 18 && (Math.abs(minutes) > 0 || Math.abs(seconds) > 0)) {
+ throw new DateTimeException("Zone offset not in valid range: -18:00 to +18:00");
+ }
+ }
+
+ /**
+ * Calculates the total offset in seconds.
+ *
+ * @param hours the time-zone offset in hours, from -18 to +18
+ * @param minutes the time-zone offset in minutes, from 0 to ±59, sign matches hours and seconds
+ * @param seconds the time-zone offset in seconds, from 0 to ±59, sign matches hours and minutes
+ * @return the total in seconds
+ */
+ private static int totalSeconds(int hours, int minutes, int seconds) {
+ return hours * SECONDS_PER_HOUR + minutes * SECONDS_PER_MINUTE + seconds;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code ZoneOffset} specifying the total offset in seconds
+ *
+ * The offset must be in the range {@code -18:00} to {@code +18:00}, which corresponds to -64800 to +64800.
+ *
+ * @param totalSeconds the total time-zone offset in seconds, from -64800 to +64800
+ * @return the ZoneOffset, not null
+ * @throws DateTimeException if the offset is not in the required range
+ */
+ public static ZoneOffset ofTotalSeconds(int totalSeconds) {
+ if (Math.abs(totalSeconds) > MAX_SECONDS) {
+ throw new DateTimeException("Zone offset not in valid range: -18:00 to +18:00");
+ }
+ if (totalSeconds % (15 * SECONDS_PER_MINUTE) == 0) {
+ Integer totalSecs = totalSeconds;
+ ZoneOffset result = SECONDS_CACHE.get(totalSecs);
+ if (result == null) {
+ result = new ZoneOffset(totalSeconds);
+ SECONDS_CACHE.putIfAbsent(totalSecs, result);
+ result = SECONDS_CACHE.get(totalSecs);
+ ID_CACHE.putIfAbsent(result.getId(), result);
+ }
+ return result;
+ } else {
+ return new ZoneOffset(totalSeconds);
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Constructor.
+ *
+ * @param totalSeconds the total time-zone offset in seconds, from -64800 to +64800
+ */
+ private ZoneOffset(int totalSeconds) {
+ super();
+ this.totalSeconds = totalSeconds;
+ id = buildId(totalSeconds);
+ }
+
+ private static String buildId(int totalSeconds) {
+ if (totalSeconds == 0) {
+ return "Z";
+ } else {
+ int absTotalSeconds = Math.abs(totalSeconds);
+ StringBuilder buf = new StringBuilder();
+ int absHours = absTotalSeconds / SECONDS_PER_HOUR;
+ int absMinutes = (absTotalSeconds / SECONDS_PER_MINUTE) % MINUTES_PER_HOUR;
+ buf.append(totalSeconds < 0 ? "-" : "+")
+ .append(absHours < 10 ? "0" : "").append(absHours)
+ .append(absMinutes < 10 ? ":0" : ":").append(absMinutes);
+ int absSeconds = absTotalSeconds % SECONDS_PER_MINUTE;
+ if (absSeconds != 0) {
+ buf.append(absSeconds < 10 ? ":0" : ":").append(absSeconds);
+ }
+ return buf.toString();
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the total zone offset in seconds.
+ *
+ * This is the primary way to access the offset amount.
+ * It returns the total of the hours, minutes and seconds fields as a
+ * single offset that can be added to a time.
+ *
+ * @return the total zone offset amount in seconds
+ */
+ public int getTotalSeconds() {
+ return totalSeconds;
+ }
+
+ /**
+ * Gets the normalized zone offset ID.
+ *
+ * The ID is minor variation to the standard ISO-8601 formatted string
+ * for the offset. There are three formats:
+ *
+ *
+ * @return the zone offset ID, not null
+ */
+ @Override
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Gets the associated time-zone rules.
+ *
+ * The rules will always return this offset when queried.
+ * The implementation class is immutable, thread-safe and serializable.
+ *
+ * @return the rules, not null
+ */
+ @Override
+ public ZoneRules getRules() {
+ return ZoneRules.of(this);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks if the specified field is supported.
+ *
+ * This checks if this offset can be queried for the specified field.
+ * If false, then calling the {@link #range(TemporalField) range} and
+ * {@link #get(TemporalField) get} methods will throw an exception.
+ *
+ * If the field is a {@link ChronoField} then the query is implemented here.
+ * The {@code OFFSET_SECONDS} field returns true.
+ * All other {@code ChronoField} instances will return false.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)}
+ * passing {@code this} as the argument.
+ * Whether the field is supported is determined by the field.
+ *
+ * @param field the field to check, null returns false
+ * @return true if the field is supported on this offset, false if not
+ */
+ @Override
+ public boolean isSupported(TemporalField field) {
+ if (field instanceof ChronoField) {
+ return field == OFFSET_SECONDS;
+ }
+ return field != null && field.doIsSupported(this);
+ }
+
+ /**
+ * Gets the range of valid values for the specified field.
+ *
+ * The range object expresses the minimum and maximum valid values for a field.
+ * This offset is used to enhance the accuracy of the returned range.
+ * If it is not possible to return the range, because the field is not supported
+ * or for some other reason, an exception is thrown.
+ *
+ * If the field is a {@link ChronoField} then the query is implemented here.
+ * The {@link #isSupported(TemporalField) supported fields} will return
+ * appropriate range instances.
+ * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)}
+ * passing {@code this} as the argument.
+ * Whether the range can be obtained is determined by the field.
+ *
+ * @param field the field to query the range for, not null
+ * @return the range of valid values for the field, not null
+ * @throws DateTimeException if the range for the field cannot be obtained
+ */
+ @Override // override for Javadoc
+ public ValueRange range(TemporalField field) {
+ return TemporalAccessor.super.range(field);
+ }
+
+ /**
+ * Gets the value of the specified field from this offset as an {@code int}.
+ *
+ * This queries this offset for the value for the specified field.
+ * The returned value will always be within the valid range of values for the field.
+ * If it is not possible to return the value, because the field is not supported
+ * or for some other reason, an exception is thrown.
+ *
+ * If the field is a {@link ChronoField} then the query is implemented here.
+ * The {@code OFFSET_SECONDS} field returns the value of the offset.
+ * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+ * passing {@code this} as the argument. Whether the value can be obtained,
+ * and what the value represents, is determined by the field.
+ *
+ * @param field the field to get, not null
+ * @return the value for the field
+ * @throws DateTimeException if a value for the field cannot be obtained
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override // override for Javadoc and performance
+ public int get(TemporalField field) {
+ if (field == OFFSET_SECONDS) {
+ return totalSeconds;
+ } else if (field instanceof ChronoField) {
+ throw new DateTimeException("Unsupported field: " + field.getName());
+ }
+ return range(field).checkValidIntValue(getLong(field), field);
+ }
+
+ /**
+ * Gets the value of the specified field from this offset as a {@code long}.
+ *
+ * This queries this offset for the value for the specified field.
+ * If it is not possible to return the value, because the field is not supported
+ * or for some other reason, an exception is thrown.
+ *
+ * If the field is a {@link ChronoField} then the query is implemented here.
+ * The {@code OFFSET_SECONDS} field returns the value of the offset.
+ * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+ * passing {@code this} as the argument. Whether the value can be obtained,
+ * and what the value represents, is determined by the field.
+ *
+ * @param field the field to get, not null
+ * @return the value for the field
+ * @throws DateTimeException if a value for the field cannot be obtained
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public long getLong(TemporalField field) {
+ if (field == OFFSET_SECONDS) {
+ return totalSeconds;
+ } else if (field instanceof ChronoField) {
+ throw new DateTimeException("Unsupported field: " + field.getName());
+ }
+ return field.doGet(this);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Queries this offset using the specified query.
+ *
+ * This queries this offset using the specified query strategy object.
+ * The {@code TemporalQuery} object defines the logic to be used to
+ * obtain the result. Read the documentation of the query to understand
+ * what the result of this method will be.
+ *
+ * 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
+ * This returns a temporal object of the same observable type as the input
+ * with the offset changed to be the same as this.
+ *
+ * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+ * passing {@link ChronoField#OFFSET_SECONDS} as the field.
+ *
+ * In most cases, it is clearer to reverse the calling pattern by using
+ * {@link Temporal#with(TemporalAdjuster)}:
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param temporal the target object to be adjusted, not null
+ * @return the adjusted object, not null
+ * @throws DateTimeException if unable to make the adjustment
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public Temporal adjustInto(Temporal temporal) {
+ return temporal.with(OFFSET_SECONDS, totalSeconds);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Compares this offset to another offset in descending order.
+ *
+ * The offsets are compared in the order that they occur for the same time
+ * of day around the world. Thus, an offset of {@code +10:00} comes before an
+ * offset of {@code +09:00} and so on down to {@code -18:00}.
+ *
+ * The comparison is "consistent with equals", as defined by {@link Comparable}.
+ *
+ * @param other the other date to compare to, not null
+ * @return the comparator value, negative if less, postive if greater
+ * @throws NullPointerException if {@code other} is null
+ */
+ @Override
+ public int compareTo(ZoneOffset other) {
+ return other.totalSeconds - totalSeconds;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks if this offset is equal to another offset.
+ *
+ * The comparison is based on the amount of the offset in seconds.
+ * This is equivalent to a comparison by ID.
+ *
+ * @param obj the object to check, null returns false
+ * @return true if this is equal to the other offset
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof ZoneOffset) {
+ return totalSeconds == ((ZoneOffset) obj).totalSeconds;
+ }
+ return false;
+ }
+
+ /**
+ * A hash code for this offset.
+ *
+ * @return a suitable hash code
+ */
+ @Override
+ public int hashCode() {
+ return totalSeconds;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Outputs this offset as a {@code String}, using the normalized ID.
+ *
+ * @return a string representation of this offset, not null
+ */
+ @Override
+ public String toString() {
+ return id;
+ }
+
+ // -----------------------------------------------------------------------
+ /**
+ * Writes the object using a
+ * dedicated serialized form.
+ *
+ * Time-zone information is categorized as a set of rules defining when and
+ * how the offset from UTC/Greenwich changes. These rules are accessed using
+ * identifiers based on geographical regions, such as countries or states.
+ * The most common region classification is the Time Zone Database (TZDB),
+ * which defines regions such as 'Europe/Paris' and 'Asia/Tokyo'.
+ *
+ * The region identifier, modeled by this class, is distinct from the
+ * underlying rules, modeled by {@link ZoneRules}.
+ * The rules are defined by governments and change frequently.
+ * By contrast, the region identifier is well-defined and long-lived.
+ * This separation also allows rules to be shared between regions if appropriate.
+ *
+ *
+ * This method parses the ID and applies any appropriate normalization.
+ * It does not validate the ID against the known set of IDsfor which rules are available.
+ *
+ * This method is intended for advanced use cases.
+ * For example, consider a system that always retrieves time-zone rules from a remote server.
+ * Using this factory would allow a {@code ZoneRegion}, and thus a {@code ZonedDateTime},
+ * to be created without loading the rules from the remote server.
+ *
+ * @param zoneId the time-zone ID, not null
+ * @return the zone ID, not null
+ * @throws DateTimeException if the ID format is invalid
+ */
+ private static ZoneRegion ofLenient(String zoneId) {
+ return ofId(zoneId, false);
+ }
+
+ /**
+ * Obtains an instance of {@code ZoneId} from an identifier.
+ *
+ * @param zoneId the time-zone ID, not null
+ * @param checkAvailable whether to check if the zone ID is available
+ * @return the zone ID, not null
+ * @throws DateTimeException if the ID format is invalid
+ * @throws DateTimeException if checking availability and the ID cannot be found
+ */
+ static ZoneRegion ofId(String zoneId, boolean checkAvailable) {
+ Objects.requireNonNull(zoneId, "zoneId");
+ if (zoneId.length() < 2 || zoneId.startsWith("UTC") ||
+ zoneId.startsWith("GMT") || (PATTERN.matcher(zoneId).matches() == false)) {
+ throw new DateTimeException("ZoneId format is not a valid region format");
+ }
+ ZoneRules rules = null;
+ try {
+ // always attempt load for better behavior after deserialization
+ rules = ZoneRulesProvider.getRules(zoneId);
+ } catch (ZoneRulesException ex) {
+ if (checkAvailable) {
+ throw ex;
+ }
+ }
+ return new ZoneRegion(zoneId, rules);
+ }
+
+ //-------------------------------------------------------------------------
+ /**
+ * Constructor.
+ *
+ * @param id the time-zone ID, not null
+ * @param rules the rules, null for lazy lookup
+ */
+ ZoneRegion(String id, ZoneRules rules) {
+ this.id = id;
+ this.rules = rules;
+ }
+
+ //-----------------------------------------------------------------------
+ @Override
+ public String getId() {
+ return id;
+ }
+
+ @Override
+ public ZoneRules getRules() {
+ // additional query for group provider when null allows for possibility
+ // that the provider was added after the ZoneId was created
+ return (rules != null ? rules : ZoneRulesProvider.getRules(id));
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Writes the object using a
+ * dedicated serialized form.
+ *
+ * {@code ZonedDateTime} is an immutable representation of a date-time with a time-zone.
+ * This class stores all date and time fields, to a precision of nanoseconds,
+ * and a time-zone, with a zone offset used to handle ambiguous local date-times.
+ * For example, the value
+ * "2nd October 2007 at 13:45.30.123456789 +02:00 in the Europe/Paris time-zone"
+ * can be stored in a {@code ZonedDateTime}.
+ *
+ * This class handles conversion from the local time-line of {@code LocalDateTime}
+ * to the instant time-line of {@code Instant}.
+ * The difference between the two time-lines is the offset from UTC/Greenwich,
+ * represented by a {@code ZoneOffset}.
+ *
+ * Converting between the two time-lines involves calculating the offset using the
+ * {@link ZoneRules rules} accessed from the {@code ZoneId}.
+ * Obtaining the offset for an instant is simple, as there is exactly one valid
+ * offset for each instant. By contrast, obtaining the offset for a local date-time
+ * is not straightforward. There are three cases:
+ *
+ *
+ * Any method that converts directly or implicitly from a local date-time to an
+ * instant by obtaining the offset has the potential to be complicated.
+ *
+ * For Gaps, the general strategy is that if the local date-time falls in the
+ * middle of a Gap, then the resulting zoned date-time will have a local date-time
+ * shifted forwards by the length of the Gap, resulting in a date-time in the later
+ * offset, typically "summer" time.
+ *
+ * For Overlaps, the general strategy is that if the local date-time falls in the
+ * middle of an Overlap, then the previous offset will be retained. If there is no
+ * previous offset, or the previous offset is invalid, then the earlier offset is
+ * used, typically "summer" time.. Two additional methods,
+ * {@link #withEarlierOffsetAtOverlap()} and {@link #withLaterOffsetAtOverlap()},
+ * help manage the case of an overlap.
+ *
+ *
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class ZonedDateTime
+ implements Temporal, ChronoZonedDateTime
+ * This will query the {@link Clock#systemDefaultZone() system clock} in the default
+ * time-zone to obtain the current date-time.
+ * The zone and offset will be set based on the time-zone in the clock.
+ *
+ * Using this method will prevent the ability to use an alternate clock for testing
+ * because the clock is hard-coded.
+ *
+ * @return the current date-time using the system clock, not null
+ */
+ public static ZonedDateTime now() {
+ return now(Clock.systemDefaultZone());
+ }
+
+ /**
+ * Obtains the current date-time from the system clock in the specified time-zone.
+ *
+ * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date-time.
+ * Specifying the time-zone avoids dependence on the default time-zone.
+ * The offset will be calculated from the specified time-zone.
+ *
+ * Using this method will prevent the ability to use an alternate clock for testing
+ * because the clock is hard-coded.
+ *
+ * @param zone the zone ID to use, not null
+ * @return the current date-time using the system clock, not null
+ */
+ public static ZonedDateTime now(ZoneId zone) {
+ return now(Clock.system(zone));
+ }
+
+ /**
+ * Obtains the current date-time from the specified clock.
+ *
+ * This will query the specified clock to obtain the current date-time.
+ * The zone and offset will be set based on the time-zone in the clock.
+ *
+ * Using this method allows the use of an alternate clock for testing.
+ * The alternate clock may be introduced using {@link Clock dependency injection}.
+ *
+ * @param clock the clock to use, not null
+ * @return the current date-time, not null
+ */
+ public static ZonedDateTime now(Clock clock) {
+ Objects.requireNonNull(clock, "clock");
+ final Instant now = clock.instant(); // called once
+ return ofInstant(now, clock.getZone());
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code ZonedDateTime} from a local date-time.
+ *
+ * This creates a zoned date-time matching the input local date-time as closely as possible.
+ * Time-zone rules, such as daylight savings, mean that not every local date-time
+ * is valid for the specified zone, thus the local date-time may be adjusted.
+ *
+ * The local date-time is resolved to a single instant on the time-line.
+ * This is achieved by finding a valid offset from UTC/Greenwich for the local
+ * date-time as defined by the {@link ZoneRules rules} of the zone ID.
+ *
+ * In most cases, there is only one valid offset for a local date-time.
+ * In the case of an overlap, when clocks are set back, there are two valid offsets.
+ * This method uses the earlier offset typically corresponding to "summer".
+ *
+ * In the case of a gap, when clocks jump forward, there is no valid offset.
+ * Instead, the local date-time is adjusted to be later by the length of the gap.
+ * For a typical one hour daylight savings change, the local date-time will be
+ * moved one hour later into the offset typically corresponding to "summer".
+ *
+ * @param localDateTime the local date-time, not null
+ * @param zone the time-zone, not null
+ * @return the zoned date-time, not null
+ */
+ public static ZonedDateTime of(LocalDateTime localDateTime, ZoneId zone) {
+ return ofLocal(localDateTime, zone, null);
+ }
+
+ /**
+ * Obtains an instance of {@code ZonedDateTime} from a local date-time
+ * using the preferred offset if possible.
+ *
+ * The local date-time is resolved to a single instant on the time-line.
+ * This is achieved by finding a valid offset from UTC/Greenwich for the local
+ * date-time as defined by the {@link ZoneRules rules} of the zone ID.
+ *
+ * In most cases, there is only one valid offset for a local date-time.
+ * In the case of an overlap, where clocks are set back, there are two valid offsets.
+ * If the preferred offset is one of the valid offsets then it is used.
+ * Otherwise the earlier valid offset is used, typically corresponding to "summer".
+ *
+ * In the case of a gap, where clocks jump forward, there is no valid offset.
+ * Instead, the local date-time is adjusted to be later by the length of the gap.
+ * For a typical one hour daylight savings change, the local date-time will be
+ * moved one hour later into the offset typically corresponding to "summer".
+ *
+ * @param localDateTime the local date-time, not null
+ * @param zone the time-zone, not null
+ * @param preferredOffset the zone offset, null if no preference
+ * @return the zoned date-time, not null
+ */
+ public static ZonedDateTime ofLocal(LocalDateTime localDateTime, ZoneId zone, ZoneOffset preferredOffset) {
+ Objects.requireNonNull(localDateTime, "localDateTime");
+ Objects.requireNonNull(zone, "zone");
+ if (zone instanceof ZoneOffset) {
+ return new ZonedDateTime(localDateTime, (ZoneOffset) zone, zone);
+ }
+ ZoneRules rules = zone.getRules();
+ List
+ * This creates a zoned date-time with the same instant as that specified.
+ * Calling {@link #toInstant()} will return an instant equal to the one used here.
+ *
+ * Converting an instant to a zoned date-time is simple as there is only one valid
+ * offset for each instant.
+ *
+ * @param instant the instant to create the date-time from, not null
+ * @param zone the time-zone, not null
+ * @return the zoned date-time, not null
+ * @throws DateTimeException if the result exceeds the supported range
+ */
+ public static ZonedDateTime ofInstant(Instant instant, ZoneId zone) {
+ Objects.requireNonNull(instant, "instant");
+ Objects.requireNonNull(zone, "zone");
+ return create(instant.getEpochSecond(), instant.getNano(), zone);
+ }
+
+ /**
+ * Obtains an instance of {@code ZonedDateTime} from the instant formed by combining
+ * the local date-time and offset.
+ *
+ * This creates a zoned date-time by {@link LocalDateTime#toInstant(ZoneOffset) combining}
+ * the {@code LocalDateTime} and {@code ZoneOffset}.
+ * This combination uniquely specifies an instant without ambiguity.
+ *
+ * Converting an instant to a zoned date-time is simple as there is only one valid
+ * offset for each instant. If the valid offset is different to the offset specified,
+ * the the date-time and offset of the zoned date-time will differ from those specified.
+ *
+ * If the {@code ZoneId} to be used is a {@code ZoneOffset}, this method is equivalent
+ * to {@link #of(LocalDateTime, ZoneId)}.
+ *
+ * @param localDateTime the local date-time, not null
+ * @param offset the zone offset, not null
+ * @param zone the time-zone, not null
+ * @return the zoned date-time, not null
+ */
+ public static ZonedDateTime ofInstant(LocalDateTime localDateTime, ZoneOffset offset, ZoneId zone) {
+ Objects.requireNonNull(localDateTime, "localDateTime");
+ Objects.requireNonNull(offset, "offset");
+ Objects.requireNonNull(zone, "zone");
+ return create(localDateTime.toEpochSecond(offset), localDateTime.getNano(), zone);
+ }
+
+ /**
+ * Obtains an instance of {@code ZonedDateTime} using seconds from the
+ * epoch of 1970-01-01T00:00:00Z.
+ *
+ * @param epochSecond the number of seconds from the epoch of 1970-01-01T00:00:00Z
+ * @param nanoOfSecond the nanosecond within the second, from 0 to 999,999,999
+ * @param zone the time-zone, not null
+ * @return the zoned date-time, not null
+ * @throws DateTimeException if the result exceeds the supported range
+ */
+ private static ZonedDateTime create(long epochSecond, int nanoOfSecond, ZoneId zone) {
+ ZoneRules rules = zone.getRules();
+ Instant instant = Instant.ofEpochSecond(epochSecond, nanoOfSecond); // TODO: rules should be queryable by epochSeconds
+ ZoneOffset offset = rules.getOffset(instant);
+ LocalDateTime ldt = LocalDateTime.ofEpochSecond(epochSecond, nanoOfSecond, offset);
+ return new ZonedDateTime(ldt, offset, zone);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code ZonedDateTime} strictly validating the
+ * combination of local date-time, offset and zone ID.
+ *
+ * This creates a zoned date-time ensuring that the offset is valid for the
+ * local date-time according to the rules of the specified zone.
+ * If the offset is invalid, an exception is thrown.
+ *
+ * @param localDateTime the local date-time, not null
+ * @param offset the zone offset, not null
+ * @param zone the time-zone, not null
+ * @return the zoned date-time, not null
+ */
+ public static ZonedDateTime ofStrict(LocalDateTime localDateTime, ZoneOffset offset, ZoneId zone) {
+ Objects.requireNonNull(localDateTime, "localDateTime");
+ Objects.requireNonNull(offset, "offset");
+ Objects.requireNonNull(zone, "zone");
+ ZoneRules rules = zone.getRules();
+ if (rules.isValidOffset(localDateTime, offset) == false) {
+ ZoneOffsetTransition trans = rules.getTransition(localDateTime);
+ if (trans != null && trans.isGap()) {
+ // error message says daylight savings for simplicity
+ // even though there are other kinds of gaps
+ throw new DateTimeException("LocalDateTime '" + localDateTime +
+ "' does not exist in zone '" + zone +
+ "' due to a gap in the local time-line, typically caused by daylight savings");
+ }
+ throw new DateTimeException("ZoneOffset '" + offset + "' is not valid for LocalDateTime '" +
+ localDateTime + "' in zone '" + zone + "'");
+ }
+ return new ZonedDateTime(localDateTime, offset, zone);
+ }
+
+ /**
+ * Obtains an instance of {@code ZonedDateTime} leniently, for advanced use cases,
+ * allowing any combination of local date-time, offset and zone ID.
+ *
+ * This creates a zoned date-time with no checks other than no nulls.
+ * This means that the resulting zoned date-time may have an offset that is in conflict
+ * with the zone ID.
+ *
+ * This method is intended for advanced use cases.
+ * For example, consider the case where a zoned date-time with valid fields is created
+ * and then stored in a database or serialization-based store. At some later point,
+ * the object is then re-loaded. However, between those points in time, the government
+ * that defined the time-zone has changed the rules, such that the originally stored
+ * local date-time now does not occur. This method can be used to create the object
+ * in an "invalid" state, despite the change in rules.
+ *
+ * @param localDateTime the local date-time, not null
+ * @param offset the zone offset, not null
+ * @param zone the time-zone, not null
+ * @return the zoned date-time, not null
+ */
+ private static ZonedDateTime ofLenient(LocalDateTime localDateTime, ZoneOffset offset, ZoneId zone) {
+ Objects.requireNonNull(localDateTime, "localDateTime");
+ Objects.requireNonNull(offset, "offset");
+ Objects.requireNonNull(zone, "zone");
+ if (zone instanceof ZoneOffset && offset.equals(zone) == false) {
+ throw new IllegalArgumentException("ZoneId must match ZoneOffset");
+ }
+ return new ZonedDateTime(localDateTime, offset, zone);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code ZonedDateTime} from a temporal object.
+ *
+ * A {@code TemporalAccessor} represents some form of date and time information.
+ * This factory converts the arbitrary temporal object to an instance of {@code ZonedDateTime}.
+ *
+ * The conversion will first obtain a {@code ZoneId}. It will then try to obtain an instant.
+ * If that fails it will try to obtain a local date-time.
+ * The zoned date time will either be a combination of {@code ZoneId} and instant,
+ * or {@code ZoneId} and local date-time.
+ *
+ * This method matches the signature of the functional interface {@link TemporalQuery}
+ * allowing it to be used in queries via method reference, {@code ZonedDateTime::from}.
+ *
+ * @param temporal the temporal object to convert, not null
+ * @return the zoned date-time, not null
+ * @throws DateTimeException if unable to convert to an {@code ZonedDateTime}
+ */
+ public static ZonedDateTime from(TemporalAccessor temporal) {
+ if (temporal instanceof ZonedDateTime) {
+ return (ZonedDateTime) temporal;
+ }
+ try {
+ ZoneId zone = ZoneId.from(temporal);
+ try {
+ long epochSecond = temporal.getLong(INSTANT_SECONDS);
+ int nanoOfSecond = temporal.get(NANO_OF_SECOND);
+ return create(epochSecond, nanoOfSecond, zone);
+
+ } catch (DateTimeException ex1) {
+ LocalDateTime ldt = LocalDateTime.from(temporal);
+ return of(ldt, zone);
+ }
+ } catch (DateTimeException ex) {
+ throw new DateTimeException("Unable to create ZonedDateTime from TemporalAccessor: " + temporal.getClass(), ex);
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code ZonedDateTime} from a text string such as
+ * {@code 2007-12-03T10:15:30+01:00[Europe/Paris]}.
+ *
+ * The string must represent a valid date-time and is parsed using
+ * {@link java.time.format.DateTimeFormatters#isoZonedDateTime()}.
+ *
+ * @param text the text to parse such as "2007-12-03T10:15:30+01:00[Europe/Paris]", not null
+ * @return the parsed zoned date-time, not null
+ * @throws DateTimeParseException if the text cannot be parsed
+ */
+ public static ZonedDateTime parse(CharSequence text) {
+ return parse(text, DateTimeFormatters.isoZonedDateTime());
+ }
+
+ /**
+ * Obtains an instance of {@code ZonedDateTime} from a text string using a specific formatter.
+ *
+ * The text is parsed using the formatter, returning a date-time.
+ *
+ * @param text the text to parse, not null
+ * @param formatter the formatter to use, not null
+ * @return the parsed zoned date-time, not null
+ * @throws DateTimeParseException if the text cannot be parsed
+ */
+ public static ZonedDateTime parse(CharSequence text, DateTimeFormatter formatter) {
+ Objects.requireNonNull(formatter, "formatter");
+ return formatter.parse(text, ZonedDateTime::from);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Constructor.
+ *
+ * @param dateTime the date-time, validated as not null
+ * @param offset the zone offset, validated as not null
+ * @param zone the time-zone, validated as not null
+ */
+ private ZonedDateTime(LocalDateTime dateTime, ZoneOffset offset, ZoneId zone) {
+ this.dateTime = dateTime;
+ this.offset = offset;
+ this.zone = zone;
+ }
+
+ /**
+ * Resolves the new local date-time using this zone ID, retaining the offset if possible.
+ *
+ * @param newDateTime the new local date-time, not null
+ * @return the zoned date-time, not null
+ */
+ private ZonedDateTime resolveLocal(LocalDateTime newDateTime) {
+ return ofLocal(newDateTime, zone, offset);
+ }
+
+ /**
+ * Resolves the new local date-time using the offset to identify the instant.
+ *
+ * @param newDateTime the new local date-time, not null
+ * @return the zoned date-time, not null
+ */
+ private ZonedDateTime resolveInstant(LocalDateTime newDateTime) {
+ return ofInstant(newDateTime, offset, zone);
+ }
+
+ /**
+ * Resolves the offset into this zoned date-time.
+ *
+ * This will use the new offset to find the instant, which is then looked up
+ * using the zone ID to find the actual offset to use.
+ *
+ * @param offset the offset, not null
+ * @return the zoned date-time, not null
+ */
+ private ZonedDateTime resolveOffset(ZoneOffset offset) {
+ long epSec = dateTime.toEpochSecond(offset);
+ return create(epSec, dateTime.getNano(), zone);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks if the specified field is supported.
+ *
+ * This checks if this date-time can be queried for the specified field.
+ * If false, then calling the {@link #range(TemporalField) range} and
+ * {@link #get(TemporalField) get} methods will throw an exception.
+ *
+ * If the field is a {@link ChronoField} then the query is implemented here.
+ * The supported fields are:
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)}
+ * passing {@code this} as the argument.
+ * Whether the field is supported is determined by the field.
+ *
+ * @param field the field to check, null returns false
+ * @return true if the field is supported on this date-time, false if not
+ */
+ @Override
+ public boolean isSupported(TemporalField field) {
+ return field instanceof ChronoField || (field != null && field.doIsSupported(this));
+ }
+
+ /**
+ * Gets the range of valid values for the specified field.
+ *
+ * The range object expresses the minimum and maximum valid values for a field.
+ * This date-time is used to enhance the accuracy of the returned range.
+ * If it is not possible to return the range, because the field is not supported
+ * or for some other reason, an exception is thrown.
+ *
+ * If the field is a {@link ChronoField} then the query is implemented here.
+ * The {@link #isSupported(TemporalField) supported fields} will return
+ * appropriate range instances.
+ * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)}
+ * passing {@code this} as the argument.
+ * Whether the range can be obtained is determined by the field.
+ *
+ * @param field the field to query the range for, not null
+ * @return the range of valid values for the field, not null
+ * @throws DateTimeException if the range for the field cannot be obtained
+ */
+ @Override
+ public ValueRange range(TemporalField field) {
+ if (field instanceof ChronoField) {
+ if (field == INSTANT_SECONDS || field == OFFSET_SECONDS) {
+ return field.range();
+ }
+ return dateTime.range(field);
+ }
+ return field.doRange(this);
+ }
+
+ /**
+ * Gets the value of the specified field from this date-time as an {@code int}.
+ *
+ * This queries this date-time for the value for the specified field.
+ * The returned value will always be within the valid range of values for the field.
+ * If it is not possible to return the value, because the field is not supported
+ * or for some other reason, an exception is thrown.
+ *
+ * If the field is a {@link ChronoField} then the query is implemented here.
+ * The {@link #isSupported(TemporalField) supported fields} will return valid
+ * values based on this date-time, except {@code NANO_OF_DAY}, {@code MICRO_OF_DAY},
+ * {@code EPOCH_DAY}, {@code EPOCH_MONTH} and {@code INSTANT_SECONDS} which are too
+ * large to fit in an {@code int} and throw a {@code DateTimeException}.
+ * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+ * passing {@code this} as the argument. Whether the value can be obtained,
+ * and what the value represents, is determined by the field.
+ *
+ * @param field the field to get, not null
+ * @return the value for the field
+ * @throws DateTimeException if a value for the field cannot be obtained
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override // override for Javadoc and performance
+ public int get(TemporalField field) {
+ if (field instanceof ChronoField) {
+ switch ((ChronoField) field) {
+ case INSTANT_SECONDS: throw new DateTimeException("Field too large for an int: " + field);
+ case OFFSET_SECONDS: return getOffset().getTotalSeconds();
+ }
+ return dateTime.get(field);
+ }
+ return ChronoZonedDateTime.super.get(field);
+ }
+
+ /**
+ * Gets the value of the specified field from this date-time as a {@code long}.
+ *
+ * This queries this date-time for the value for the specified field.
+ * If it is not possible to return the value, because the field is not supported
+ * or for some other reason, an exception is thrown.
+ *
+ * If the field is a {@link ChronoField} then the query is implemented here.
+ * The {@link #isSupported(TemporalField) supported fields} will return valid
+ * values based on this date-time.
+ * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
+ * passing {@code this} as the argument. Whether the value can be obtained,
+ * and what the value represents, is determined by the field.
+ *
+ * @param field the field to get, not null
+ * @return the value for the field
+ * @throws DateTimeException if a value for the field cannot be obtained
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public long getLong(TemporalField field) {
+ if (field instanceof ChronoField) {
+ switch ((ChronoField) field) {
+ case INSTANT_SECONDS: return toEpochSecond();
+ case OFFSET_SECONDS: return getOffset().getTotalSeconds();
+ }
+ return dateTime.getLong(field);
+ }
+ return field.doGet(this);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the zone offset, such as '+01:00'.
+ *
+ * This is the offset of the local date-time from UTC/Greenwich.
+ *
+ * @return the zone offset, not null
+ */
+ @Override
+ public ZoneOffset getOffset() {
+ return offset;
+ }
+
+ /**
+ * Returns a copy of this date-time changing the zone offset to the
+ * earlier of the two valid offsets at a local time-line overlap.
+ *
+ * This method only has any effect when the local time-line overlaps, such as
+ * at an autumn daylight savings cutover. In this scenario, there are two
+ * valid offsets for the local date-time. Calling this method will return
+ * a zoned date-time with the earlier of the two selected.
+ *
+ * If this method is called when it is not an overlap, {@code this}
+ * is returned.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @return a {@code ZonedDateTime} based on this date-time with the earlier offset, not null
+ */
+ @Override
+ public ZonedDateTime withEarlierOffsetAtOverlap() {
+ ZoneOffsetTransition trans = getZone().getRules().getTransition(dateTime);
+ if (trans != null && trans.isOverlap()) {
+ ZoneOffset earlierOffset = trans.getOffsetBefore();
+ if (earlierOffset.equals(offset) == false) {
+ return new ZonedDateTime(dateTime, earlierOffset, zone);
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Returns a copy of this date-time changing the zone offset to the
+ * later of the two valid offsets at a local time-line overlap.
+ *
+ * This method only has any effect when the local time-line overlaps, such as
+ * at an autumn daylight savings cutover. In this scenario, there are two
+ * valid offsets for the local date-time. Calling this method will return
+ * a zoned date-time with the later of the two selected.
+ *
+ * If this method is called when it is not an overlap, {@code this}
+ * is returned.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @return a {@code ZonedDateTime} based on this date-time with the later offset, not null
+ */
+ @Override
+ public ZonedDateTime withLaterOffsetAtOverlap() {
+ ZoneOffsetTransition trans = getZone().getRules().getTransition(getDateTime());
+ if (trans != null) {
+ ZoneOffset laterOffset = trans.getOffsetAfter();
+ if (laterOffset.equals(offset) == false) {
+ return new ZonedDateTime(dateTime, laterOffset, zone);
+ }
+ }
+ return this;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the time-zone, such as 'Europe/Paris'.
+ *
+ * This returns the zone ID. This identifies the time-zone {@link ZoneRules rules}
+ * that determine when and how the offset from UTC/Greenwich changes.
+ *
+ * The zone ID may be same as the {@linkplain #getOffset() offset}.
+ * If this is true, then any future calculations, such as addition or subtraction,
+ * have no complex edge cases due to time-zone rules.
+ * See also {@link #withFixedOffsetZone()}.
+ *
+ * @return the time-zone, not null
+ */
+ @Override
+ public ZoneId getZone() {
+ return zone;
+ }
+
+ /**
+ * Returns a copy of this date-time with a different time-zone,
+ * retaining the local date-time if possible.
+ *
+ * This method changes the time-zone and retains the local date-time.
+ * The local date-time is only changed if it is invalid for the new zone,
+ * determined using the same approach as
+ * {@link #ofLocal(LocalDateTime, ZoneId, ZoneOffset)}.
+ *
+ * To change the zone and adjust the local date-time,
+ * use {@link #withZoneSameInstant(ZoneId)}.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param zone the time-zone to change to, not null
+ * @return a {@code ZonedDateTime} based on this date-time with the requested zone, not null
+ */
+ @Override
+ public ZonedDateTime withZoneSameLocal(ZoneId zone) {
+ Objects.requireNonNull(zone, "zone");
+ return this.zone.equals(zone) ? this : ofLocal(dateTime, zone, offset);
+ }
+
+ /**
+ * Returns a copy of this date-time with a different time-zone,
+ * retaining the instant.
+ *
+ * This method changes the time-zone and retains the instant.
+ * This normally results in a change to the local date-time.
+ *
+ * This method is based on retaining the same instant, thus gaps and overlaps
+ * in the local time-line have no effect on the result.
+ *
+ * To change the offset while keeping the local time,
+ * use {@link #withZoneSameLocal(ZoneId)}.
+ *
+ * @param zone the time-zone to change to, not null
+ * @return a {@code ZonedDateTime} based on this date-time with the requested zone, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ @Override
+ public ZonedDateTime withZoneSameInstant(ZoneId zone) {
+ Objects.requireNonNull(zone, "zone");
+ return this.zone.equals(zone) ? this :
+ create(dateTime.toEpochSecond(offset), dateTime.getNano(), zone);
+ }
+
+ /**
+ * Returns a copy of this date-time with the zone ID set to the offset.
+ *
+ * This returns a zoned date-time where the zone ID is the same as {@link #getOffset()}.
+ * The local date-time, offset and instant of the result will be the same as in this date-time.
+ *
+ * Setting the date-time to a fixed single offset means that any future
+ * calculations, such as addition or subtraction, have no complex edge cases
+ * due to time-zone rules.
+ * This might also be useful when sending a zoned date-time across a network,
+ * as most protocols, such as ISO-8601, only handle offsets,
+ * and not region-based zone IDs.
+ *
+ * This is equivalent to {@code ZonedDateTime.of(zdt.getDateTime(), zdt.getOffset())}.
+ *
+ * @return a {@code ZonedDateTime} with the zone ID set to the offset, not null
+ */
+ public ZonedDateTime withFixedOffsetZone() {
+ return this.zone.equals(offset) ? this : new ZonedDateTime(dateTime, offset, offset);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the {@code LocalDateTime} part of this date-time.
+ *
+ * This returns a {@code LocalDateTime} with the same year, month, day and time
+ * as this date-time.
+ *
+ * @return the local date-time part of this date-time, not null
+ */
+ @Override // override for return type
+ public LocalDateTime getDateTime() {
+ return dateTime;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the {@code LocalDate} part of this date-time.
+ *
+ * This returns a {@code LocalDate} with the same year, month and day
+ * as this date-time.
+ *
+ * @return the date part of this date-time, not null
+ */
+ @Override // override for return type
+ public LocalDate getDate() {
+ return dateTime.getDate();
+ }
+
+ /**
+ * Gets the year field.
+ *
+ * This method returns the primitive {@code int} value for the year.
+ *
+ * The year returned by this method is proleptic as per {@code get(YEAR)}.
+ * To obtain the year-of-era, use {@code get(YEAR_OF_ERA}.
+ *
+ * @return the year, from MIN_YEAR to MAX_YEAR
+ */
+ public int getYear() {
+ return dateTime.getYear();
+ }
+
+ /**
+ * Gets the month-of-year field from 1 to 12.
+ *
+ * This method returns the month as an {@code int} from 1 to 12.
+ * Application code is frequently clearer if the enum {@link Month}
+ * is used by calling {@link #getMonth()}.
+ *
+ * @return the month-of-year, from 1 to 12
+ * @see #getMonth()
+ */
+ public int getMonthValue() {
+ return dateTime.getMonthValue();
+ }
+
+ /**
+ * Gets the month-of-year field using the {@code Month} enum.
+ *
+ * This method returns the enum {@link Month} for the month.
+ * This avoids confusion as to what {@code int} values mean.
+ * If you need access to the primitive {@code int} value then the enum
+ * provides the {@link Month#getValue() int value}.
+ *
+ * @return the month-of-year, not null
+ * @see #getMonthValue()
+ */
+ public Month getMonth() {
+ return dateTime.getMonth();
+ }
+
+ /**
+ * Gets the day-of-month field.
+ *
+ * This method returns the primitive {@code int} value for the day-of-month.
+ *
+ * @return the day-of-month, from 1 to 31
+ */
+ public int getDayOfMonth() {
+ return dateTime.getDayOfMonth();
+ }
+
+ /**
+ * Gets the day-of-year field.
+ *
+ * This method returns the primitive {@code int} value for the day-of-year.
+ *
+ * @return the day-of-year, from 1 to 365, or 366 in a leap year
+ */
+ public int getDayOfYear() {
+ return dateTime.getDayOfYear();
+ }
+
+ /**
+ * Gets the day-of-week field, which is an enum {@code DayOfWeek}.
+ *
+ * This method returns the enum {@link DayOfWeek} for the day-of-week.
+ * This avoids confusion as to what {@code int} values mean.
+ * If you need access to the primitive {@code int} value then the enum
+ * provides the {@link DayOfWeek#getValue() int value}.
+ *
+ * Additional information can be obtained from the {@code DayOfWeek}.
+ * This includes textual names of the values.
+ *
+ * @return the day-of-week, not null
+ */
+ public DayOfWeek getDayOfWeek() {
+ return dateTime.getDayOfWeek();
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the {@code LocalTime} part of this date-time.
+ *
+ * This returns a {@code LocalTime} with the same hour, minute, second and
+ * nanosecond as this date-time.
+ *
+ * @return the time part of this date-time, not null
+ */
+ @Override // override for Javadoc and performance
+ public LocalTime getTime() {
+ return dateTime.getTime();
+ }
+
+ /**
+ * Gets the hour-of-day field.
+ *
+ * @return the hour-of-day, from 0 to 23
+ */
+ public int getHour() {
+ return dateTime.getHour();
+ }
+
+ /**
+ * Gets the minute-of-hour field.
+ *
+ * @return the minute-of-hour, from 0 to 59
+ */
+ public int getMinute() {
+ return dateTime.getMinute();
+ }
+
+ /**
+ * Gets the second-of-minute field.
+ *
+ * @return the second-of-minute, from 0 to 59
+ */
+ public int getSecond() {
+ return dateTime.getSecond();
+ }
+
+ /**
+ * Gets the nano-of-second field.
+ *
+ * @return the nano-of-second, from 0 to 999,999,999
+ */
+ public int getNano() {
+ return dateTime.getNano();
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns an adjusted copy of this date-time.
+ *
+ * This returns a new {@code ZonedDateTime}, based on this one, with the date-time adjusted.
+ * The adjustment takes place using the specified adjuster strategy object.
+ * Read the documentation of the adjuster to understand what adjustment will be made.
+ *
+ * A simple adjuster might simply set the one of the fields, such as the year field.
+ * A more complex adjuster might set the date to the last day of the month.
+ * A selection of common adjustments is provided in {@link java.time.temporal.Adjusters}.
+ * These include finding the "last day of the month" and "next Wednesday".
+ * Key date-time classes also implement the {@code TemporalAdjuster} interface,
+ * such as {@link Month} and {@link java.time.temporal.MonthDay MonthDay}.
+ * The adjuster is responsible for handling special cases, such as the varying
+ * lengths of month and leap years.
+ *
+ * For example this code returns a date on the last day of July:
+ *
+ * The classes {@link LocalDate} and {@link LocalTime} implement {@code TemporalAdjuster},
+ * thus this method can be used to change the date, time or offset:
+ *
+ * {@link ZoneOffset} also implements {@code TemporalAdjuster} however it is less likely
+ * that setting the offset will have the effect you expect. When an offset is passed in,
+ * the local date-time is combined with the new offset to form an {@code Instant}.
+ * The instant and original zone are then used to create the result.
+ * This algorithm means that it is quite likely that the output has a different offset
+ * to the specified offset. It will however work correctly when passing in the offset
+ * applicable for the instant of the zoned date-time, and will work correctly if passing
+ * one of the two valid offsets during a daylight savings overlap when the same local time
+ * occurs twice.
+ *
+ * The result of this method is obtained by invoking the
+ * {@link TemporalAdjuster#adjustInto(Temporal)} method on the
+ * specified adjuster passing {@code this} as the argument.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param adjuster the adjuster to use, not null
+ * @return a {@code ZonedDateTime} based on {@code this} with the adjustment made, not null
+ * @throws DateTimeException if the adjustment cannot be made
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public ZonedDateTime with(TemporalAdjuster adjuster) {
+ // optimizations
+ if (adjuster instanceof LocalDate) {
+ return resolveLocal(LocalDateTime.of((LocalDate) adjuster, dateTime.getTime()));
+ } else if (adjuster instanceof LocalTime) {
+ return resolveLocal(LocalDateTime.of(dateTime.getDate(), (LocalTime) adjuster));
+ } else if (adjuster instanceof LocalDateTime) {
+ return resolveLocal((LocalDateTime) adjuster);
+ } else if (adjuster instanceof Instant) {
+ Instant instant = (Instant) adjuster;
+ return create(instant.getEpochSecond(), instant.getNano(), zone);
+ } else if (adjuster instanceof ZoneOffset) {
+ return resolveOffset((ZoneOffset) adjuster);
+ }
+ return (ZonedDateTime) adjuster.adjustInto(this);
+ }
+
+ /**
+ * Returns a copy of this date-time with the specified field set to a new value.
+ *
+ * This returns a new {@code ZonedDateTime}, based on this one, with the value
+ * for the specified field changed.
+ * This can be used to change any supported field, such as the year, month or day-of-month.
+ * If it is not possible to set the value, because the field is not supported or for
+ * some other reason, an exception is thrown.
+ *
+ * In some cases, changing the specified field can cause the resulting date-time to become invalid,
+ * such as changing the month from 31st January to February would make the day-of-month invalid.
+ * In cases like this, the field is responsible for resolving the date. Typically it will choose
+ * the previous valid date, which would be the last valid day of February in this example.
+ *
+ * If the field is a {@link ChronoField} then the adjustment is implemented here.
+ *
+ * The {@code INSTANT_SECONDS} field will return a date-time with the specified instant.
+ * The zone and nano-of-second are unchanged.
+ * The result will have an offset derived from the new instant and original zone.
+ * If the new instant value is outside the valid range then a {@code DateTimeException} will be thrown.
+ *
+ * The {@code OFFSET_SECONDS} field will return a date-time calculated using the specified offset.
+ * The local date-time is combined with the new offset to form an {@code Instant}.
+ * The instant and original zone are then used to create the result.
+ * This algorithm means that it is quite likely that the output has a different offset
+ * to the specified offset. It will however work correctly when passing in the offset
+ * applicable for the instant of the zoned date-time, and will work correctly if passing
+ * one of the two valid offsets during a daylight savings overlap when the same local time
+ * occurs twice. If the new offset value is outside the valid range then a
+ * {@code DateTimeException} will be thrown.
+ *
+ * The other {@link #isSupported(TemporalField) supported fields} will behave as per
+ * the matching method on {@link LocalDateTime#with(TemporalField, long) LocalDateTime}.
+ * The zone is not part of the calculation and will be unchanged.
+ * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+ * then the offset will be retained if possible, otherwise the earlier offset will be used.
+ * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+ *
+ * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
+ *
+ * If the field is not a {@code ChronoField}, then the result of this method
+ * is obtained by invoking {@code TemporalField.doWith(Temporal, long)}
+ * passing {@code this} as the argument. In this case, the field determines
+ * whether and how to adjust the instant.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param field the field to set in the result, not null
+ * @param newValue the new value of the field in the result
+ * @return a {@code ZonedDateTime} based on {@code this} with the specified field set, not null
+ * @throws DateTimeException if the field cannot be set
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public ZonedDateTime with(TemporalField field, long newValue) {
+ if (field instanceof ChronoField) {
+ ChronoField f = (ChronoField) field;
+ switch (f) {
+ case INSTANT_SECONDS: return create(newValue, getNano(), zone);
+ case OFFSET_SECONDS: {
+ ZoneOffset offset = ZoneOffset.ofTotalSeconds(f.checkValidIntValue(newValue));
+ return resolveOffset(offset);
+ }
+ }
+ return resolveLocal(dateTime.with(field, newValue));
+ }
+ return field.doWith(this, newValue);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this {@code ZonedDateTime} with the year value altered.
+ *
+ * This operates on the local time-line,
+ * {@link LocalDateTime#withYear(int) changing the year} of the local date-time.
+ * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+ * to obtain the offset.
+ *
+ * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+ * then the offset will be retained if possible, otherwise the earlier offset will be used.
+ * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param year the year to set in the result, from MIN_YEAR to MAX_YEAR
+ * @return a {@code ZonedDateTime} based on this date-time with the requested year, not null
+ * @throws DateTimeException if the year value is invalid
+ */
+ public ZonedDateTime withYear(int year) {
+ return resolveLocal(dateTime.withYear(year));
+ }
+
+ /**
+ * Returns a copy of this {@code ZonedDateTime} with the month-of-year value altered.
+ *
+ * This operates on the local time-line,
+ * {@link LocalDateTime#withMonth(int) changing the month} of the local date-time.
+ * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+ * to obtain the offset.
+ *
+ * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+ * then the offset will be retained if possible, otherwise the earlier offset will be used.
+ * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param month the month-of-year to set in the result, from 1 (January) to 12 (December)
+ * @return a {@code ZonedDateTime} based on this date-time with the requested month, not null
+ * @throws DateTimeException if the month-of-year value is invalid
+ */
+ public ZonedDateTime withMonth(int month) {
+ return resolveLocal(dateTime.withMonth(month));
+ }
+
+ /**
+ * Returns a copy of this {@code ZonedDateTime} with the day-of-month value altered.
+ *
+ * This operates on the local time-line,
+ * {@link LocalDateTime#withDayOfMonth(int) changing the day-of-month} of the local date-time.
+ * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+ * to obtain the offset.
+ *
+ * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+ * then the offset will be retained if possible, otherwise the earlier offset will be used.
+ * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param dayOfMonth the day-of-month to set in the result, from 1 to 28-31
+ * @return a {@code ZonedDateTime} based on this date-time with the requested day, not null
+ * @throws DateTimeException if the day-of-month value is invalid
+ * @throws DateTimeException if the day-of-month is invalid for the month-year
+ */
+ public ZonedDateTime withDayOfMonth(int dayOfMonth) {
+ return resolveLocal(dateTime.withDayOfMonth(dayOfMonth));
+ }
+
+ /**
+ * Returns a copy of this {@code ZonedDateTime} with the day-of-year altered.
+ *
+ * This operates on the local time-line,
+ * {@link LocalDateTime#withDayOfYear(int) changing the day-of-year} of the local date-time.
+ * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+ * to obtain the offset.
+ *
+ * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+ * then the offset will be retained if possible, otherwise the earlier offset will be used.
+ * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param dayOfYear the day-of-year to set in the result, from 1 to 365-366
+ * @return a {@code ZonedDateTime} based on this date with the requested day, not null
+ * @throws DateTimeException if the day-of-year value is invalid
+ * @throws DateTimeException if the day-of-year is invalid for the year
+ */
+ public ZonedDateTime withDayOfYear(int dayOfYear) {
+ return resolveLocal(dateTime.withDayOfYear(dayOfYear));
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this {@code ZonedDateTime} with the hour-of-day value altered.
+ *
+ * This operates on the local time-line,
+ * {@linkplain LocalDateTime#withHour(int) changing the time} of the local date-time.
+ * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+ * to obtain the offset.
+ *
+ * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+ * then the offset will be retained if possible, otherwise the earlier offset will be used.
+ * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param hour the hour-of-day to set in the result, from 0 to 23
+ * @return a {@code ZonedDateTime} based on this date-time with the requested hour, not null
+ * @throws DateTimeException if the hour value is invalid
+ */
+ public ZonedDateTime withHour(int hour) {
+ return resolveLocal(dateTime.withHour(hour));
+ }
+
+ /**
+ * Returns a copy of this {@code ZonedDateTime} with the minute-of-hour value altered.
+ *
+ * This operates on the local time-line,
+ * {@linkplain LocalDateTime#withMinute(int) changing the time} of the local date-time.
+ * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+ * to obtain the offset.
+ *
+ * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+ * then the offset will be retained if possible, otherwise the earlier offset will be used.
+ * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param minute the minute-of-hour to set in the result, from 0 to 59
+ * @return a {@code ZonedDateTime} based on this date-time with the requested minute, not null
+ * @throws DateTimeException if the minute value is invalid
+ */
+ public ZonedDateTime withMinute(int minute) {
+ return resolveLocal(dateTime.withMinute(minute));
+ }
+
+ /**
+ * Returns a copy of this {@code ZonedDateTime} with the second-of-minute value altered.
+ *
+ * This operates on the local time-line,
+ * {@linkplain LocalDateTime#withSecond(int) changing the time} of the local date-time.
+ * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+ * to obtain the offset.
+ *
+ * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+ * then the offset will be retained if possible, otherwise the earlier offset will be used.
+ * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param second the second-of-minute to set in the result, from 0 to 59
+ * @return a {@code ZonedDateTime} based on this date-time with the requested second, not null
+ * @throws DateTimeException if the second value is invalid
+ */
+ public ZonedDateTime withSecond(int second) {
+ return resolveLocal(dateTime.withSecond(second));
+ }
+
+ /**
+ * Returns a copy of this {@code ZonedDateTime} with the nano-of-second value altered.
+ *
+ * This operates on the local time-line,
+ * {@linkplain LocalDateTime#withNano(int) changing the time} of the local date-time.
+ * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+ * to obtain the offset.
+ *
+ * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+ * then the offset will be retained if possible, otherwise the earlier offset will be used.
+ * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param nanoOfSecond the nano-of-second to set in the result, from 0 to 999,999,999
+ * @return a {@code ZonedDateTime} based on this date-time with the requested nanosecond, not null
+ * @throws DateTimeException if the nano value is invalid
+ */
+ public ZonedDateTime withNano(int nanoOfSecond) {
+ return resolveLocal(dateTime.withNano(nanoOfSecond));
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this {@code ZonedDateTime} with the time truncated.
+ *
+ * Truncation returns a copy of the original date-time with fields
+ * smaller than the specified unit set to zero.
+ * For example, truncating with the {@link ChronoUnit#MINUTES minutes} unit
+ * will set the second-of-minute and nano-of-second field to zero.
+ *
+ * Not all units are accepted. The {@link ChronoUnit#DAYS days} unit and time
+ * units with an exact duration can be used, other units throw an exception.
+ *
+ * This operates on the local time-line,
+ * {@link LocalDateTime#truncatedTo(java.time.temporal.TemporalUnit) truncating}
+ * the underlying local date-time. This is then converted back to a
+ * {@code ZonedDateTime}, using the zone ID to obtain the offset.
+ *
+ * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+ * then the offset will be retained if possible, otherwise the earlier offset will be used.
+ * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param unit the unit to truncate to, not null
+ * @return a {@code ZonedDateTime} based on this date-time with the time truncated, not null
+ * @throws DateTimeException if unable to truncate
+ */
+ public ZonedDateTime truncatedTo(TemporalUnit unit) {
+ return resolveLocal(dateTime.truncatedTo(unit));
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this date-time with the specified period added.
+ *
+ * This method returns a new date-time based on this time with the specified period added.
+ * The adder is typically {@link Period} but may be any other type implementing
+ * the {@link TemporalAdder} interface.
+ * The calculation is delegated to the specified adjuster, which typically calls
+ * back to {@link #plus(long, TemporalUnit)}.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param adder the adder to use, not null
+ * @return a {@code ZonedDateTime} based on this date-time with the addition made, not null
+ * @throws DateTimeException if the addition cannot be made
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public ZonedDateTime plus(TemporalAdder adder) {
+ return (ZonedDateTime) adder.addTo(this);
+ }
+
+ /**
+ * Returns a copy of this date-time with the specified period added.
+ *
+ * This method returns a new date-time based on this date-time with the specified period added.
+ * This can be used to add any period that is defined by a unit, for example to add years, months or days.
+ * The unit is responsible for the details of the calculation, including the resolution
+ * of any edge cases in the calculation.
+ *
+ * The calculation for date and time units differ.
+ *
+ * Date units operate on the local time-line.
+ * The period is first added to the local date-time, then converted back
+ * to a zoned date-time using the zone ID.
+ * The conversion uses {@link #ofLocal(LocalDateTime, ZoneId, ZoneOffset)}
+ * with the offset before the addition.
+ *
+ * Time units operate on the instant time-line.
+ * The period is first added to the local date-time, then converted back to
+ * a zoned date-time using the zone ID.
+ * The conversion uses {@link #ofInstant(LocalDateTime, ZoneOffset, ZoneId)}
+ * with the offset before the addition.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param amountToAdd the amount of the unit to add to the result, may be negative
+ * @param unit the unit of the period to add, not null
+ * @return a {@code ZonedDateTime} based on this date-time with the specified period added, not null
+ * @throws DateTimeException if the unit cannot be added to this type
+ */
+ @Override
+ public ZonedDateTime plus(long amountToAdd, TemporalUnit unit) {
+ if (unit instanceof ChronoUnit) {
+ ChronoUnit u = (ChronoUnit) unit;
+ if (u.isDateUnit()) {
+ return resolveLocal(dateTime.plus(amountToAdd, unit));
+ } else {
+ return resolveInstant(dateTime.plus(amountToAdd, unit));
+ }
+ }
+ return unit.doPlus(this, amountToAdd);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this {@code ZonedDateTime} with the specified period in years added.
+ *
+ * This operates on the local time-line,
+ * {@link LocalDateTime#plusYears(long) adding years} to the local date-time.
+ * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+ * to obtain the offset.
+ *
+ * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+ * then the offset will be retained if possible, otherwise the earlier offset will be used.
+ * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param years the years to add, may be negative
+ * @return a {@code ZonedDateTime} based on this date-time with the years added, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public ZonedDateTime plusYears(long years) {
+ return resolveLocal(dateTime.plusYears(years));
+ }
+
+ /**
+ * Returns a copy of this {@code ZonedDateTime} with the specified period in months added.
+ *
+ * This operates on the local time-line,
+ * {@link LocalDateTime#plusMonths(long) adding months} to the local date-time.
+ * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+ * to obtain the offset.
+ *
+ * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+ * then the offset will be retained if possible, otherwise the earlier offset will be used.
+ * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param months the months to add, may be negative
+ * @return a {@code ZonedDateTime} based on this date-time with the months added, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public ZonedDateTime plusMonths(long months) {
+ return resolveLocal(dateTime.plusMonths(months));
+ }
+
+ /**
+ * Returns a copy of this {@code ZonedDateTime} with the specified period in weeks added.
+ *
+ * This operates on the local time-line,
+ * {@link LocalDateTime#plusWeeks(long) adding weeks} to the local date-time.
+ * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+ * to obtain the offset.
+ *
+ * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+ * then the offset will be retained if possible, otherwise the earlier offset will be used.
+ * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param weeks the weeks to add, may be negative
+ * @return a {@code ZonedDateTime} based on this date-time with the weeks added, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public ZonedDateTime plusWeeks(long weeks) {
+ return resolveLocal(dateTime.plusWeeks(weeks));
+ }
+
+ /**
+ * Returns a copy of this {@code ZonedDateTime} with the specified period in days added.
+ *
+ * This operates on the local time-line,
+ * {@link LocalDateTime#plusDays(long) adding days} to the local date-time.
+ * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+ * to obtain the offset.
+ *
+ * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+ * then the offset will be retained if possible, otherwise the earlier offset will be used.
+ * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param days the days to add, may be negative
+ * @return a {@code ZonedDateTime} based on this date-time with the days added, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public ZonedDateTime plusDays(long days) {
+ return resolveLocal(dateTime.plusDays(days));
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this {@code ZonedDateTime} with the specified period in hours added.
+ *
+ * This operates on the instant time-line, such that adding one hour will
+ * always be a duration of one hour later.
+ * This may cause the local date-time to change by an amount other than one hour.
+ * Note that this is a different approach to that used by days, months and years,
+ * thus adding one day is not the same as adding 24 hours.
+ *
+ * For example, consider a time-zone where the spring DST cutover means that the
+ * local times 01:00 to 01:59 occur twice changing from offset +02:00 to +01:00.
+ *
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param hours the hours to add, may be negative
+ * @return a {@code ZonedDateTime} based on this date-time with the hours added, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public ZonedDateTime plusHours(long hours) {
+ return resolveInstant(dateTime.plusHours(hours));
+ }
+
+ /**
+ * Returns a copy of this {@code ZonedDateTime} with the specified period in minutes added.
+ *
+ * This operates on the instant time-line, such that adding one minute will
+ * always be a duration of one minute later.
+ * This may cause the local date-time to change by an amount other than one minute.
+ * Note that this is a different approach to that used by days, months and years.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param minutes the minutes to add, may be negative
+ * @return a {@code ZonedDateTime} based on this date-time with the minutes added, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public ZonedDateTime plusMinutes(long minutes) {
+ return resolveInstant(dateTime.plusMinutes(minutes));
+ }
+
+ /**
+ * Returns a copy of this {@code ZonedDateTime} with the specified period in seconds added.
+ *
+ * This operates on the instant time-line, such that adding one second will
+ * always be a duration of one second later.
+ * This may cause the local date-time to change by an amount other than one second.
+ * Note that this is a different approach to that used by days, months and years.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param seconds the seconds to add, may be negative
+ * @return a {@code ZonedDateTime} based on this date-time with the seconds added, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public ZonedDateTime plusSeconds(long seconds) {
+ return resolveInstant(dateTime.plusSeconds(seconds));
+ }
+
+ /**
+ * Returns a copy of this {@code ZonedDateTime} with the specified period in nanoseconds added.
+ *
+ * This operates on the instant time-line, such that adding one nano will
+ * always be a duration of one nano later.
+ * This may cause the local date-time to change by an amount other than one nano.
+ * Note that this is a different approach to that used by days, months and years.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param nanos the nanos to add, may be negative
+ * @return a {@code ZonedDateTime} based on this date-time with the nanoseconds added, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public ZonedDateTime plusNanos(long nanos) {
+ return resolveInstant(dateTime.plusNanos(nanos));
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this date-time with the specified period subtracted.
+ *
+ * This method returns a new date-time based on this time with the specified period subtracted.
+ * The subtractor is typically {@link Period} but may be any other type implementing
+ * the {@link TemporalSubtractor} interface.
+ * The calculation is delegated to the specified adjuster, which typically calls
+ * back to {@link #minus(long, TemporalUnit)}.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param subtractor the subtractor to use, not null
+ * @return a {@code ZonedDateTime} based on this date-time with the subtraction made, not null
+ * @throws DateTimeException if the subtraction cannot be made
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public ZonedDateTime minus(TemporalSubtractor subtractor) {
+ return (ZonedDateTime) subtractor.subtractFrom(this);
+ }
+
+ /**
+ * Returns a copy of this date-time with the specified period subtracted.
+ *
+ * This method returns a new date-time based on this date-time with the specified period subtracted.
+ * This can be used to subtract any period that is defined by a unit, for example to subtract years, months or days.
+ * The unit is responsible for the details of the calculation, including the resolution
+ * of any edge cases in the calculation.
+ *
+ * The calculation for date and time units differ.
+ *
+ * Date units operate on the local time-line.
+ * The period is first subtracted from the local date-time, then converted back
+ * to a zoned date-time using the zone ID.
+ * The conversion uses {@link #ofLocal(LocalDateTime, ZoneId, ZoneOffset)}
+ * with the offset before the subtraction.
+ *
+ * Time units operate on the instant time-line.
+ * The period is first subtracted from the local date-time, then converted back to
+ * a zoned date-time using the zone ID.
+ * The conversion uses {@link #ofInstant(LocalDateTime, ZoneOffset, ZoneId)}
+ * with the offset before the subtraction.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param amountToSubtract the amount of the unit to subtract from the result, may be negative
+ * @param unit the unit of the period to subtract, not null
+ * @return a {@code ZonedDateTime} based on this date-time with the specified period subtracted, not null
+ * @throws DateTimeException if the unit cannot be added to this type
+ */
+ @Override
+ public ZonedDateTime minus(long amountToSubtract, TemporalUnit unit) {
+ return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this {@code ZonedDateTime} with the specified period in years subtracted.
+ *
+ * This operates on the local time-line,
+ * {@link LocalDateTime#minusYears(long) subtracting years} to the local date-time.
+ * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+ * to obtain the offset.
+ *
+ * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+ * then the offset will be retained if possible, otherwise the earlier offset will be used.
+ * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param years the years to subtract, may be negative
+ * @return a {@code ZonedDateTime} based on this date-time with the years subtracted, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public ZonedDateTime minusYears(long years) {
+ return (years == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-years));
+ }
+
+ /**
+ * Returns a copy of this {@code ZonedDateTime} with the specified period in months subtracted.
+ *
+ * This operates on the local time-line,
+ * {@link LocalDateTime#minusMonths(long) subtracting months} to the local date-time.
+ * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+ * to obtain the offset.
+ *
+ * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+ * then the offset will be retained if possible, otherwise the earlier offset will be used.
+ * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param months the months to subtract, may be negative
+ * @return a {@code ZonedDateTime} based on this date-time with the months subtracted, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public ZonedDateTime minusMonths(long months) {
+ return (months == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-months));
+ }
+
+ /**
+ * Returns a copy of this {@code ZonedDateTime} with the specified period in weeks subtracted.
+ *
+ * This operates on the local time-line,
+ * {@link LocalDateTime#minusWeeks(long) subtracting weeks} to the local date-time.
+ * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+ * to obtain the offset.
+ *
+ * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+ * then the offset will be retained if possible, otherwise the earlier offset will be used.
+ * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param weeks the weeks to subtract, may be negative
+ * @return a {@code ZonedDateTime} based on this date-time with the weeks subtracted, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public ZonedDateTime minusWeeks(long weeks) {
+ return (weeks == Long.MIN_VALUE ? plusWeeks(Long.MAX_VALUE).plusWeeks(1) : plusWeeks(-weeks));
+ }
+
+ /**
+ * Returns a copy of this {@code ZonedDateTime} with the specified period in days subtracted.
+ *
+ * This operates on the local time-line,
+ * {@link LocalDateTime#minusDays(long) subtracting days} to the local date-time.
+ * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+ * to obtain the offset.
+ *
+ * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+ * then the offset will be retained if possible, otherwise the earlier offset will be used.
+ * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param days the days to subtract, may be negative
+ * @return a {@code ZonedDateTime} based on this date-time with the days subtracted, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public ZonedDateTime minusDays(long days) {
+ return (days == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-days));
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a copy of this {@code ZonedDateTime} with the specified period in hours subtracted.
+ *
+ * This operates on the instant time-line, such that subtracting one hour will
+ * always be a duration of one hour earlier.
+ * This may cause the local date-time to change by an amount other than one hour.
+ * Note that this is a different approach to that used by days, months and years,
+ * thus subtracting one day is not the same as adding 24 hours.
+ *
+ * For example, consider a time-zone where the spring DST cutover means that the
+ * local times 01:00 to 01:59 occur twice changing from offset +02:00 to +01:00.
+ *
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param hours the hours to subtract, may be negative
+ * @return a {@code ZonedDateTime} based on this date-time with the hours subtracted, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public ZonedDateTime minusHours(long hours) {
+ return (hours == Long.MIN_VALUE ? plusHours(Long.MAX_VALUE).plusHours(1) : plusHours(-hours));
+ }
+
+ /**
+ * Returns a copy of this {@code ZonedDateTime} with the specified period in minutes subtracted.
+ *
+ * This operates on the instant time-line, such that subtracting one minute will
+ * always be a duration of one minute earlier.
+ * This may cause the local date-time to change by an amount other than one minute.
+ * Note that this is a different approach to that used by days, months and years.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param minutes the minutes to subtract, may be negative
+ * @return a {@code ZonedDateTime} based on this date-time with the minutes subtracted, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public ZonedDateTime minusMinutes(long minutes) {
+ return (minutes == Long.MIN_VALUE ? plusMinutes(Long.MAX_VALUE).plusMinutes(1) : plusMinutes(-minutes));
+ }
+
+ /**
+ * Returns a copy of this {@code ZonedDateTime} with the specified period in seconds subtracted.
+ *
+ * This operates on the instant time-line, such that subtracting one second will
+ * always be a duration of one second earlier.
+ * This may cause the local date-time to change by an amount other than one second.
+ * Note that this is a different approach to that used by days, months and years.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param seconds the seconds to subtract, may be negative
+ * @return a {@code ZonedDateTime} based on this date-time with the seconds subtracted, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public ZonedDateTime minusSeconds(long seconds) {
+ return (seconds == Long.MIN_VALUE ? plusSeconds(Long.MAX_VALUE).plusSeconds(1) : plusSeconds(-seconds));
+ }
+
+ /**
+ * Returns a copy of this {@code ZonedDateTime} with the specified period in nanoseconds subtracted.
+ *
+ * This operates on the instant time-line, such that subtracting one nano will
+ * always be a duration of one nano earlier.
+ * This may cause the local date-time to change by an amount other than one nano.
+ * Note that this is a different approach to that used by days, months and years.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param nanos the nanos to subtract, may be negative
+ * @return a {@code ZonedDateTime} based on this date-time with the nanoseconds subtracted, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ public ZonedDateTime minusNanos(long nanos) {
+ return (nanos == Long.MIN_VALUE ? plusNanos(Long.MAX_VALUE).plusNanos(1) : plusNanos(-nanos));
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Queries this date-time using the specified query.
+ *
+ * This queries this date-time using the specified query strategy object.
+ * The {@code TemporalQuery} object defines the logic to be used to
+ * obtain the result. Read the documentation of the query to understand
+ * what the result of this method will be.
+ *
+ * The result of this method is obtained by invoking the
+ * {@link java.time.temporal.TemporalQuery#queryFrom(TemporalAccessor)} method on the
+ * specified query passing {@code this} as the argument.
+ *
+ * @param
+ * This calculates the period between two date-times in terms of a single unit.
+ * The start and end points are {@code this} and the specified date-time.
+ * The result will be negative if the end is before the start.
+ * For example, the period in days between two date-times can be calculated
+ * using {@code startDateTime.periodUntil(endDateTime, DAYS)}.
+ *
+ * The {@code Temporal} passed to this method must be a {@code ZonedDateTime}.
+ * If the time-zone differs between the two zoned date-times, the specified
+ * end date-time is normalized to have the same zone as this date-time.
+ *
+ * The calculation returns a whole number, representing the number of
+ * complete units between the two date-times.
+ * For example, the period in months between 2012-06-15T00:00Z and 2012-08-14T23:59Z
+ * will only be one month as it is one minute short of two months.
+ *
+ * This method operates in association with {@link TemporalUnit#between}.
+ * The result of this method is a {@code long} representing the amount of
+ * the specified unit. By contrast, the result of {@code between} is an
+ * object that can be used directly in addition/subtraction:
+ *
+ * The calculation is implemented in this method for {@link ChronoUnit}.
+ * The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS},
+ * {@code MINUTES}, {@code HOURS} and {@code HALF_DAYS}, {@code DAYS},
+ * {@code WEEKS}, {@code MONTHS}, {@code YEARS}, {@code DECADES},
+ * {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS} are supported.
+ * Other {@code ChronoUnit} values will throw an exception.
+ *
+ * The calculation for date and time units differ.
+ *
+ * Date units operate on the local time-line, using the local date-time.
+ * For example, the period from noon on day 1 to noon the following day
+ * in days will always be counted as exactly one day, irrespective of whether
+ * there was a daylight savings change or not.
+ *
+ * Time units operate on the instant time-line.
+ * The calculation effectively converts both zoned date-times to instants
+ * and then calculates the period between the instants.
+ * For example, the period from noon on day 1 to noon the following day
+ * in hours may be 23, 24 or 25 hours (or some other amount) depending on
+ * whether there was a daylight savings change or not.
+ *
+ * If the unit is not a {@code ChronoUnit}, then the result of this method
+ * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
+ * passing {@code this} as the first argument and the input temporal as
+ * the second argument.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param endDateTime the end date-time, which must be a {@code ZonedDateTime}, not null
+ * @param unit the unit to measure the period in, not null
+ * @return the amount of the period between this date-time and the end date-time
+ * @throws DateTimeException if the period cannot be calculated
+ * @throws ArithmeticException if numeric overflow occurs
+ */
+ @Override
+ public long periodUntil(Temporal endDateTime, TemporalUnit unit) {
+ if (endDateTime instanceof ZonedDateTime == false) {
+ Objects.requireNonNull(endDateTime, "endDateTime");
+ throw new DateTimeException("Unable to calculate period between objects of two different types");
+ }
+ if (unit instanceof ChronoUnit) {
+ ZonedDateTime end = (ZonedDateTime) endDateTime;
+ end = end.withZoneSameInstant(zone);
+ ChronoUnit u = (ChronoUnit) unit;
+ if (u.isDateUnit()) {
+ return dateTime.periodUntil(end.dateTime, unit);
+ } else {
+ return toOffsetDateTime().periodUntil(end.toOffsetDateTime(), unit);
+ }
+ }
+ return unit.between(this, endDateTime).getAmount();
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Converts this date-time to an {@code OffsetDateTime}.
+ *
+ * This creates an offset date-time using the local date-time and offset.
+ * The zone ID is ignored.
+ *
+ * @return an offset date-time representing the same local date-time and offset, not null
+ */
+ public OffsetDateTime toOffsetDateTime() {
+ return OffsetDateTime.of(dateTime, offset);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks if this date-time is equal to another date-time.
+ *
+ * The comparison is based on the offset date-time and the zone.
+ * Only objects of type {@code ZonedDateTime} are compared, other types return false.
+ *
+ * @param obj the object to check, null returns false
+ * @return true if this is equal to the other date-time
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof ZonedDateTime) {
+ ZonedDateTime other = (ZonedDateTime) obj;
+ return dateTime.equals(other.dateTime) &&
+ offset.equals(other.offset) &&
+ zone.equals(other.zone);
+ }
+ return false;
+ }
+
+ /**
+ * A hash code for this date-time.
+ *
+ * @return a suitable hash code
+ */
+ @Override
+ public int hashCode() {
+ return dateTime.hashCode() ^ offset.hashCode() ^ Integer.rotateLeft(zone.hashCode(), 3);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Outputs this date-time as a {@code String}, such as
+ * {@code 2007-12-03T10:15:30+01:00[Europe/Paris]}.
+ *
+ * The format consists of the {@code LocalDateTime} followed by the {@code ZoneOffset}.
+ * If the {@code ZoneId} is not the same as the offset, then the ID is output.
+ * The output is compatible with ISO-8601 if the offset and ID are the same.
+ *
+ * @return a string representation of this date-time, not null
+ */
+ @Override // override for Javadoc
+ public String toString() {
+ String str = dateTime.toString() + offset.toString();
+ if (offset != zone) {
+ str += '[' + zone.toString() + ']';
+ }
+ return str;
+ }
+
+ /**
+ * Outputs this date-time as a {@code String} using the formatter.
+ *
+ * This date will be passed to the formatter
+ * {@link DateTimeFormatter#print(TemporalAccessor) print method}.
+ *
+ * @param formatter the formatter to use, not null
+ * @return the formatted date-time string, not null
+ * @throws DateTimeException if an error occurs during printing
+ */
+ @Override // override for Javadoc
+ public String toString(DateTimeFormatter formatter) {
+ return ChronoZonedDateTime.super.toString(formatter);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Writes the object using a
+ * dedicated serialized form.
+ *
+ * This class is used by applications seeking to handle dates in non-ISO calendar systems.
+ * For example, the Japanese, Minguo, Thai Buddhist and others.
+ *
+ * {@code ChronoLocalDate} is built on the generic concepts of year, month and day.
+ * The calendar system, represented by a {@link java.time.temporal.Chrono}, expresses the relationship between
+ * the fields and this class allows the resulting date to be manipulated.
+ *
+ * Note that not all calendar systems are suitable for use with this class.
+ * For example, the Mayan calendar uses a system that bears no relation to years, months and days.
+ *
+ * The API design encourages the use of {@code LocalDate} for the majority of the application.
+ * This includes code to read and write from a persistent data store, such as a database,
+ * and to send dates and times across a network. The {@code ChronoLocalDate} instance is then used
+ * at the user interface level to deal with localized input/output.
+ *
+ * Example: The set of calendars is extensible by defining a subclass of {@link ChronoLocalDate}
+ * to represent a date instance and an implementation of {@code Chrono}
+ * to be the factory for the ChronoLocalDate subclass.
+ * To permit the discovery of the additional calendar types the implementation of
+ * {@code Chrono} must be registered as a Service implementing the {@code Chrono} interface
+ * in the {@code META-INF/Services} file as per the specification of {@link java.util.ServiceLoader}.
+ * The subclass must function according to the {@code Chrono} class description and must provide its
+ * {@link java.time.temporal.Chrono#getId() chronlogy ID} and {@link Chrono#getCalendarType() calendar type}.
+ * This adds the specified period in years to the date.
+ * In some cases, adding years can cause the resulting date to become invalid.
+ * If this occurs, then other fields, typically the day-of-month, will be adjusted to ensure
+ * that the result is valid. Typically this will select the last valid day of the month.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param yearsToAdd the years to add, may be negative
+ * @return a date based on this one with the years added, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ abstract ChronoDateImpl
+ * This adds the specified period in months to the date.
+ * In some cases, adding months can cause the resulting date to become invalid.
+ * If this occurs, then other fields, typically the day-of-month, will be adjusted to ensure
+ * that the result is valid. Typically this will select the last valid day of the month.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param monthsToAdd the months to add, may be negative
+ * @return a date based on this one with the months added, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ abstract ChronoDateImpl
+ * This adds the specified period in weeks to the date.
+ * In some cases, adding weeks can cause the resulting date to become invalid.
+ * If this occurs, then other fields will be adjusted to ensure that the result is valid.
+ *
+ * The default implementation uses {@link #plusDays(long)} using a 7 day week.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param weeksToAdd the weeks to add, may be negative
+ * @return a date based on this one with the weeks added, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ ChronoDateImpl
+ * This adds the specified period in days to the date.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param daysToAdd the days to add, may be negative
+ * @return a date based on this one with the days added, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ abstract ChronoDateImpl
+ * This subtracts the specified period in years to the date.
+ * In some cases, subtracting years can cause the resulting date to become invalid.
+ * If this occurs, then other fields, typically the day-of-month, will be adjusted to ensure
+ * that the result is valid. Typically this will select the last valid day of the month.
+ *
+ * The default implementation uses {@link #plusYears(long)}.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param yearsToSubtract the years to subtract, may be negative
+ * @return a date based on this one with the years subtracted, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ ChronoDateImpl
+ * This subtracts the specified period in months to the date.
+ * In some cases, subtracting months can cause the resulting date to become invalid.
+ * If this occurs, then other fields, typically the day-of-month, will be adjusted to ensure
+ * that the result is valid. Typically this will select the last valid day of the month.
+ *
+ * The default implementation uses {@link #plusMonths(long)}.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param monthsToSubtract the months to subtract, may be negative
+ * @return a date based on this one with the months subtracted, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ ChronoDateImpl
+ * This subtracts the specified period in weeks to the date.
+ * In some cases, subtracting weeks can cause the resulting date to become invalid.
+ * If this occurs, then other fields will be adjusted to ensure that the result is valid.
+ *
+ * The default implementation uses {@link #plusWeeks(long)}.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param weeksToSubtract the weeks to subtract, may be negative
+ * @return a date based on this one with the weeks subtracted, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ ChronoDateImpl
+ * This subtracts the specified period in days to the date.
+ *
+ * The default implementation uses {@link #plusDays(long)}.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param daysToSubtract the days to subtract, may be negative
+ * @return a date based on this one with the days subtracted, not null
+ * @throws DateTimeException if the result exceeds the supported date range
+ */
+ ChronoDateImpl
+ * This chronology defines the rules of the Hijrah calendar system.
+ *
+ * The implementation follows the Freeman-Grenville algorithm (*1) and has following features.
+ *
+ *
+ * The table shows the features described above.
+ *
+ * (*1) The algorithm is taken from the book,
+ * The Muslim and Christian Calendars by G.S.P. Freeman-Grenville.
+ *
+ *
+ *
+ * The ID uniquely identifies the {@code Chrono}.
+ * It can be used to lookup the {@code Chrono} using {@link #of(String)}.
+ *
+ * @return the chronology ID - 'Hijrah'
+ * @see #getCalendarType()
+ */
+ @Override
+ public String getId() {
+ return typeId;
+ }
+
+ /**
+ * Gets the calendar type of the underlying calendar system - 'islamicc'.
+ *
+ * The calendar type is an identifier defined by the
+ * Unicode Locale Data Markup Language (LDML) specification.
+ * It can be used to lookup the {@code Chrono} using {@link #of(String)}.
+ * It can also be used as part of a locale, accessible via
+ * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
+ *
+ * @return the calendar system type - 'islamicc'
+ * @see #getId()
+ */
+ @Override
+ public String getCalendarType() {
+ return calendarType;
+ }
+
+ //-----------------------------------------------------------------------
+ @Override
+ public ChronoLocalDate
+ * This implements {@code ChronoLocalDate} for the {@link HijrahChrono Hijrah calendar}.
+ *
+ * The Hijrah calendar has a different total of days in a year than
+ * Gregorian calendar, and a month is based on the period of a complete
+ * revolution of the moon around the earth (as between successive new moons).
+ * The calendar cycles becomes longer and unstable, and sometimes a manual
+ * adjustment (for entering deviation) is necessary for correctness
+ * because of the complex algorithm.
+ *
+ * HijrahDate supports the manual adjustment feature by providing a configuration
+ * file. The configuration file contains the adjustment (deviation) data with following format.
+ *
+ * For each Hijrah calendar a deviation file is used
+ * to modify the initial Hijrah calendar by changing the length of
+ * individual months.
+ *
+ * The default location of the deviation files is
+ * {@code
+ * The deviation file for a calendar can be overridden by defining the
+ * property {@code java.time.calendar.HijrahChrono.File.hijrah_
+ * The deviation file is read line by line:
+ * Example:
+ * The Hijrah calendar system has two eras.
+ * The date {@code 0001-01-01 (Hijrah)} is {@code 622-06-19 (ISO)}.
+ *
+ * Do not use {@code ordinal()} to obtain the numeric representation of {@code HijrahEra}.
+ * Use {@code getValue()} instead.
+ *
+ *
+ * The current era (from ISO date 622-06-19 onwards) has the value 1
+ * The previous era has the value 0.
+ *
+ * @param hijrahEra the era to represent, from 0 to 1
+ * @return the HijrahEra singleton, never null
+ * @throws DateTimeException if the era is invalid
+ */
+ public static HijrahEra of(int hijrahEra) {
+ switch (hijrahEra) {
+ case 0:
+ return BEFORE_AH;
+ case 1:
+ return AH;
+ default:
+ throw new DateTimeException("HijrahEra not valid");
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the era numeric value.
+ *
+ * The current era (from ISO date 622-06-19 onwards) has the value 1.
+ * The previous era has the value 0.
+ *
+ * @return the era value, from 0 (BEFORE_AH) to 1 (AH)
+ */
+ @Override
+ public int getValue() {
+ return ordinal();
+ }
+
+ @Override
+ public HijrahChrono getChrono() {
+ return HijrahChrono.INSTANCE;
+ }
+
+ // JDK8 default methods:
+ //-----------------------------------------------------------------------
+ @Override
+ public ChronoLocalDate
+ * This chronology defines the rules of the Japanese Imperial calendar system.
+ * This calendar system is primarily used in Japan.
+ * The Japanese Imperial calendar system is the same as the ISO calendar system
+ * apart from the era-based year numbering.
+ *
+ * Only Meiji (1865-04-07 - 1868-09-07) and later eras are supported.
+ * Older eras are handled as an unknown era where the year-of-era is the ISO year.
+ *
+ *
+ * The ID uniquely identifies the {@code Chrono}.
+ * It can be used to lookup the {@code Chrono} using {@link #of(String)}.
+ *
+ * @return the chronology ID - 'Japanese'
+ * @see #getCalendarType()
+ */
+ @Override
+ public String getId() {
+ return "Japanese";
+ }
+
+ /**
+ * Gets the calendar type of the underlying calendar system - 'japanese'.
+ *
+ * The calendar type is an identifier defined by the
+ * Unicode Locale Data Markup Language (LDML) specification.
+ * It can be used to lookup the {@code Chrono} using {@link #of(String)}.
+ * It can also be used as part of a locale, accessible via
+ * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
+ *
+ * @return the calendar system type - 'japanese'
+ * @see #getId()
+ */
+ @Override
+ public String getCalendarType() {
+ return "japanese";
+ }
+
+ //-----------------------------------------------------------------------
+ @Override
+ public ChronoLocalDate
+ * Japanese calendar leap years occur exactly in line with ISO leap years.
+ * This method does not validate the year passed in, and only has a
+ * well-defined result for years in the supported range.
+ *
+ * @param prolepticYear the proleptic-year to check, not validated for range
+ * @return true if the year is a leap year
+ */
+ @Override
+ public boolean isLeapYear(long prolepticYear) {
+ return ISOChrono.INSTANCE.isLeapYear(prolepticYear);
+ }
+
+ @Override
+ public int prolepticYear(Era
+ * This implements {@code ChronoLocalDate} for the
+ * {@linkplain JapaneseChrono Japanese Imperial calendar}.
+ *
+ *
+ * This method changes the year of the date.
+ * If the month-day is invalid for the year, then the previous valid day
+ * will be selected instead.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param era the era to set in the result, not null
+ * @param yearOfEra the year-of-era to set in the returned date
+ * @return a {@code JapaneseDate} based on this date with the requested year, never null
+ * @throws DateTimeException if {@code year} is invalid
+ */
+ private JapaneseDate withYear(JapaneseEra era, int yearOfEra) {
+ int year = JapaneseChrono.INSTANCE.prolepticYear(era, yearOfEra);
+ return with(isoDate.withYear(year));
+ }
+
+ /**
+ * Returns a copy of this date with the year-of-era altered.
+ *
+ * This method changes the year-of-era of the date.
+ * If the month-day is invalid for the year, then the previous valid day
+ * will be selected instead.
+ *
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param year the year to set in the returned date
+ * @return a {@code JapaneseDate} based on this date with the requested year-of-era, never null
+ * @throws DateTimeException if {@code year} is invalid
+ */
+ private JapaneseDate withYear(int year) {
+ return withYear((JapaneseEra) getEra(), year);
+ }
+
+ //-----------------------------------------------------------------------
+ @Override
+ JapaneseDate plusYears(long years) {
+ return with(isoDate.plusYears(years));
+ }
+
+ @Override
+ JapaneseDate plusMonths(long months) {
+ return with(isoDate.plusMonths(months));
+ }
+
+ @Override
+ JapaneseDate plusDays(long days) {
+ return with(isoDate.plusDays(days));
+ }
+
+ private JapaneseDate with(LocalDate newDate) {
+ return (newDate.equals(isoDate) ? this : new JapaneseDate(newDate));
+ }
+
+ @Override // override for performance
+ public long toEpochDay() {
+ return isoDate.toEpochDay();
+ }
+
+ //-------------------------------------------------------------------------
+ @Override // override for performance
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof JapaneseDate) {
+ JapaneseDate otherDate = (JapaneseDate) obj;
+ return this.isoDate.equals(otherDate.isoDate);
+ }
+ return false;
+ }
+
+ @Override // override for performance
+ public int hashCode() {
+ return getChrono().getId().hashCode() ^ isoDate.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ if (era == JapaneseEra.SEIREKI) {
+ return getChrono().getId() + " " + isoDate.toString();
+ }
+ return super.toString();
+ }
+
+ //-----------------------------------------------------------------------
+ private Object writeReplace() {
+ return new Ser(Ser.JAPANESE_DATE_TYPE, this);
+ }
+
+ void writeExternal(DataOutput out) throws IOException {
+ // JapaneseChrono is implicit in the JAPANESE_DATE_TYPE
+ out.writeInt(get(YEAR));
+ out.writeByte(get(MONTH_OF_YEAR));
+ out.writeByte(get(DAY_OF_MONTH));
+ }
+
+ static ChronoLocalDate
+ * This class defines the valid eras for the Japanese chronology.
+ * Only Meiji (1868-09-08 - 1912-07-29) and later eras are supported.
+ * Japan introduced the Gregorian calendar since Meiji 6. The dates
+ * between Meiji 1 - 5 are not historically correct.
+ * The older eras are recognized as Seireki (Western calendar) era,
+ * and the year of era of Seireki is proleptic Gregorian year.
+ * (The Julian to Gregorian transition is not supported.)
+ *
+ *
+ * The {@link #SHOWA} era that contains 1970-01-01 (ISO calendar system) has the value 1
+ * Later era is numbered 2 ({@link #HEISEI}). Earlier eras are numbered 0 ({@link #TAISHO}),
+ * -1 ({@link #MEIJI}), only Meiji and later eras are supported. The prior to Meiji,
+ * {@link #SEIREKI} is used.
+ *
+ * @param japaneseEra the era to represent
+ * @return the {@code JapaneseEra} singleton, never null
+ * @throws DateTimeException if {@code japaneseEra} is invalid
+ */
+ public static JapaneseEra of(int japaneseEra) {
+ if (japaneseEra != SEIREKI.eraValue &&
+ (japaneseEra < MEIJI.eraValue || japaneseEra > HEISEI.eraValue)) {
+ throw new DateTimeException("japaneseEra is invalid");
+ }
+ return KNOWN_ERAS[ordinal(japaneseEra)];
+ }
+
+ /**
+ * Returns an array of JapaneseEras.
+ * @return an array of JapaneseEras
+ */
+ static JapaneseEra[] values() {
+ return Arrays.copyOf(KNOWN_ERAS, KNOWN_ERAS.length);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code JapaneseEra} from a date.
+ *
+ * @param date the date, not null
+ * @return the Era singleton, never null
+ */
+ static JapaneseEra from(LocalDate date) {
+ for (int i = KNOWN_ERAS.length - 1; i > 0; i--) {
+ JapaneseEra era = KNOWN_ERAS[i];
+ if (date.compareTo(era.since) >= 0) {
+ return era;
+ }
+ }
+ return SEIREKI;
+ }
+
+ static JapaneseEra toJapaneseEra(sun.util.calendar.Era privateEra) {
+ for (int i = ERA_CONFIG.length - 1; i > 0; i--) {
+ if (ERA_CONFIG[i].equals(privateEra)) {
+ return KNOWN_ERAS[i];
+ }
+ }
+ return SEIREKI;
+ }
+
+ static sun.util.calendar.Era privateEraFrom(LocalDate isoDate) {
+ for (int i = KNOWN_ERAS.length - 1; i > 0; i--) {
+ JapaneseEra era = KNOWN_ERAS[i];
+ if (isoDate.compareTo(era.since) >= 0) {
+ return ERA_CONFIG[i];
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the index into the arrays from the Era value.
+ * the eraValue is a valid Era number, -999, -1..2.
+ * @param eravalue the era value to convert to the index
+ * @return the index of the current Era
+ */
+ private static int ordinal(int eravalue) {
+ return (eravalue == SEIREKI.eraValue) ? 0 : eravalue + ERA_OFFSET;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns the numeric value of this {@code JapaneseEra}.
+ *
+ * The {@link #SHOWA} era that contains 1970-01-01 (ISO calendar system) has the value 1.
+ * Later eras are numbered from 2 ({@link #HEISEI}).
+ * Earlier eras are numbered 0 ({@link #TAISHO}), -1 ({@link #MEIJI}), and -999 ({@link #SEIREKI}).
+ *
+ * @return the era value
+ */
+ @Override
+ public int getValue() {
+ return eraValue;
+ }
+
+ @Override
+ public JapaneseChrono getChrono() {
+ return JapaneseChrono.INSTANCE;
+ }
+
+ //-----------------------------------------------------------------------
+ String getAbbreviation() {
+ int index = ordinal(getValue());
+ if (index == 0) {
+ return "";
+ }
+ return ERA_CONFIG[index].getAbbreviation();
+ }
+
+ String getName() {
+ int index = ordinal(getValue());
+ if (index == 0) {
+ return "Seireki";
+ }
+ return ERA_CONFIG[index].getName();
+ }
+
+ @Override
+ public String toString() {
+ return getName();
+ }
+
+ //-----------------------------------------------------------------------
+ private Object writeReplace() {
+ return new Ser(Ser.JAPANESE_ERA_TYPE, this);
+ }
+
+ void writeExternal(DataOutput out) throws IOException {
+ out.writeByte(this.getValue());
+ }
+
+ static JapaneseEra readExternal(DataInput in) throws IOException {
+ byte eraValue = in.readByte();
+ return JapaneseEra.of(eraValue);
+ }
+
+}
diff --git a/src/share/classes/java/time/calendar/MinguoChrono.java b/src/share/classes/java/time/calendar/MinguoChrono.java
new file mode 100644
index 0000000000000000000000000000000000000000..70fa85a6d43c2b110c994fd623e8cadd459ddc33
--- /dev/null
+++ b/src/share/classes/java/time/calendar/MinguoChrono.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.calendar;
+
+import static java.time.temporal.ChronoField.YEAR;
+
+import java.io.Serializable;
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.temporal.Chrono;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoLocalDate;
+import java.time.temporal.Era;
+import java.time.temporal.ISOChrono;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.ValueRange;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * The Minguo calendar system.
+ *
+ * This chronology defines the rules of the Minguo calendar system.
+ * This calendar system is primarily used in the Republic of China, often known as Taiwan.
+ * Dates are aligned such that {@code 0001-01-01 (Minguo)} is {@code 1911-01-01 (ISO)}.
+ *
+ * The fields are defined as follows:
+ *
+ *
+ *
+ * The ID uniquely identifies the {@code Chrono}.
+ * It can be used to lookup the {@code Chrono} using {@link #of(String)}.
+ *
+ * @return the chronology ID - 'Minguo'
+ * @see #getCalendarType()
+ */
+ @Override
+ public String getId() {
+ return "Minguo";
+ }
+
+ /**
+ * Gets the calendar type of the underlying calendar system - 'roc'.
+ *
+ * The calendar type is an identifier defined by the
+ * Unicode Locale Data Markup Language (LDML) specification.
+ * It can be used to lookup the {@code Chrono} using {@link #of(String)}.
+ * It can also be used as part of a locale, accessible via
+ * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
+ *
+ * @return the calendar system type - 'roc'
+ * @see #getId()
+ */
+ @Override
+ public String getCalendarType() {
+ return "roc";
+ }
+
+ //-----------------------------------------------------------------------
+ @Override
+ public ChronoLocalDate
+ * Minguo leap years occur exactly in line with ISO leap years.
+ * This method does not validate the year passed in, and only has a
+ * well-defined result for years in the supported range.
+ *
+ * @param prolepticYear the proleptic-year to check, not validated for range
+ * @return true if the year is a leap year
+ */
+ @Override
+ public boolean isLeapYear(long prolepticYear) {
+ return ISOChrono.INSTANCE.isLeapYear(prolepticYear + YEARS_DIFFERENCE);
+ }
+
+ @Override
+ public int prolepticYear(Era
+ * This implements {@code ChronoLocalDate} for the {@link MinguoChrono Minguo calendar}.
+ *
+ *
+ * The Minguo calendar system has two eras.
+ * The date {@code 0001-01-01 (Minguo)} is equal to {@code 1912-01-01 (ISO)}.
+ *
+ * Do not use {@code ordinal()} to obtain the numeric representation of {@code MinguoEra}.
+ * Use {@code getValue()} instead.
+ *
+ *
+ * {@code MinguoEra} is an enum representing the Minguo eras of BEFORE_ROC/ROC.
+ * This factory allows the enum to be obtained from the {@code int} value.
+ *
+ * @param era the BEFORE_ROC/ROC value to represent, from 0 (BEFORE_ROC) to 1 (ROC)
+ * @return the era singleton, not null
+ * @throws DateTimeException if the value is invalid
+ */
+ public static MinguoEra of(int era) {
+ switch (era) {
+ case 0:
+ return BEFORE_ROC;
+ case 1:
+ return ROC;
+ default:
+ throw new DateTimeException("Invalid era: " + era);
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the numeric era {@code int} value.
+ *
+ * The era BEFORE_ROC has the value 0, while the era ROC has the value 1.
+ *
+ * @return the era value, from 0 (BEFORE_ROC) to 1 (ROC)
+ */
+ @Override
+ public int getValue() {
+ return ordinal();
+ }
+
+ @Override
+ public MinguoChrono getChrono() {
+ return MinguoChrono.INSTANCE;
+ }
+
+ // JDK8 default methods:
+ //-----------------------------------------------------------------------
+ @Override
+ public ChronoLocalDate
+ * In order to serialise the object it writes its byte and then calls back to the appropriate class where
+ * the serialisation is performed. In order to deserialise the object it read in the type byte, switching
+ * in order to select which class to call back into.
+ *
+ * The serialisation format is determined on a per class basis. In the case of field based classes each
+ * of the fields is written out with an appropriate size format in descending order of the field's size. For
+ * example in the case of {@link LocalDate} year is written before month. Composite classes, such as
+ * {@link LocalDateTime} are serialised as one object. Enum classes are serialised using the index of their
+ * element.
+ *
+ * This class is mutable and should be created once per serialization.
+ *
+ * @serial include
+ * @since 1.8
+ */
+final class Ser implements Externalizable {
+
+ /**
+ * Serialization version.
+ */
+ private static final long serialVersionUID = 7857518227608961174L;
+
+ static final byte JAPANESE_DATE_TYPE = 1;
+ static final byte JAPANESE_ERA_TYPE = 2;
+ static final byte HIJRAH_DATE_TYPE = 3;
+ static final byte HIJRAH_ERA_TYPE = 4;
+ static final byte MINGUO_DATE_TYPE = 5;
+ static final byte MINGUO_ERA_TYPE = 6;
+ static final byte THAIBUDDHIST_DATE_TYPE = 7;
+ static final byte THAIBUDDHIST_ERA_TYPE = 8;
+
+ /** The type being serialized. */
+ private byte type;
+ /** The object being serialized. */
+ private Object object;
+
+ /**
+ * Constructor for deserialization.
+ */
+ public Ser() {
+ }
+
+ /**
+ * Creates an instance for serialization.
+ *
+ * @param type the type
+ * @param object the object
+ */
+ Ser(byte type, Object object) {
+ this.type = type;
+ this.object = object;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Implements the {@code Externalizable} interface to write the object.
+ *
+ * @param out the data stream to write to, not null
+ */
+ @Override
+ public void writeExternal(ObjectOutput out) throws IOException {
+ writeInternal(type, object, out);
+ }
+
+ private static void writeInternal(byte type, Object object, ObjectOutput out) throws IOException {
+ out.writeByte(type);
+ switch (type) {
+ case JAPANESE_DATE_TYPE:
+ ((JapaneseDate) object).writeExternal(out);
+ break;
+ case JAPANESE_ERA_TYPE:
+ ((JapaneseEra) object).writeExternal(out);
+ break;
+ case HIJRAH_DATE_TYPE:
+ ((HijrahDate) object).writeExternal(out);
+ break;
+ case HIJRAH_ERA_TYPE:
+ ((HijrahEra) object).writeExternal(out);
+ break;
+ case MINGUO_DATE_TYPE:
+ ((MinguoDate) object).writeExternal(out);
+ break;
+ case MINGUO_ERA_TYPE:
+ ((MinguoEra) object).writeExternal(out);
+ break;
+ case THAIBUDDHIST_DATE_TYPE:
+ ((ThaiBuddhistDate) object).writeExternal(out);
+ break;
+ case THAIBUDDHIST_ERA_TYPE:
+ ((ThaiBuddhistEra) object).writeExternal(out);
+ break;
+ default:
+ throw new InvalidClassException("Unknown serialized type");
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Implements the {@code Externalizable} interface to read the object.
+ *
+ * @param in the data to read, not null
+ */
+ @Override
+ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+ type = in.readByte();
+ object = readInternal(type, in);
+ }
+
+ static Object read(ObjectInput in) throws IOException, ClassNotFoundException {
+ byte type = in.readByte();
+ return readInternal(type, in);
+ }
+
+ private static Object readInternal(byte type, ObjectInput in) throws IOException, ClassNotFoundException {
+ switch (type) {
+ case JAPANESE_DATE_TYPE: return JapaneseDate.readExternal(in);
+ case JAPANESE_ERA_TYPE: return JapaneseEra.readExternal(in);
+ case HIJRAH_DATE_TYPE: return HijrahDate.readExternal(in);
+ case HIJRAH_ERA_TYPE: return HijrahEra.readExternal(in);
+ case MINGUO_DATE_TYPE: return MinguoDate.readExternal(in);
+ case MINGUO_ERA_TYPE: return MinguoEra.readExternal(in);
+ case THAIBUDDHIST_DATE_TYPE: return ThaiBuddhistDate.readExternal(in);
+ case THAIBUDDHIST_ERA_TYPE: return ThaiBuddhistEra.readExternal(in);
+ default:
+ throw new StreamCorruptedException("Unknown serialized type");
+ }
+ }
+
+ /**
+ * Returns the object that will replace this one.
+ *
+ * @return the read object, should never be null
+ */
+ private Object readResolve() {
+ return object;
+ }
+
+}
diff --git a/src/share/classes/java/time/calendar/ThaiBuddhistChrono.java b/src/share/classes/java/time/calendar/ThaiBuddhistChrono.java
new file mode 100644
index 0000000000000000000000000000000000000000..1fadb5e57c49618c3e307590efe1e3e06a48be94
--- /dev/null
+++ b/src/share/classes/java/time/calendar/ThaiBuddhistChrono.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.calendar;
+
+import static java.time.temporal.ChronoField.YEAR;
+
+import java.io.Serializable;
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.temporal.Chrono;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoLocalDate;
+import java.time.temporal.Era;
+import java.time.temporal.ISOChrono;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.ValueRange;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * The Thai Buddhist calendar system.
+ *
+ * This chronology defines the rules of the Thai Buddhist calendar system.
+ * This calendar system is primarily used in Thailand.
+ * Dates are aligned such that {@code 2484-01-01 (Buddhist)} is {@code 1941-01-01 (ISO)}.
+ *
+ * The fields are defined as follows:
+ *
+ *
+ *
+ * The ID uniquely identifies the {@code Chrono}.
+ * It can be used to lookup the {@code Chrono} using {@link #of(String)}.
+ *
+ * @return the chronology ID - 'ThaiBuddhist'
+ * @see #getCalendarType()
+ */
+ @Override
+ public String getId() {
+ return "ThaiBuddhist";
+ }
+
+ /**
+ * Gets the calendar type of the underlying calendar system - 'buddhist'.
+ *
+ * The calendar type is an identifier defined by the
+ * Unicode Locale Data Markup Language (LDML) specification.
+ * It can be used to lookup the {@code Chrono} using {@link #of(String)}.
+ * It can also be used as part of a locale, accessible via
+ * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
+ *
+ * @return the calendar system type - 'buddhist'
+ * @see #getId()
+ */
+ @Override
+ public String getCalendarType() {
+ return "buddhist";
+ }
+
+ //-----------------------------------------------------------------------
+ @Override
+ public ChronoLocalDate
+ * Thai Buddhist leap years occur exactly in line with ISO leap years.
+ * This method does not validate the year passed in, and only has a
+ * well-defined result for years in the supported range.
+ *
+ * @param prolepticYear the proleptic-year to check, not validated for range
+ * @return true if the year is a leap year
+ */
+ @Override
+ public boolean isLeapYear(long prolepticYear) {
+ return ISOChrono.INSTANCE.isLeapYear(prolepticYear - YEARS_DIFFERENCE);
+ }
+
+ @Override
+ public int prolepticYear(Era
+ * This implements {@code ChronoLocalDate} for the {@link ThaiBuddhistChrono Thai Buddhist calendar}.
+ *
+ *
+ * The Thai Buddhist calendar system has two eras.
+ *
+ * Do not use ordinal() to obtain the numeric representation of a ThaiBuddhistEra
+ * instance. Use getValue() instead.
+ *
+ *
+ * The current era (from ISO year -543 onwards) has the value 1
+ * The previous era has the value 0.
+ *
+ * @param thaiBuddhistEra the era to represent, from 0 to 1
+ * @return the BuddhistEra singleton, never null
+ * @throws IllegalCalendarFieldValueException if the era is invalid
+ */
+ public static ThaiBuddhistEra of(int thaiBuddhistEra) {
+ switch (thaiBuddhistEra) {
+ case 0:
+ return BEFORE_BE;
+ case 1:
+ return BE;
+ default:
+ throw new DateTimeException("Era is not valid for ThaiBuddhistEra");
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the era numeric value.
+ *
+ * The current era (from ISO year -543 onwards) has the value 1
+ * The previous era has the value 0.
+ *
+ * @return the era value, from 0 (BEFORE_BE) to 1 (BE)
+ */
+ @Override
+ public int getValue() {
+ return ordinal();
+ }
+
+ @Override
+ public ThaiBuddhistChrono getChrono() {
+ return ThaiBuddhistChrono.INSTANCE;
+ }
+
+ // JDK8 default methods:
+ //-----------------------------------------------------------------------
+ @Override
+ public ChronoLocalDate
+ * Support for calendar systems other than the default ISO.
+ *
+ * The main API is based around the calendar system defined in ISO-8601.
+ * This package provides support for alternate systems.
+ *
+ * The supported calendar systems includes:
+ *
+ * It is intended that applications use the main API whenever possible,
+ * including code to read and write from a persistent data store,
+ * such as a database, and to send dates and times across a network.
+ * This package is then used at the user interface level to deal with
+ * localized input/output.
+ * See {@link java.time.temporal.ChronoLocalDate ChronoLocalDate}
+ * for a full discussion of the issues.
+ *
+ * This example creates and uses a date in a non-ISO calendar system.
+ *
+ * Unless otherwise noted, passing a null argument to a constructor or method in any class or interface
+ * in this package will cause a {@link java.lang.NullPointerException NullPointerException} to be thrown.
+ * The Javadoc "@param" definition is used to summarise the null-behavior.
+ * The "@throws {@link java.lang.NullPointerException}" is not explicitly documented in each method.
+ *
+ * All calculations should check for numeric overflow and throw either an {@link java.lang.ArithmeticException}
+ * or a {@link java.time.DateTimeException}.
+ *
+ * This class still needs major revision before JDK1.8 ships.
+ *
+ * The builder is used to hold onto different elements of date and time.
+ * It is designed as two separate maps:
+ *
+ *
+ *
+ *
+ *
+ *
Specification for implementors
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+final class ZoneOffsetTransitionRule {
+
+ /**
+ * The month of the month-day of the first day of the cutover week.
+ * The actual date will be adjusted by the dowChange field.
+ */
+ final int month;
+ /**
+ * The day-of-month of the month-day of the cutover week.
+ * If positive, it is the start of the week where the cutover can occur.
+ * If negative, it represents the end of the week where cutover can occur.
+ * The value is the number of days from the end of the month, such that
+ * {@code -1} is the last day of the month, {@code -2} is the second
+ * to last day, and so on.
+ */
+ final byte dom;
+ /**
+ * The cutover day-of-week, -1 to retain the day-of-month.
+ */
+ final int dow;
+ /**
+ * The cutover time in the 'before' offset.
+ */
+ final LocalTime time;
+ /**
+ * Whether the cutover time is midnight at the end of day.
+ */
+ final boolean timeEndOfDay;
+ /**
+ * The definition of how the local time should be interpreted.
+ */
+ final TimeDefinition timeDefinition;
+ /**
+ * The standard offset at the cutover.
+ */
+ final ZoneOffset standardOffset;
+ /**
+ * The offset before the cutover.
+ */
+ final ZoneOffset offsetBefore;
+ /**
+ * The offset after the cutover.
+ */
+ final ZoneOffset offsetAfter;
+
+ /**
+ * Creates an instance defining the yearly rule to create transitions between two offsets.
+ *
+ * @param month the month of the month-day of the first day of the cutover week, from 1 to 12
+ * @param dayOfMonthIndicator the day of the month-day of the cutover week, positive if the week is that
+ * day or later, negative if the week is that day or earlier, counting from the last day of the month,
+ * from -28 to 31 excluding 0
+ * @param dayOfWeek the required day-of-week, -1 if the month-day should not be changed
+ * @param time the cutover time in the 'before' offset, not null
+ * @param timeEndOfDay whether the time is midnight at the end of day
+ * @param timeDefnition how to interpret the cutover
+ * @param standardOffset the standard offset in force at the cutover, not null
+ * @param offsetBefore the offset before the cutover, not null
+ * @param offsetAfter the offset after the cutover, not null
+ * @throws IllegalArgumentException if the day of month indicator is invalid
+ * @throws IllegalArgumentException if the end of day flag is true when the time is not midnight
+ */
+ ZoneOffsetTransitionRule(
+ int month,
+ int dayOfMonthIndicator,
+ int dayOfWeek,
+ LocalTime time,
+ boolean timeEndOfDay,
+ TimeDefinition timeDefnition,
+ ZoneOffset standardOffset,
+ ZoneOffset offsetBefore,
+ ZoneOffset offsetAfter) {
+ Objects.requireNonNull(time, "time");
+ Objects.requireNonNull(timeDefnition, "timeDefnition");
+ Objects.requireNonNull(standardOffset, "standardOffset");
+ Objects.requireNonNull(offsetBefore, "offsetBefore");
+ Objects.requireNonNull(offsetAfter, "offsetAfter");
+ if (month < 1 || month > 12) {
+ throw new IllegalArgumentException("month must be between 1 and 12");
+ }
+ if (dayOfMonthIndicator < -28 || dayOfMonthIndicator > 31 || dayOfMonthIndicator == 0) {
+ throw new IllegalArgumentException("Day of month indicator must be between -28 and 31 inclusive excluding zero");
+ }
+ if (timeEndOfDay && time.equals(LocalTime.MIDNIGHT) == false) {
+ throw new IllegalArgumentException("Time must be midnight when end of day flag is true");
+ }
+ this.month = month;
+ this.dom = (byte) dayOfMonthIndicator;
+ this.dow = dayOfWeek;
+ this.time = time;
+ this.timeEndOfDay = timeEndOfDay;
+ this.timeDefinition = timeDefnition;
+ this.standardOffset = standardOffset;
+ this.offsetBefore = offsetBefore;
+ this.offsetAfter = offsetAfter;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Checks if this object equals another.
+ *
+ *
Implementation notes
+ * This class is a mutable builder used to create zone instances.
+ * It must only be used from a single thread.
+ * The created instances are immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public class ZoneRulesBuilder {
+
+ /**
+ * The list of windows.
+ */
+ private List
+ * public class MyBean {
+ * private Clock clock; // dependency inject
+ * ...
+ * public void process(LocalDate eventDate) {
+ * if (eventDate.isBefore(LocalDate.now(clock)) {
+ * ...
+ * }
+ * }
+ * }
+ *
+ * This approach allows an alternate clock, such as {@link #fixed(Instant, ZoneId) fixed}
+ * or {@link #offset(Clock, Duration) offset} to be used during testing.
+ * Specification for implementors
+ * 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.
+ * Specification for implementors
+ * 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);
+ }
+
+}
diff --git a/src/share/classes/java/time/DayOfWeek.java b/src/share/classes/java/time/DayOfWeek.java
new file mode 100644
index 0000000000000000000000000000000000000000..5d1f3f34772746104d28756ec9e9866cd225e627
--- /dev/null
+++ b/src/share/classes/java/time/DayOfWeek.java
@@ -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'.
+ * Specification for implementors
+ * 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.
+ *
+ * // these two lines are equivalent, but the second approach is recommended
+ * temporal = thisDayOfWeek.adjustInto(temporal);
+ * temporal = temporal.with(thisDayOfWeek);
+ *
+ *
+ * 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
+ *
+ * Specification for implementors
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class Duration
+ implements TemporalAdder, TemporalSubtractor, Comparable
+ * Duration.ofSeconds(3, 1);
+ * Duration.ofSeconds(4, -999_999_999);
+ * Duration.ofSeconds(2, 1000_000_001);
+ *
+ *
+ * @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.
+ *
+ * Duration.of(3, SECONDS);
+ * Duration.of(465, HOURS);
+ *
+ * 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.
+ *
+ * // these two lines are equivalent, but the second approach is recommended
+ * dateTime = thisDuration.addTo(dateTime);
+ * dateTime = dateTime.plus(thisDuration);
+ *
+ *
+ * // these two lines are equivalent, but the second approach is recommended
+ * dateTime = thisDuration.subtractFrom(dateTime);
+ * dateTime = dateTime.minus(thisDuration);
+ *
+ *
+ * out.writeByte(1); // identifies this as a Duration
+ * out.writeLong(seconds);
+ * out.writeInt(nanos);
+ *
+ *
+ * @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);
+ }
+
+}
diff --git a/src/share/classes/java/time/Instant.java b/src/share/classes/java/time/Instant.java
new file mode 100644
index 0000000000000000000000000000000000000000..f253eb58e5192eda1db8f0e2f532704efa51e60e
--- /dev/null
+++ b/src/share/classes/java/time/Instant.java
@@ -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.
+ * Time-scale
+ *
+ *
Specification for implementors
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class Instant
+ implements Temporal, TemporalAdjuster, Comparable
+ * Instant.ofSeconds(3, 1);
+ * Instant.ofSeconds(4, -999_999_999);
+ * Instant.ofSeconds(2, 1000_000_001);
+ *
+ *
+ * @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.
+ *
+ *
+ * All other {@code ChronoField} instances will return false.
+ *
+ *
+ *
+ * // these two lines are equivalent, but the second approach is recommended
+ * temporal = thisInstant.adjustInto(temporal);
+ * temporal = temporal.with(thisInstant);
+ *
+ *
+ * long period = start.periodUntil(end, SECONDS); // this method
+ * dateTime.plus(SECONDS.between(start, end)); // use in plus/minus
+ *
+ *
+ * out.writeByte(2); // identifies this as an Instant
+ * out.writeLong(seconds);
+ * out.writeInt(nanos);
+ *
+ *
+ * @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);
+ }
+
+}
diff --git a/src/share/classes/java/time/LocalDate.java b/src/share/classes/java/time/LocalDate.java
new file mode 100644
index 0000000000000000000000000000000000000000..8d40f72871fb3e21293fb12218cb9f4f9553e0d2
--- /dev/null
+++ b/src/share/classes/java/time/LocalDate.java
@@ -0,0 +1,1875 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import static java.time.LocalTime.SECONDS_PER_DAY;
+import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH;
+import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR;
+import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH;
+import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR;
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.DAY_OF_YEAR;
+import static java.time.temporal.ChronoField.EPOCH_DAY;
+import static java.time.temporal.ChronoField.EPOCH_MONTH;
+import static java.time.temporal.ChronoField.ERA;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.YEAR;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.time.format.DateTimeBuilder;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatters;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoLocalDate;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Era;
+import java.time.temporal.ISOChrono;
+import java.time.temporal.OffsetDate;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdder;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.TemporalSubtractor;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.ValueRange;
+import java.time.temporal.Year;
+import java.time.zone.ZoneOffsetTransition;
+import java.time.zone.ZoneRules;
+import java.util.Objects;
+
+/**
+ * A date without a time-zone in the ISO-8601 calendar system,
+ * such as {@code 2007-12-03}.
+ * Specification for implementors
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class LocalDate
+ implements Temporal, TemporalAdjuster, ChronoLocalDate
+ *
+ * All other {@code ChronoField} instances will return false.
+ *
+ * import static java.time.Month.*;
+ * import static java.time.temporal.Adjusters.*;
+ *
+ * result = localDate.with(JULY).with(lastDayOfMonth());
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * // these two lines are equivalent, but the second approach is recommended
+ * temporal = thisLocalDate.adjustInto(temporal);
+ * temporal = temporal.with(thisLocalDate);
+ *
+ *
+ * long period = start.periodUntil(end, MONTHS); // this method
+ * dateTime.plus(MONTHS.between(start, end)); // use in plus/minus
+ *
+ *
+ * LocalDate a = LocalDate.of(2012, 6, 30);
+ * LocalDate b = LocalDate.of(2012, 7, 1);
+ * a.isAfter(b) == false
+ * a.isAfter(a) == false
+ * b.isAfter(a) == true
+ *
+ *
+ * LocalDate a = LocalDate.of(2012, 6, 30);
+ * LocalDate b = LocalDate.of(2012, 7, 1);
+ * a.isBefore(b) == true
+ * a.isBefore(a) == false
+ * b.isBefore(a) == false
+ *
+ *
+ * LocalDate a = LocalDate.of(2012, 6, 30);
+ * LocalDate b = LocalDate.of(2012, 7, 1);
+ * a.isEqual(b) == false
+ * a.isEqual(a) == true
+ * b.isEqual(a) == false
+ *
+ *
+ * out.writeByte(3); // identifies this as a LocalDate
+ * out.writeInt(year);
+ * out.writeByte(month);
+ * out.writeByte(day);
+ *
+ *
+ * @return the instance of {@code Ser}, not null
+ */
+ private Object writeReplace() {
+ return new Ser(Ser.LOCAL_DATE_TYPE, this);
+ }
+
+ /**
+ * Defend against malicious streams.
+ * @return never
+ * @throws InvalidObjectException always
+ */
+ private Object readResolve() throws ObjectStreamException {
+ throw new InvalidObjectException("Deserialization via serialization delegate");
+ }
+
+ void writeExternal(DataOutput out) throws IOException {
+ out.writeInt(year);
+ out.writeByte(month);
+ out.writeByte(day);
+ }
+
+ static LocalDate readExternal(DataInput in) throws IOException {
+ int year = in.readInt();
+ int month = in.readByte();
+ int dayOfMonth = in.readByte();
+ return LocalDate.of(year, month, dayOfMonth);
+ }
+
+}
diff --git a/src/share/classes/java/time/LocalDateTime.java b/src/share/classes/java/time/LocalDateTime.java
new file mode 100644
index 0000000000000000000000000000000000000000..6dff20bc1aa5d96d130046fc57fbd410863cc909
--- /dev/null
+++ b/src/share/classes/java/time/LocalDateTime.java
@@ -0,0 +1,1860 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import static java.time.LocalTime.HOURS_PER_DAY;
+import static java.time.LocalTime.MICROS_PER_DAY;
+import static java.time.LocalTime.MILLIS_PER_DAY;
+import static java.time.LocalTime.MINUTES_PER_DAY;
+import static java.time.LocalTime.NANOS_PER_DAY;
+import static java.time.LocalTime.NANOS_PER_HOUR;
+import static java.time.LocalTime.NANOS_PER_MINUTE;
+import static java.time.LocalTime.NANOS_PER_SECOND;
+import static java.time.LocalTime.SECONDS_PER_DAY;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatters;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoLocalDateTime;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.ISOChrono;
+import java.time.temporal.OffsetDateTime;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdder;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.TemporalSubtractor;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.ValueRange;
+import java.time.zone.ZoneRules;
+import java.util.Objects;
+
+/**
+ * A date-time without a time-zone in the ISO-8601 calendar system,
+ * such as {@code 2007-12-03T10:15:30}.
+ * Specification for implementors
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class LocalDateTime
+ implements Temporal, TemporalAdjuster, ChronoLocalDateTime
+ *
+ * All other {@code ChronoField} instances will return false.
+ *
+ * import static java.time.Month.*;
+ * import static java.time.temporal.Adjusters.*;
+ *
+ * result = localDateTime.with(JULY).with(lastDayOfMonth());
+ *
+ *
+ * result = localDateTime.with(date);
+ * result = localDateTime.with(time);
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * // these two lines are equivalent, but the second approach is recommended
+ * temporal = thisLocalDateTime.adjustInto(temporal);
+ * temporal = temporal.with(thisLocalDateTime);
+ *
+ *
+ * long period = start.periodUntil(end, MONTHS); // this method
+ * dateTime.plus(MONTHS.between(start, end)); // use in plus/minus
+ *
+ *
+ * LocalDate a = LocalDateTime.of(2012, 6, 30, 12, 00);
+ * LocalDate b = LocalDateTime.of(2012, 7, 1, 12, 00);
+ * a.isAfter(b) == false
+ * a.isAfter(a) == false
+ * b.isAfter(a) == true
+ *
+ *
+ * LocalDate a = LocalDateTime.of(2012, 6, 30, 12, 00);
+ * LocalDate b = LocalDateTime.of(2012, 7, 1, 12, 00);
+ * a.isBefore(b) == true
+ * a.isBefore(a) == false
+ * b.isBefore(a) == false
+ *
+ *
+ * LocalDate a = LocalDateTime.of(2012, 6, 30, 12, 00);
+ * LocalDate b = LocalDateTime.of(2012, 7, 1, 12, 00);
+ * a.isEqual(b) == false
+ * a.isEqual(a) == true
+ * b.isEqual(a) == false
+ *
+ *
+ *
+ * out.writeByte(5); // identifies this as a LocalDateTime
+ * // the date excluding the one byte header
+ * // the time excluding the one byte header
+ *
+ *
+ * @return the instance of {@code Ser}, not null
+ */
+ private Object writeReplace() {
+ return new Ser(Ser.LOCAL_DATE_TIME_TYPE, this);
+ }
+
+ /**
+ * Defend against malicious streams.
+ * @return never
+ * @throws InvalidObjectException always
+ */
+ private Object readResolve() throws ObjectStreamException {
+ throw new InvalidObjectException("Deserialization via serialization delegate");
+ }
+
+ void writeExternal(DataOutput out) throws IOException {
+ date.writeExternal(out);
+ time.writeExternal(out);
+ }
+
+ static LocalDateTime readExternal(DataInput in) throws IOException {
+ LocalDate date = LocalDate.readExternal(in);
+ LocalTime time = LocalTime.readExternal(in);
+ return LocalDateTime.of(date, time);
+ }
+
+}
diff --git a/src/share/classes/java/time/LocalTime.java b/src/share/classes/java/time/LocalTime.java
new file mode 100644
index 0000000000000000000000000000000000000000..01e74e6c51bd09f7ee6b656f9c2e3d081d55e19c
--- /dev/null
+++ b/src/share/classes/java/time/LocalTime.java
@@ -0,0 +1,1630 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import static java.time.temporal.ChronoField.HOUR_OF_DAY;
+import static java.time.temporal.ChronoField.MICRO_OF_DAY;
+import static java.time.temporal.ChronoField.MINUTE_OF_HOUR;
+import static java.time.temporal.ChronoField.NANO_OF_DAY;
+import static java.time.temporal.ChronoField.NANO_OF_SECOND;
+import static java.time.temporal.ChronoField.SECOND_OF_DAY;
+import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
+import static java.time.temporal.ChronoUnit.NANOS;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.time.format.DateTimeBuilder;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatters;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoLocalDateTime;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.ChronoZonedDateTime;
+import java.time.temporal.OffsetTime;
+import java.time.temporal.Queries;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdder;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.TemporalSubtractor;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.ValueRange;
+import java.util.Objects;
+
+/**
+ * A time without time-zone in the ISO-8601 calendar system,
+ * such as {@code 10:15:30}.
+ * Specification for implementors
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class LocalTime
+ implements Temporal, TemporalAdjuster, Comparable
+ *
+ * All other {@code ChronoField} instances will return false.
+ *
+ *
+ *
+ * // these two lines are equivalent, but the second approach is recommended
+ * temporal = thisLocalTime.adjustInto(temporal);
+ * temporal = temporal.with(thisLocalTime);
+ *
+ *
+ * long period = start.periodUntil(end, HOURS); // this method
+ * dateTime.plus(HOURS.between(start, end)); // use in plus/minus
+ *
+ *
+ *
+ * out.writeByte(4); // identifies this as a LocalTime
+ * if (nano == 0) {
+ * if (second == 0) {
+ * if (minute == 0) {
+ * out.writeByte(~hour);
+ * } else {
+ * out.writeByte(hour);
+ * out.writeByte(~minute);
+ * }
+ * } else {
+ * out.writeByte(hour);
+ * out.writeByte(minute);
+ * out.writeByte(~second);
+ * }
+ * } else {
+ * out.writeByte(hour);
+ * out.writeByte(minute);
+ * out.writeByte(second);
+ * out.writeInt(nano);
+ * }
+ *
+ *
+ * @return the instance of {@code Ser}, not null
+ */
+ private Object writeReplace() {
+ return new Ser(Ser.LOCAL_TIME_TYPE, this);
+ }
+
+ /**
+ * Defend against malicious streams.
+ * @return never
+ * @throws InvalidObjectException always
+ */
+ private Object readResolve() throws ObjectStreamException {
+ throw new InvalidObjectException("Deserialization via serialization delegate");
+ }
+
+ void writeExternal(DataOutput out) throws IOException {
+ if (nano == 0) {
+ if (second == 0) {
+ if (minute == 0) {
+ out.writeByte(~hour);
+ } else {
+ out.writeByte(hour);
+ out.writeByte(~minute);
+ }
+ } else {
+ out.writeByte(hour);
+ out.writeByte(minute);
+ out.writeByte(~second);
+ }
+ } else {
+ out.writeByte(hour);
+ out.writeByte(minute);
+ out.writeByte(second);
+ out.writeInt(nano);
+ }
+ }
+
+ static LocalTime readExternal(DataInput in) throws IOException {
+ int hour = in.readByte();
+ int minute = 0;
+ int second = 0;
+ int nano = 0;
+ if (hour < 0) {
+ hour = ~hour;
+ } else {
+ minute = in.readByte();
+ if (minute < 0) {
+ minute = ~minute;
+ } else {
+ second = in.readByte();
+ if (second < 0) {
+ second = ~second;
+ } else {
+ nano = in.readInt();
+ }
+ }
+ }
+ return LocalTime.of(hour, minute, second, nano);
+ }
+
+}
diff --git a/src/share/classes/java/time/Month.java b/src/share/classes/java/time/Month.java
new file mode 100644
index 0000000000000000000000000000000000000000..db8d0533296bce27c029f207e489026aa948152e
--- /dev/null
+++ b/src/share/classes/java/time/Month.java
@@ -0,0 +1,608 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoUnit.MONTHS;
+
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.TextStyle;
+import java.time.temporal.Chrono;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ISOChrono;
+import java.time.temporal.Queries;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.ValueRange;
+import java.util.Locale;
+
+/**
+ * A month-of-year, such as 'July'.
+ * Specification for implementors
+ * This is an immutable and thread-safe enum.
+ *
+ * @since 1.8
+ */
+public enum Month implements TemporalAccessor, TemporalAdjuster {
+
+ /**
+ * The singleton instance for the month of January with 31 days.
+ * This has the numeric value of {@code 1}.
+ */
+ JANUARY,
+ /**
+ * The singleton instance for the month of February with 28 days, or 29 in a leap year.
+ * This has the numeric value of {@code 2}.
+ */
+ FEBRUARY,
+ /**
+ * The singleton instance for the month of March with 31 days.
+ * This has the numeric value of {@code 3}.
+ */
+ MARCH,
+ /**
+ * The singleton instance for the month of April with 30 days.
+ * This has the numeric value of {@code 4}.
+ */
+ APRIL,
+ /**
+ * The singleton instance for the month of May with 31 days.
+ * This has the numeric value of {@code 5}.
+ */
+ MAY,
+ /**
+ * The singleton instance for the month of June with 30 days.
+ * This has the numeric value of {@code 6}.
+ */
+ JUNE,
+ /**
+ * The singleton instance for the month of July with 31 days.
+ * This has the numeric value of {@code 7}.
+ */
+ JULY,
+ /**
+ * The singleton instance for the month of August with 31 days.
+ * This has the numeric value of {@code 8}.
+ */
+ AUGUST,
+ /**
+ * The singleton instance for the month of September with 30 days.
+ * This has the numeric value of {@code 9}.
+ */
+ SEPTEMBER,
+ /**
+ * The singleton instance for the month of October with 31 days.
+ * This has the numeric value of {@code 10}.
+ */
+ OCTOBER,
+ /**
+ * The singleton instance for the month of November with 30 days.
+ * This has the numeric value of {@code 11}.
+ */
+ NOVEMBER,
+ /**
+ * The singleton instance for the month of December with 31 days.
+ * This has the numeric value of {@code 12}.
+ */
+ DECEMBER;
+ /**
+ * Private cache of all the constants.
+ */
+ private static final Month[] ENUMS = Month.values();
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains an instance of {@code Month} from an {@code int} value.
+ *
+ * // these two lines are equivalent, but the second approach is recommended
+ * temporal = thisMonth.adjustInto(temporal);
+ * temporal = temporal.with(thisMonth);
+ *
+ *
+ * dateInMay.with(JANUARY); // four months earlier
+ * dateInMay.with(APRIL); // one months earlier
+ * dateInMay.with(MAY); // same date
+ * dateInMay.with(JUNE); // one month later
+ * dateInMay.with(DECEMBER); // seven months later
+ *
+ *
+ *
Specification for implementors
+ * This class is immutable and thread-safe.
+ * The maximum number of hours that can be stored is about 2.5 million, limited by storing
+ * a single {@code long} nanoseconds for all time units internally.
+ *
+ * @since 1.8
+ */
+public final class Period
+ implements TemporalAdder, TemporalSubtractor, Serializable {
+ // maximum hours is 2,562,047
+
+ /**
+ * A constant for a period of zero.
+ */
+ public static final Period ZERO = new Period(0, 0, 0, 0);
+ /**
+ * Serialization version.
+ */
+ private static final long serialVersionUID = -8290556941213247973L;
+
+ /**
+ * The number of years.
+ */
+ private final int years;
+ /**
+ * The number of months.
+ */
+ private final int months;
+ /**
+ * The number of days.
+ */
+ private final int days;
+ /**
+ * The number of nanoseconds.
+ */
+ private final long nanos;
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains a {@code Period} from date-based and time-based fields.
+ *
+ * Period.of(3, SECONDS);
+ * Period.of(5, YEARS);
+ *
+ * The specified unit must be one of the supported units from {@link ChronoUnit},
+ * {@code YEARS}, {@code MONTHS} or {@code DAYS} or be a time unit with an
+ * {@linkplain TemporalUnit#isDurationEstimated() exact duration}.
+ * Other units throw an exception.
+ *
+ * @param amount the amount of the period, measured in terms of the unit, positive or negative
+ * @param unit the unit that the period is measured in, must have an exact duration, not null
+ * @return the period, not null
+ * @throws DateTimeException if the period unit is invalid
+ * @throws ArithmeticException if a numeric overflow occurs
+ */
+ public static Period of(long amount, TemporalUnit unit) {
+ return ZERO.plus(amount, unit);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Obtains a {@code Period} from a {@code Duration}.
+ *
+ * // these two lines are equivalent, but the second approach is recommended
+ * dateTime = thisPeriod.addTo(dateTime);
+ * dateTime = dateTime.plus(thisPeriod);
+ *
+ *
+ * // these two lines are equivalent, but the second approach is recommended
+ * dateTime = thisPeriod.subtractFrom(dateTime);
+ * dateTime = dateTime.minus(thisPeriod);
+ *
+ * Implementation notes
+ * This class wraps the object being serialized, and takes a byte representing the type of the class to
+ * be serialized. This byte can also be used for versioning the serialization format. In this case another
+ * byte flag would be used in order to specify an alternative version of the type format.
+ * For example {@code LOCAL_DATE_TYPE_VERSION_2 = 21}.
+ *
+ *
Time-zone IDs
+ * The ID is unique within the system.
+ * The formats for offset and region IDs differ.
+ * Specification for implementors
+ * This abstract class has two implementations, both of which are immutable and thread-safe.
+ * One implementation models region-based IDs, the other is {@code ZoneOffset} modelling
+ * offset-based IDs.
+ *
+ * @since 1.8
+ */
+public abstract class ZoneId implements Serializable {
+
+ /**
+ * A map of zone overrides to enable the older US time-zone names to be used.
+ *
+ *
+ *
+ *
{offset} - a {@link ZoneOffset} ID, such as 'Z' or '+02:00'
+ * UTC - alternate form of a {@code ZoneOffset} ID equal to 'Z'
+ * UTC0 - alternate form of a {@code ZoneOffset} ID equal to 'Z'
+ * UTC{offset} - alternate form of a {@code ZoneOffset} ID equal to '{offset}'
+ * GMT - alternate form of a {@code ZoneOffset} ID equal to 'Z'
+ * GMT0 - alternate form of a {@code ZoneOffset} ID equal to 'Z'
+ * GMT{offset} - alternate form of a {@code ZoneOffset} ID equal to '{offset}'r
+ * {regionID} - full region ID, loaded from configuration
+ * [A-Za-z][A-Za-z0-9~/._+-]+.
+ *
+ * out.writeByte(7); // identifies this as a ZoneId (not ZoneOffset)
+ * out.writeUTF(zoneId);
+ *
+ *
+ * @return the instance of {@code Ser}, not null
+ */
+ // this is here for serialization Javadoc
+ private Object writeReplace() {
+ return new Ser(Ser.ZONE_REGION_TYPE, this);
+ }
+
+ abstract void write(DataOutput out) throws IOException;
+
+}
diff --git a/src/share/classes/java/time/ZoneOffset.java b/src/share/classes/java/time/ZoneOffset.java
new file mode 100644
index 0000000000000000000000000000000000000000..5436a71f44c9fb4433bb5414bb47877b3981547f
--- /dev/null
+++ b/src/share/classes/java/time/ZoneOffset.java
@@ -0,0 +1,789 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import static java.time.temporal.ChronoField.OFFSET_SECONDS;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.time.temporal.ChronoField;
+import java.time.temporal.Queries;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.ValueRange;
+import java.time.zone.ZoneRules;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * A time-zone offset from Greenwich/UTC, such as {@code +02:00}.
+ * Specification for implementors
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class ZoneOffset
+ extends ZoneId
+ implements TemporalAccessor, TemporalAdjuster, Comparable
+ *
+ *
+ * // these two lines are equivalent, but the second approach is recommended
+ * temporal = thisOffset.adjustInto(temporal);
+ * temporal = temporal.with(thisOffset);
+ *
+ *
+ * out.writeByte(8); // identifies this as a ZoneOffset
+ * int offsetByte = totalSeconds % 900 == 0 ? totalSeconds / 900 : 127;
+ * out.writeByte(offsetByte);
+ * if (offsetByte == 127) {
+ * out.writeInt(totalSeconds);
+ * }
+ *
+ *
+ * @return the instance of {@code Ser}, not null
+ */
+ private Object writeReplace() {
+ return new Ser(Ser.ZONE_OFFSET_TYPE, this);
+ }
+
+ /**
+ * Defend against malicious streams.
+ * @return never
+ * @throws InvalidObjectException always
+ */
+ private Object readResolve() throws ObjectStreamException {
+ throw new InvalidObjectException("Deserialization via serialization delegate");
+ }
+
+ @Override
+ void write(DataOutput out) throws IOException {
+ out.writeByte(Ser.ZONE_OFFSET_TYPE);
+ writeExternal(out);
+ }
+
+ void writeExternal(DataOutput out) throws IOException {
+ final int offsetSecs = totalSeconds;
+ int offsetByte = offsetSecs % 900 == 0 ? offsetSecs / 900 : 127; // compress to -72 to +72
+ out.writeByte(offsetByte);
+ if (offsetByte == 127) {
+ out.writeInt(offsetSecs);
+ }
+ }
+
+ static ZoneOffset readExternal(DataInput in) throws IOException {
+ int offsetByte = in.readByte();
+ return (offsetByte == 127 ? ZoneOffset.ofTotalSeconds(in.readInt()) : ZoneOffset.ofTotalSeconds(offsetByte * 900));
+ }
+
+}
diff --git a/src/share/classes/java/time/ZoneRegion.java b/src/share/classes/java/time/ZoneRegion.java
new file mode 100644
index 0000000000000000000000000000000000000000..ad93e3517900e22aa95203039ac52be804b9df06
--- /dev/null
+++ b/src/share/classes/java/time/ZoneRegion.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.time.zone.ZoneRules;
+import java.time.zone.ZoneRulesException;
+import java.time.zone.ZoneRulesProvider;
+import java.util.Objects;
+import java.util.regex.Pattern;
+
+/**
+ * A geographical region where the same time-zone rules apply.
+ * Specification for implementors
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+final class ZoneRegion extends ZoneId implements Serializable {
+
+ /**
+ * Serialization version.
+ */
+ private static final long serialVersionUID = 8386373296231747096L;
+ /**
+ * The regex pattern for region IDs.
+ */
+ private static final Pattern PATTERN = Pattern.compile("[A-Za-z][A-Za-z0-9~/._+-]+");
+
+ /**
+ * The time-zone ID, not null.
+ */
+ private final String id;
+ /**
+ * The time-zone rules, null if zone ID was loaded leniently.
+ */
+ private final transient ZoneRules rules;
+
+ /**
+ * Obtains an instance of {@code ZoneRegion} from an identifier without checking
+ * if the time-zone has available rules.
+ *
+ * out.writeByte(7); // identifies this as a ZoneId (not ZoneOffset)
+ * out.writeUTF(zoneId);
+ *
+ *
+ * @return the instance of {@code Ser}, not null
+ */
+ private Object writeReplace() {
+ return new Ser(Ser.ZONE_REGION_TYPE, this);
+ }
+
+ /**
+ * Defend against malicious streams.
+ * @return never
+ * @throws InvalidObjectException always
+ */
+ private Object readResolve() throws ObjectStreamException {
+ throw new InvalidObjectException("Deserialization via serialization delegate");
+ }
+
+ @Override
+ void write(DataOutput out) throws IOException {
+ out.writeByte(Ser.ZONE_REGION_TYPE);
+ writeExternal(out);
+ }
+
+ void writeExternal(DataOutput out) throws IOException {
+ out.writeUTF(id);
+ }
+
+ static ZoneId readExternal(DataInput in) throws IOException {
+ String id = in.readUTF();
+ return ofLenient(id);
+ }
+
+}
diff --git a/src/share/classes/java/time/ZonedDateTime.java b/src/share/classes/java/time/ZonedDateTime.java
new file mode 100644
index 0000000000000000000000000000000000000000..c6c62fdebaace907cf9010d1097823252e4a5192
--- /dev/null
+++ b/src/share/classes/java/time/ZonedDateTime.java
@@ -0,0 +1,2071 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import static java.time.temporal.ChronoField.INSTANT_SECONDS;
+import static java.time.temporal.ChronoField.NANO_OF_SECOND;
+import static java.time.temporal.ChronoField.OFFSET_SECONDS;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatters;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.ChronoZonedDateTime;
+import java.time.temporal.ISOChrono;
+import java.time.temporal.OffsetDateTime;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdder;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.TemporalSubtractor;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.ValueRange;
+import java.time.zone.ZoneOffsetTransition;
+import java.time.zone.ZoneRules;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A date-time with a time-zone in the ISO-8601 calendar system,
+ * such as {@code 2007-12-03T10:15:30+01:00 Europe/Paris}.
+ *
+ *
Specification for implementors
+ * A {@code ZonedDateTime} holds state equivalent to three separate objects,
+ * a {@code LocalDateTime}, a {@code ZoneId} and the resolved {@code ZoneOffset}.
+ * The offset and local date-time are used to define an instant when necessary.
+ * The zone ID is used to obtain the rules for how and when the offset changes.
+ * The offset cannot be freely set, as the zone controls which offsets are valid.
+ *
+ *
+ * All other {@code ChronoField} instances will return false.
+ *
+ * import static java.time.Month.*;
+ * import static java.time.temporal.Adjusters.*;
+ *
+ * result = zonedDateTime.with(JULY).with(lastDayOfMonth());
+ *
+ *
+ * result = zonedDateTime.with(date);
+ * result = zonedDateTime.with(time);
+ *
+ *
+ *
+ *
+ * long period = start.periodUntil(end, MONTHS); // this method
+ * dateTime.plus(MONTHS.between(start, end)); // use in plus/minus
+ *
+ *
+ * out.writeByte(6); // identifies this as a ZonedDateTime
+ * // the date-time excluding the one byte header
+ * // the offset excluding the one byte header
+ * // the zone ID excluding the one byte header
+ *
+ *
+ * @return the instance of {@code Ser}, not null
+ */
+ private Object writeReplace() {
+ return new Ser(Ser.ZONE_DATE_TIME_TYPE, this);
+ }
+
+ /**
+ * Defend against malicious streams.
+ * @return never
+ * @throws InvalidObjectException always
+ */
+ private Object readResolve() throws ObjectStreamException {
+ throw new InvalidObjectException("Deserialization via serialization delegate");
+ }
+
+ void writeExternal(DataOutput out) throws IOException {
+ dateTime.writeExternal(out);
+ offset.writeExternal(out);
+ zone.write(out);
+ }
+
+ static ZonedDateTime readExternal(DataInput in) throws IOException {
+ LocalDateTime dateTime = LocalDateTime.readExternal(in);
+ ZoneOffset offset = ZoneOffset.readExternal(in);
+ ZoneId zone = (ZoneId) Ser.read(in);
+ return ZonedDateTime.ofLenient(dateTime, offset, zone);
+ }
+
+}
diff --git a/src/share/classes/java/time/calendar/ChronoDateImpl.java b/src/share/classes/java/time/calendar/ChronoDateImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..9ecd2a27103b735880c722dddd7425833fb04523
--- /dev/null
+++ b/src/share/classes/java/time/calendar/ChronoDateImpl.java
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.calendar;
+
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.ERA;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.YEAR_OF_ERA;
+
+import java.io.Serializable;
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.temporal.Chrono;
+import java.time.temporal.ChronoLocalDate;
+import java.time.temporal.ChronoLocalDateTime;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalUnit;
+
+/**
+ * A date expressed in terms of a standard year-month-day calendar system.
+ *
+ * System.out.printf("Example()%n");
+ * // Enumerate the list of available calendars and print today for each
+ * Set<Chrono> chronos = Chrono.getAvailableChronologies();
+ * for (Chrono chrono : chronos) {
+ * ChronoLocalDate> date = chrono.dateNow();
+ * System.out.printf(" %20s: %s%n", chrono.getID(), date.toString());
+ * }
+ *
+ * // Print the Hijrah date and calendar
+ * ChronoLocalDate> date = Chrono.of("Hijrah").dateNow();
+ * int day = date.get(ChronoField.DAY_OF_MONTH);
+ * int dow = date.get(ChronoField.DAY_OF_WEEK);
+ * int month = date.get(ChronoField.MONTH_OF_YEAR);
+ * int year = date.get(ChronoField.YEAR);
+ * System.out.printf(" Today is %s %s %d-%s-%d%n", date.getChrono().getID(),
+ * dow, day, month, year);
+
+ * // Print today's date and the last day of the year
+ * ChronoLocalDate> now1 = Chrono.of("Hijrah").dateNow();
+ * ChronoLocalDate> first = now1.with(ChronoField.DAY_OF_MONTH, 1)
+ * .with(ChronoField.MONTH_OF_YEAR, 1);
+ * ChronoLocalDate> last = first.plus(1, ChronoUnit.YEARS)
+ * .minus(1, ChronoUnit.DAYS);
+ * System.out.printf(" Today is %s: start: %s; end: %s%n", last.getChrono().getID(),
+ * first, last);
+ *
+ *
+ * Adding Calendars
+ * Specification for implementors
+ * This abstract class must be implemented with care to ensure other classes operate correctly.
+ * All implementations that can be instantiated must be final, immutable and thread-safe.
+ * Subclasses should be Serializable wherever possible.
+ *
+ * @param
+ *
+ *
+ *
+ *
+ *
+ *
+ * # of month
+ * Name of month
+ * Number of days
+ *
+ *
+ * 1
+ * Muharram
+ * 30
+ *
+ *
+ * 2
+ * Safar
+ * 29
+ *
+ *
+ * 3
+ * Rabi'al-Awwal
+ * 30
+ *
+ *
+ * 4
+ * Rabi'ath-Thani
+ * 29
+ *
+ *
+ * 5
+ * Jumada l-Ula
+ * 30
+ *
+ *
+ * 6
+ * Jumada t-Tania
+ * 29
+ *
+ *
+ * 7
+ * Rajab
+ * 30
+ *
+ *
+ * 8
+ * Sha`ban
+ * 29
+ *
+ *
+ * 9
+ * Ramadan
+ * 30
+ *
+ *
+ * 10
+ * Shawwal
+ * 29
+ *
+ *
+ * 11
+ * Dhu 'l-Qa`da
+ * 30
+ *
+ *
+ *
+ * 12
+ * Dhu 'l-Hijja
+ * 29, but 30 days in years 2, 5, 7, 10,
+ *
+ * 13, 16, 18, 21, 24, 26, and 29Specification for implementors
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class HijrahChrono extends Chrono
+ * Greatest Least
+ * Field name Minimum Minimum Maximum Maximum
+ * ---------- ------- ------- ------- -------
+ * ERA 0 0 1 1
+ * YEAR_OF_ERA 1 1 9999 9999
+ * MONTH_OF_YEAR 1 1 12 12
+ * DAY_OF_MONTH 1 1 29 30
+ * DAY_OF_YEAR 1 1 354 355
+ *
+ *
+ * Minimum values.
+ */
+ private static final int MIN_VALUES[] =
+ {
+ 0,
+ MIN_YEAR_OF_ERA,
+ 0,
+ 1,
+ 0,
+ 1,
+ 1
+ };
+
+ /**
+ * Least maximum values.
+ */
+ private static final int LEAST_MAX_VALUES[] =
+ {
+ 1,
+ MAX_YEAR_OF_ERA,
+ 11,
+ 51,
+ 5,
+ 29,
+ 354
+ };
+
+ /**
+ * Maximum values.
+ */
+ private static final int MAX_VALUES[] =
+ {
+ 1,
+ MAX_YEAR_OF_ERA,
+ 11,
+ 52,
+ 6,
+ 30,
+ 355
+ };
+
+ /**
+ * Position of day-of-month. This value is used to get the min/max value
+ * from an array.
+ */
+ private static final int POSITION_DAY_OF_MONTH = 5;
+ /**
+ * Position of day-of-year. This value is used to get the min/max value from
+ * an array.
+ */
+ private static final int POSITION_DAY_OF_YEAR = 6;
+ /**
+ * Zero-based start date of cycle year.
+ */
+ private static final int CYCLEYEAR_START_DATE[] =
+ {
+ 0,
+ 354,
+ 709,
+ 1063,
+ 1417,
+ 1772,
+ 2126,
+ 2481,
+ 2835,
+ 3189,
+ 3544,
+ 3898,
+ 4252,
+ 4607,
+ 4961,
+ 5315,
+ 5670,
+ 6024,
+ 6379,
+ 6733,
+ 7087,
+ 7442,
+ 7796,
+ 8150,
+ 8505,
+ 8859,
+ 9214,
+ 9568,
+ 9922,
+ 10277
+ };
+
+ /**
+ * Holding the adjusted month days in year. The key is a year (Integer) and
+ * the value is the all the month days in year (int[]).
+ */
+ private final HashMap
+ * StartYear/StartMonth(0-based)-EndYear/EndMonth(0-based):Deviation day (1, 2, -1, or -2)
+ * Line separator or ";" is used for the separator of each deviation data.
+ * Here is the example.
+ *
+ * 1429/0-1429/1:1
+ * 1429/2-1429/7:1;1429/6-1429/11:1
+ * 1429/11-9999/11:1
+ * The default location of the configuration file is:
+ *
+ * $CLASSPATH/java/time/i18n
+ * And the default file name is:
+ *
+ * hijrah_deviation.cfg
+ * The default location and file name can be overriden by setting
+ * following two Java's system property.
+ *
+ * Location: java.time.i18n.HijrahDate.deviationConfigDir
+ * File name: java.time.i18n.HijrahDate.deviationConfigFile
+ *
+ * Specification for implementors
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+final class HijrahDate
+ extends ChronoDateImpl
+ *
+ * # Deviation data for islamicc calendar
+ * Mar-23-2012 -1
+ * Apr-22-2012 +1
+ * May-21-2012 -1
+ * Dec-14-2012 +1
+ *
+ *
+ * @since 1.8
+ */
+final class HijrahDeviationReader {
+
+ /**
+ * Default prefix for name of deviation file; suffix is typeId.
+ */
+ private static final String DEFAULT_CONFIG_FILE_PREFIX = "hijrah_";
+
+ /**
+ * Read Hijrah_deviation.cfg file. The config file contains the deviation
+ * data with format defined in the class javadoc.
+ *
+ * @param typeId the name of the calendar
+ * @param calendarType the calendar type
+ * @return {@code true} if the file was read and each entry accepted by the
+ * Block; else {@code false} no configuration was done
+ *
+ * @throws IOException for zip/jar file handling exception.
+ * @throws ParseException if the format of the configuration file is wrong.
+ */
+ static boolean readDeviation(String typeId, String calendarType,
+ Block
+ * $CLASSPATH/java/time/calendar
+ *
And the default file name is:
+ *
+ * hijrah_ + typeId + .cfg
+ *
The default location and file name can be overridden by setting
+ * following two Java system properties.
+ *
+ * Location: java.time.calendar.HijrahDate.deviationConfigDir
+ * File name: java.time.calendar.HijrahDate.File. + typeid
+ *
Regarding the file format, see readDeviationConfig() method for
+ * details.
+ *
+ * @param typeId the name of the calendar deviation data
+ * @return InputStream for file reading.
+ * @throws IOException for zip/jar file handling exception.
+ */
+ private static InputStream getConfigFileInputStream(final String typeId) throws IOException {
+ try {
+ InputStream stream =
+ (InputStream)AccessController
+ .doPrivileged((java.security.PrivilegedExceptionAction) () -> {
+ String propFilename = "java.time.calendar.HijrahChrono.File." + typeId;
+ String filename = System.getProperty(propFilename);
+ File file = null;
+ if (filename != null) {
+ file = new File(filename);
+ } else {
+ String libDir = System.getProperty("java.home") + File.separator + "lib";
+ try {
+ libDir = FileSystems.getDefault().getPath(libDir).toRealPath().toString();
+ } catch(Exception e) {}
+ filename = DEFAULT_CONFIG_FILE_PREFIX + typeId + ".cfg";
+ file = new File(libDir, filename);
+ }
+
+ if (file.exists()) {
+ try {
+ return new FileInputStream(file);
+ } catch (IOException ioe) {
+ throw ioe;
+ }
+ } else {
+ return null;
+ }
+ });
+ return stream;
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ // Not working
+ return null;
+ }
+ }
+}
diff --git a/src/share/classes/java/time/calendar/HijrahEra.java b/src/share/classes/java/time/calendar/HijrahEra.java
new file mode 100644
index 0000000000000000000000000000000000000000..5c622f78e8e1a7f7f06ed037e75371b5dffe12d5
--- /dev/null
+++ b/src/share/classes/java/time/calendar/HijrahEra.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of JSR-310 nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.calendar;
+
+import static java.time.temporal.ChronoField.ERA;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.time.DateTimeException;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.TextStyle;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoLocalDate;
+import java.time.temporal.Era;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalField;
+import java.time.temporal.ValueRange;
+import java.util.Locale;
+
+/**
+ * An era in the Hijrah calendar system.
+ * Specification for implementors
+ * This is an immutable and thread-safe enum.
+ *
+ * @since 1.8
+ */
+enum HijrahEra implements EraSpecification for implementors
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class JapaneseChrono extends ChronoSpecification for implementors
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+final class JapaneseDate
+ extends ChronoDateImplSpecification for implementors
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+final class JapaneseEra
+ implements Era
+ *
Specification for implementors
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class MinguoChrono extends ChronoSpecification for implementors
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+final class MinguoDate
+ extends ChronoDateImplSpecification for implementors
+ * This is an immutable and thread-safe enum.
+ *
+ * @since 1.8
+ */
+enum MinguoEra implements EraImplementation notes
+ * This class wraps the object being serialized, and takes a byte representing the type of the class to
+ * be serialized. This byte can also be used for versioning the serialization format. In this case another
+ * byte flag would be used in order to specify an alternative version of the type format.
+ * For example {@code JAPANESE_DATE_TYPE_VERSION_2 = 21}.
+ *
+ *
Specification for implementors
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class ThaiBuddhistChrono extends ChronoSpecification for implementors
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+final class ThaiBuddhistDate
+ extends ChronoDateImplSpecification for implementors
+ * This is an immutable and thread-safe enum.
+ *
+ * @since 1.8
+ */
+enum ThaiBuddhistEra implements Era
+ *
+ * Example
+ *
+ * // Print the Thai Buddhist date
+ * ChronoLocalDate<ThaiBuddhistChrono> now1 = ThaiBuddhistChrono.INSTANCE.dateNow();
+ * int day = now1.get(ChronoField.DAY_OF_MONTH);
+ * int dow = now1.get(ChronoField.DAY_OF_WEEK);
+ * int month = now1.get(ChronoField.MONTH_OF_YEAR);
+ * int year = now1.get(ChronoField.YEAR);
+ * System.out.printf(" Today is %s %s %d-%s-%d%n", now1.getChrono().getId(),
+ * dow, day, month, year);
+ *
+ * // Enumerate the list of available calendars and print today for each
+ * Set<Chrono<?>> chronos = Chrono.getAvailableChronologies();
+ * for (Chrono<?> chrono : chronos) {
+ * ChronoLocalDate<?> date = chrono.dateNow();
+ * System.out.printf(" %20s: %s%n", chrono.getId(), date.toString());
+ * }
+ *
+ * // Print today's date and the last day of the year for the Thai Buddhist Calendar.
+ * ChronoLocalDate<ThaiBuddhistChrono> first = now1
+ * .with(ChronoField.DAY_OF_MONTH, 1)
+ * .with(ChronoField.MONTH_OF_YEAR, 1);
+ * ChronoLocalDate<ThaiBuddhistChrono> last = first
+ * .plus(1, ChronoUnit.YEARS)
+ * .minus(1, ChronoUnit.DAYS);
+ * System.out.printf(" %s: 1st of year: %s; end of year: %s%n", last.getChrono().getId(),
+ * first, last);
+ *
+ *
+ * Package specification
+ *
+ *
Specification for implementors
+ * This class is mutable and not thread-safe.
+ * It should only be used from a single thread.
+ *
+ * @since 1.8
+ */
+public final class DateTimeBuilder
+ implements TemporalAccessor, Cloneable {
+
+ /**
+ * The map of other fields.
+ */
+ private Map