OpenJDK / jdk / jdk
changeset 15982:c47c078f91b8
Merge
author | lana |
---|---|
date | Tue, 19 Feb 2013 22:23:34 -0800 |
parents | 6a17b454c6db c6c397d4cbac |
children | 26a673dec5b2 3e009b5be123 |
files | jdk/src/share/classes/java/time/PeriodParser.java jdk/src/share/classes/java/time/calendar/ChronoDateImpl.java jdk/src/share/classes/java/time/calendar/HijrahChrono.java jdk/src/share/classes/java/time/calendar/HijrahDate.java jdk/src/share/classes/java/time/calendar/HijrahDeviationReader.java jdk/src/share/classes/java/time/calendar/HijrahEra.java jdk/src/share/classes/java/time/calendar/JapaneseChrono.java jdk/src/share/classes/java/time/calendar/JapaneseDate.java jdk/src/share/classes/java/time/calendar/JapaneseEra.java jdk/src/share/classes/java/time/calendar/MinguoChrono.java jdk/src/share/classes/java/time/calendar/MinguoDate.java jdk/src/share/classes/java/time/calendar/MinguoEra.java jdk/src/share/classes/java/time/calendar/Ser.java jdk/src/share/classes/java/time/calendar/ThaiBuddhistChrono.java jdk/src/share/classes/java/time/calendar/ThaiBuddhistDate.java jdk/src/share/classes/java/time/calendar/ThaiBuddhistEra.java jdk/src/share/classes/java/time/calendar/package-info.java jdk/src/share/classes/java/time/format/DateTimeFormatters.java jdk/src/share/classes/java/time/format/DateTimePrintException.java jdk/src/share/classes/java/time/temporal/Chrono.java jdk/src/share/classes/java/time/temporal/ChronoLocalDate.java jdk/src/share/classes/java/time/temporal/ChronoLocalDateTime.java jdk/src/share/classes/java/time/temporal/ChronoLocalDateTimeImpl.java jdk/src/share/classes/java/time/temporal/ChronoZonedDateTime.java jdk/src/share/classes/java/time/temporal/ChronoZonedDateTimeImpl.java jdk/src/share/classes/java/time/temporal/Era.java jdk/src/share/classes/java/time/temporal/ISOChrono.java jdk/src/share/classes/java/time/temporal/ISOEra.java jdk/src/share/classes/java/time/temporal/ISOFields.java jdk/src/share/classes/java/time/temporal/MonthDay.java jdk/src/share/classes/java/time/temporal/OffsetDate.java jdk/src/share/classes/java/time/temporal/OffsetDateTime.java jdk/src/share/classes/java/time/temporal/OffsetTime.java jdk/src/share/classes/java/time/temporal/Ser.java jdk/src/share/classes/java/time/temporal/SimplePeriod.java jdk/src/share/classes/java/time/temporal/TemporalAdder.java jdk/src/share/classes/java/time/temporal/TemporalSubtractor.java jdk/src/share/classes/java/time/temporal/Year.java jdk/src/share/classes/java/time/temporal/YearMonth.java jdk/src/share/classes/sun/util/calendar/TzIDOldMapping.java jdk/test/java/time/META-INF/services/java.time.temporal.Chrono jdk/test/java/time/tck/java/time/calendar/CopticChrono.java jdk/test/java/time/tck/java/time/calendar/CopticDate.java jdk/test/java/time/tck/java/time/calendar/CopticEra.java jdk/test/java/time/tck/java/time/calendar/TestChronoLocalDate.java jdk/test/java/time/tck/java/time/calendar/TestChronoLocalDateTime.java jdk/test/java/time/tck/java/time/calendar/TestHijrahChrono.java jdk/test/java/time/tck/java/time/calendar/TestJapaneseChrono.java jdk/test/java/time/tck/java/time/calendar/TestMinguoChrono.java jdk/test/java/time/tck/java/time/calendar/TestServiceLoader.java jdk/test/java/time/tck/java/time/calendar/TestThaiBuddhistChrono.java jdk/test/java/time/tck/java/time/format/TCKDateTimePrintException.java jdk/test/java/time/tck/java/time/temporal/TCKISOFields.java jdk/test/java/time/tck/java/time/temporal/TCKMonthDay.java jdk/test/java/time/tck/java/time/temporal/TCKOffsetDate.java jdk/test/java/time/tck/java/time/temporal/TCKOffsetDateTime.java jdk/test/java/time/tck/java/time/temporal/TCKOffsetTime.java jdk/test/java/time/tck/java/time/temporal/TCKSimplePeriod.java jdk/test/java/time/tck/java/time/temporal/TCKYear.java jdk/test/java/time/tck/java/time/temporal/TCKYearMonth.java jdk/test/java/time/tck/java/time/temporal/TestChrono.java jdk/test/java/time/tck/java/time/temporal/TestISOChrono.java jdk/test/java/time/test/java/time/TestPeriodParser.java jdk/test/java/time/test/java/time/format/TestDateTimeFormatters.java jdk/test/java/time/test/java/time/format/TestDateTimePrintException.java jdk/test/java/time/test/java/time/format/TestPadParserDecorator.java jdk/test/java/time/test/java/time/format/TestZoneIdParser.java jdk/test/java/time/test/java/time/temporal/TestISOChronoImpl.java jdk/test/java/time/test/java/time/temporal/TestMonthDay.java jdk/test/java/time/test/java/time/temporal/TestOffsetDate.java jdk/test/java/time/test/java/time/temporal/TestOffsetDateTime.java jdk/test/java/time/test/java/time/temporal/TestOffsetDateTime_instants.java jdk/test/java/time/test/java/time/temporal/TestOffsetTime.java jdk/test/java/time/test/java/time/temporal/TestYear.java jdk/test/java/time/test/java/time/temporal/TestYearMonth.java |
diffstat | 479 files changed, 74456 insertions(+), 42805 deletions(-) [+] |
line wrap: on
line diff
--- a/jdk/.hgtags Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/.hgtags Tue Feb 19 22:23:34 2013 -0800 @@ -198,3 +198,4 @@ 57d5d954462831ac353a1f40d3bb05ddb4620952 jdk8-b74 4a67fdb752b7d6329d9be9c28d3f9d6cf7eb9a3c jdk8-b75 3a263052866137b645ab86498a43693ff5c19e69 jdk8-b76 +b2fc8e31cecc35b76188e821d4c5dc0e0b74ac24 jdk8-b77
--- a/jdk/make/docs/CORE_PKGS.gmk Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/make/docs/CORE_PKGS.gmk Tue Feb 19 22:23:34 2013 -0800 @@ -128,9 +128,9 @@ java.text \ java.text.spi \ java.time \ + java.time.chrono \ + java.time.format \ java.time.temporal \ - java.time.calendar \ - java.time.format \ java.time.zone \ java.util \ java.util.concurrent \
--- a/jdk/make/java/java/FILES_java.gmk Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/make/java/java/FILES_java.gmk Tue Feb 19 22:23:34 2013 -0800 @@ -255,7 +255,6 @@ java/util/SimpleTimeZone.java \ sun/util/calendar/ZoneInfo.java \ sun/util/calendar/ZoneInfoFile.java \ - sun/util/calendar/TzIDOldMapping.java \ java/util/TooManyListenersException.java \ java/util/Comparator.java \ java/util/Collections.java \ @@ -389,6 +388,7 @@ java/util/concurrent/locks/ReadWriteLock.java \ java/util/concurrent/locks/ReentrantLock.java \ java/util/concurrent/locks/ReentrantReadWriteLock.java \ + java/util/concurrent/locks/StampedLock.java \ java/util/regex/Pattern.java \ java/util/regex/Matcher.java \ java/util/regex/MatchResult.java \
--- a/jdk/make/jprt.properties Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/make/jprt.properties Tue Feb 19 22:23:34 2013 -0800 @@ -63,6 +63,7 @@ ${jprt.my.test.target.set:TESTNAME=jvm98} # Default jdk test targets (testset=default) +# NOTE: This does not match test/Makefile :: jdk_default jprt.make.rule.default.test.targets= \ ${jprt.my.test.target.set:TESTNAME=jdk_lang}, \ ${jprt.my.test.target.set:TESTNAME=jdk_math} @@ -72,6 +73,7 @@ ${jprt.vm.default.test.targets} # Core jdk test targets (testset=core) +# NOTE: please keep this in sync with test/Makefile :: jdk_core jprt.make.rule.core.test.targets= \ ${jprt.make.rule.default.test.targets}, \ ${jprt.my.test.target.set:TESTNAME=jdk_util}, \ @@ -97,6 +99,7 @@ ${jprt.my.test.target.set:TESTNAME=jbb_default} # All jdk test targets (testset=all) +# NOTE: This does not match test/Makefile :: jdk_all jprt.make.rule.all.test.targets= \ ${jprt.make.rule.core.test.targets}, \ ${jprt.my.test.target.set:TESTNAME=jdk_awt}, \
--- a/jdk/make/sun/Makefile Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/make/sun/Makefile Tue Feb 19 22:23:34 2013 -0800 @@ -70,7 +70,7 @@ endif # nio need to be compiled before awt to have all charsets ready -SUBDIRS = jar security javazic misc net nio text util launcher cldr tzdb +SUBDIRS = jar security misc net nio text util launcher cldr tzdb ifdef BUILD_HEADLESS_ONLY DISPLAY_LIBS = awt $(HEADLESS_SUBDIR)
--- a/jdk/make/sun/javazic/Makefile Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/make/sun/javazic/Makefile Tue Feb 19 22:23:34 2013 -0800 @@ -33,11 +33,11 @@ # Time zone data file creation TZDATA = ./tzdata/ -TZDATA_VER = `$(GREP) '^tzdata' $(TZDATA)VERSION` +TZDATA_VER := $(shell $(GREP) '^tzdata' $(TZDATA)VERSION) TZFILE = \ africa antarctica asia australasia europe northamerica \ pacificnew southamerica backward \ - etcetera solar87 solar88 solar89 systemv + etcetera systemv JDKTZDATA = ./tzdata_jdk/ JDKTZFILES = gmt jdk11_backward TZFILES = \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/make/sun/javazic/tzdata/gmt Tue Feb 19 22:23:34 2013 -0800 @@ -0,0 +1,27 @@ +# +# Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# Zone NAME GMTOFF RULES FORMAT [UNTIL] +Zone GMT 0:00 - GMT
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/make/sun/javazic/tzdata/jdk11_backward Tue Feb 19 22:23:34 2013 -0800 @@ -0,0 +1,51 @@ +# +# Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# JDK 1.1.x compatible time zone IDs +# + +# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S +Rule SystemV min 1973 - Apr lastSun 2:00 1:00 D +Rule SystemV min 1973 - Oct lastSun 2:00 0 S +Rule SystemV 1974 only - Jan 6 2:00 1:00 D +Rule SystemV 1974 only - Nov lastSun 2:00 0 S +Rule SystemV 1975 only - Feb 23 2:00 1:00 D +Rule SystemV 1975 only - Oct lastSun 2:00 0 S +Rule SystemV 1976 max - Apr lastSun 2:00 1:00 D +Rule SystemV 1976 max - Oct lastSun 2:00 0 S + +# Zone NAME GMTOFF RULES/SAVE FORMAT [UNTIL] +Zone SystemV/AST4ADT -4:00 SystemV A%sT +Zone SystemV/EST5EDT -5:00 SystemV E%sT +Zone SystemV/CST6CDT -6:00 SystemV C%sT +Zone SystemV/MST7MDT -7:00 SystemV M%sT +Zone SystemV/PST8PDT -8:00 SystemV P%sT +Zone SystemV/YST9YDT -9:00 SystemV Y%sT +Zone SystemV/AST4 -4:00 - AST +Zone SystemV/EST5 -5:00 - EST +Zone SystemV/CST6 -6:00 - CST +Zone SystemV/MST7 -7:00 - MST +Zone SystemV/PST8 -8:00 - PST +Zone SystemV/YST9 -9:00 - YST +Zone SystemV/HST10 -10:00 - HST
--- a/jdk/make/sun/tzdb/Makefile Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/make/sun/tzdb/Makefile Tue Feb 19 22:23:34 2013 -0800 @@ -43,9 +43,15 @@ # TZDATA_DIR := ../javazic/tzdata TZDATA_VER := $(subst tzdata,,$(shell $(GREP) '^tzdata' $(TZDATA_DIR)/VERSION)) -TZFILE := africa antarctica asia australasia europe northamerica southamerica backward etcetera +TZFILE := \ + africa antarctica asia australasia europe northamerica \ + pacificnew southamerica backward etcetera \ + gmt jdk11_backward + TZFILES := $(addprefix $(TZDATA_DIR)/,$(TZFILE)) + + TZDB_JAR = tzdb.jar # @@ -61,7 +67,7 @@ $(LIBDIR)/$(TZDB_JAR): $(TZFILES) $(prep-target) echo build tzdb from version $(TZDATA_VER) - $(BOOT_JAVA_CMD) -jar $(BUILDTOOLJARDIR)/tzdb.jar -verbose \ + $(BOOT_JAVA_CMD) -jar $(BUILDTOOLJARDIR)/tzdb.jar \ -version $(TZDATA_VER) -srcdir $(TZDATA_DIR) -dstdir $(LIBDIR) $(TZFILE) clean clobber::
--- a/jdk/make/tools/Makefile Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/make/tools/Makefile Tue Feb 19 22:23:34 2013 -0800 @@ -48,7 +48,6 @@ hasher_classes \ jarreorder \ jarsplit \ - javazic \ jdwpgen \ makeclasslist \ strip_properties \
--- a/jdk/make/tools/src/build/tools/javazic/Zoneinfo.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/make/tools/src/build/tools/javazic/Zoneinfo.java Tue Feb 19 22:23:34 2013 -0800 @@ -490,11 +490,16 @@ tz.addUsedRec(rrec); usedZone = true; } - } else { + } else { // fromTime == minTime int save = rrec.getSave(); - tz.addTransition(fromTime, + tz.addTransition(minTime, + tz.getOffsetIndex(gmtOffset), + tz.getDstOffsetIndex(0)); + + tz.addTransition(transition, tz.getOffsetIndex(gmtOffset+save), tz.getDstOffsetIndex(save)); + tz.addUsedRec(rrec); usedZone = true; }
--- a/jdk/make/tools/src/build/tools/tzdb/TzdbZoneRulesCompiler.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/make/tools/src/build/tools/tzdb/TzdbZoneRulesCompiler.java Tue Feb 19 22:23:34 2013 -0800 @@ -227,6 +227,7 @@ Map<String, SortedMap<String, ZoneRules>> allBuiltZones = new TreeMap<>(); Set<String> allRegionIds = new TreeSet<String>(); Set<ZoneRules> allRules = new HashSet<ZoneRules>(); + Map<String, Map<String, String>> allLinks = new TreeMap<>(); for (File srcDir : srcDirs) { // source files in this directory @@ -242,7 +243,8 @@ } // compile - String loopVersion = srcDir.getName(); + String loopVersion = (srcDirs.size() == 1 && version != null) + ? version : srcDir.getName(); TzdbZoneRulesCompiler compiler = new TzdbZoneRulesCompiler(loopVersion, srcFiles, verbose); try { // compile @@ -255,12 +257,13 @@ if (verbose) { System.out.println("Outputting file: " + dstFile); } - outputFile(dstFile, loopVersion, builtZones); + outputFile(dstFile, loopVersion, builtZones, compiler.links); // create totals allBuiltZones.put(loopVersion, builtZones); allRegionIds.addAll(builtZones.keySet()); allRules.addAll(builtZones.values()); + allLinks.put(loopVersion, compiler.links); } catch (Exception ex) { System.out.println("Failed: " + ex.toString()); ex.printStackTrace(); @@ -274,7 +277,7 @@ if (verbose) { System.out.println("Outputting combined file: " + dstFile); } - outputFile(dstFile, allBuiltZones, allRegionIds, allRules); + outputFile(dstFile, allBuiltZones, allRegionIds, allRules, allLinks); } } @@ -283,12 +286,15 @@ */ private static void outputFile(File dstFile, String version, - SortedMap<String, ZoneRules> builtZones) { + SortedMap<String, ZoneRules> builtZones, + Map<String, String> links) { Map<String, SortedMap<String, ZoneRules>> loopAllBuiltZones = new TreeMap<>(); loopAllBuiltZones.put(version, builtZones); Set<String> loopAllRegionIds = new TreeSet<String>(builtZones.keySet()); Set<ZoneRules> loopAllRules = new HashSet<ZoneRules>(builtZones.values()); - outputFile(dstFile, loopAllBuiltZones, loopAllRegionIds, loopAllRules); + Map<String, Map<String, String>> loopAllLinks = new TreeMap<>(); + loopAllLinks.put(version, links); + outputFile(dstFile, loopAllBuiltZones, loopAllRegionIds, loopAllRules, loopAllLinks); } /** @@ -297,10 +303,10 @@ private static void outputFile(File dstFile, Map<String, SortedMap<String, ZoneRules>> allBuiltZones, Set<String> allRegionIds, - Set<ZoneRules> allRules) - { + Set<ZoneRules> allRules, + Map<String, Map<String, String>> allLinks) { try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(dstFile))) { - outputTZEntry(jos, allBuiltZones, allRegionIds, allRules); + outputTZEntry(jos, allBuiltZones, allRegionIds, allRules, allLinks); } catch (Exception ex) { System.out.println("Failed: " + ex.toString()); ex.printStackTrace(); @@ -314,7 +320,8 @@ private static void outputTZEntry(JarOutputStream jos, Map<String, SortedMap<String, ZoneRules>> allBuiltZones, Set<String> allRegionIds, - Set<ZoneRules> allRules) { + Set<ZoneRules> allRules, + Map<String, Map<String, String>> allLinks) { // this format is not publicly specified try { jos.putNextEntry(new ZipEntry("TZDB.dat")); @@ -359,6 +366,16 @@ out.writeShort(rulesIndex); } } + // alias-region + for (String version : allLinks.keySet()) { + out.writeShort(allLinks.get(version).size()); + for (Map.Entry<String, String> entry : allLinks.get(version).entrySet()) { + int aliasIndex = Arrays.binarySearch(regionArray, entry.getKey()); + int regionIndex = Arrays.binarySearch(regionArray, entry.getValue()); + out.writeShort(aliasIndex); + out.writeShort(regionIndex); + } + } out.flush(); jos.closeEntry(); } catch (Exception ex) { @@ -621,7 +638,8 @@ private int parseYear(String str, int defaultYear) { if (YEAR.reset(str).matches()) { if (YEAR.group("min") != null) { - return YEAR_MIN_VALUE; + //return YEAR_MIN_VALUE; + return 1900; // systemv has min } else if (YEAR.group("max") != null) { return YEAR_MAX_VALUE; } else if (YEAR.group("only") != null) { @@ -742,16 +760,20 @@ if (realRules == null) { throw new IllegalArgumentException("Alias '" + aliasId + "' links to invalid zone '" + realId + "' for '" + version + "'"); } + links.put(aliasId, realId); + } builtZones.put(aliasId, realRules); } // remove UTC and GMT - builtZones.remove("UTC"); - builtZones.remove("GMT"); - builtZones.remove("GMT0"); + //builtZones.remove("UTC"); + //builtZones.remove("GMT"); + //builtZones.remove("GMT0"); builtZones.remove("GMT+0"); builtZones.remove("GMT-0"); + links.remove("GMT+0"); + links.remove("GMT-0"); } //----------------------------------------------------------------------- @@ -785,7 +807,6 @@ boolean endOfDay; /** The time of the cutover. */ TimeDefinition timeDefinition = TimeDefinition.WALL; - void adjustToFowards(int year) { if (adjustForwards == false && dayOfMonth > 0) { LocalDate adjustedDate = LocalDate.of(year, month, dayOfMonth).minusDays(6);
--- a/jdk/makefiles/GendataTZDB.gmk Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/makefiles/GendataTZDB.gmk Tue Feb 19 22:23:34 2013 -0800 @@ -30,7 +30,7 @@ # TZDATA_DIR := $(JDK_TOPDIR)/make/sun/javazic/tzdata TZDATA_VER := $(subst tzdata,,$(shell $(GREP) '^tzdata' $(TZDATA_DIR)/VERSION)) -TZDATA_TZFILE := africa antarctica asia australasia europe northamerica southamerica backward etcetera +TZDATA_TZFILE := africa antarctica asia australasia europe northamerica pacificnew southamerica backward etcetera gmt jdk11_backward TZDATA_TZFILES := $(addprefix $(TZDATA_DIR)/,$(TZDATA_TZFILE)) GENDATA_TZDB_DST := $(JDK_OUTPUTDIR)/lib @@ -39,6 +39,6 @@ $(GENDATA_TZDB_DST)/$(GENDATA_TZDB_JAR) : $(TZDATA_TZFILES) $(RM) $(GENDATA_TZDB_DST)/$(GENDATA_TZDB_JAR) echo building tzdb from version $(TZDATA_VER) - $(TOOL_TZDB) -verbose -version $(TZDATA_VER) -srcdir $(TZDATA_DIR) -dstdir $(GENDATA_TZDB_DST) $(TZDATA_TZFILE) + $(TOOL_TZDB) -version $(TZDATA_VER) -srcdir $(TZDATA_DIR) -dstdir $(GENDATA_TZDB_DST) $(TZDATA_TZFILE) GENDATA_TZDB += $(GENDATA_TZDB_DST)/$(GENDATA_TZDB_JAR)
--- a/jdk/makefiles/GendataTimeZone.gmk Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/makefiles/GendataTimeZone.gmk Tue Feb 19 22:23:34 2013 -0800 @@ -34,7 +34,7 @@ TZFILE0 := \ africa antarctica asia australasia europe northamerica \ pacificnew southamerica backward \ - etcetera solar87 solar88 solar89 systemv + etcetera systemv TZFILE1 := \ gmt jdk11_backward
--- a/jdk/makefiles/GenerateData.gmk Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/makefiles/GenerateData.gmk Tue Feb 19 22:23:34 2013 -0800 @@ -44,9 +44,6 @@ include GendataFontConfig.gmk GENDATA += $(GENDATA_FONT_CONFIG) -include GendataTimeZone.gmk -GENDATA += $(GENDATA_TIMEZONE) - include GendataTZDB.gmk GENDATA += $(GENDATA_TZDB)
--- a/jdk/makefiles/Tools.gmk Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/makefiles/Tools.gmk Tue Feb 19 22:23:34 2013 -0800 @@ -103,9 +103,6 @@ TOOL_JARSPLIT=$(JAVA) -cp $(JDK_OUTPUTDIR)/btclasses \ build.tools.jarsplit.JarSplit -TOOL_JAVAZIC=$(JAVA) -cp $(JDK_OUTPUTDIR)/btclasses \ - build.tools.javazic.Main - TOOL_TZDB=$(JAVA) -cp $(JDK_OUTPUTDIR)/btclasses \ build.tools.tzdb.TzdbZoneRulesCompiler
--- a/jdk/src/macosx/native/jobjc/src/core/native/SEL.m Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/macosx/native/jobjc/src/core/native/SEL.m Tue Feb 19 22:23:34 2013 -0800 @@ -34,7 +34,7 @@ const char *selNameAsChars = (*env)->GetStringUTFChars(env, selName, JNI_FALSE); const SEL sel = sel_registerName(selNameAsChars); (*env)->ReleaseStringUTFChars(env, selName, selNameAsChars); - return ptr_to_jlong(sel); + return ptr_to_jlong((void*)sel); } JNIEXPORT jstring JNICALL Java_com_apple_jobjc_SEL_getSelectorName
--- a/jdk/src/share/bin/parse_manifest.c Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/bin/parse_manifest.c Tue Feb 19 22:23:34 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -106,8 +106,9 @@ *size_out = (int)entry->isize; } return (out); - } else - return (NULL); + } + free(in); + return (NULL); } static jboolean zip64_present = JNI_FALSE; @@ -563,7 +564,7 @@ if ((fd = open(jarfile, O_RDONLY #ifdef O_LARGEFILE - | O_LARGEFILE /* large file mode on solaris */ + | O_LARGEFILE /* large file mode */ #endif #ifdef O_BINARY | O_BINARY /* use binary mode on windows */ @@ -618,6 +619,9 @@ void *data = NULL; fd = open(jarfile, O_RDONLY +#ifdef O_LARGEFILE + | O_LARGEFILE /* large file mode */ +#endif #ifdef O_BINARY | O_BINARY /* use binary mode on windows */ #endif @@ -661,6 +665,9 @@ int rc; if ((fd = open(jarfile, O_RDONLY +#ifdef O_LARGEFILE + | O_LARGEFILE /* large file mode */ +#endif #ifdef O_BINARY | O_BINARY /* use binary mode on windows */ #endif
--- a/jdk/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java Tue Feb 19 22:23:34 2013 -0800 @@ -52,16 +52,19 @@ * principal set and private credentials set are updated only when * <code>commit</code> is called. * When <code>commit</code> is called, the <code>KerberosPrincipal</code> - * is added to the <code>Subject</code>'s - * principal set and <code>KerberosTicket</code> is + * is added to the <code>Subject</code>'s principal set (unless the + * <code>principal</code> is specified as "*"). If <code>isInitiator</code> + * is true, the <code>KerberosTicket</code> is * added to the <code>Subject</code>'s private credentials. * * <p> If the configuration entry for <code>KerberosLoginModule</code> * has the option <code>storeKey</code> set to true, then - * <code>KerberosKey</code> will also be added to the + * <code>KerberosKey</code> or <code>KeyTab</code> will also be added to the * subject's private credentials. <code>KerberosKey</code>, the principal's - * key will be either obtained from the keytab or - * derived from user's password. + * key(s) will be derived from user's password, and <code>KeyTab</code> is + * the keytab used when <code>useKeyTab</code> is set to true. The + * <code>KeyTab</code> object is restricted to be used by the specified + * principal unless the principal value is "*". * * <p> This <code>LoginModule</code> recognizes the <code>doNotPrompt</code> * option. If set to true the user will not be prompted for the password. @@ -75,8 +78,8 @@ * * <p> The principal name can be specified in the configuration entry * by using the option <code>principal</code>. The principal name - * can either be a simple user name or a service name such as - * <code>host/mission.eng.sun.com</code>. The principal can also + * can either be a simple user name, a service name such as + * <code>host/mission.eng.sun.com</code>, or "*". The principal can also * be set using the system property <code>sun.security.krb5.principal</code>. * This property is checked during login. If this property is not set, then * the principal name from the configuration is used. In the @@ -87,11 +90,10 @@ * * <p> The following is a list of configuration options supported * for <code>Krb5LoginModule</code>: - * <dl> - * <blockquote><dt><b><code>refreshKrb5Config</code></b>:</dt> + * <blockquote><dl> + * <dt><b><code>refreshKrb5Config</code></b>:</dt> * <dd> Set this to true, if you want the configuration * to be refreshed before the <code>login</code> method is called.</dd> - * <P> * <dt><b><code>useTicketCache</code></b>:</dt> * <dd>Set this to true, if you want the * TGT to be obtained @@ -112,19 +114,16 @@ * <code>ticketCache</code>. * For Windows, if a ticket cannot be retrieved from the file ticket cache, * it will use Local Security Authority (LSA) API to get the TGT. - * <P> * <dt><b><code>ticketCache</code></b>:</dt> * <dd>Set this to the name of the ticket * cache that contains user's TGT. * If this is set, <code>useTicketCache</code> * must also be set to true; Otherwise a configuration error will * be returned.</dd> - * <P> * <dt><b><code>renewTGT</code></b>:</dt> * <dd>Set this to true, if you want to renew * the TGT. If this is set, <code>useTicketCache</code> must also be * set to true; otherwise a configuration error will be returned.</dd> - * <p> * <dt><b><code>doNotPrompt</code></b>:</dt> * <dd>Set this to true if you do not want to be * prompted for the password @@ -132,7 +131,6 @@ * or through shared state.(Default is false) * If set to true, credential must be obtained through cache, keytab, * or shared state. Otherwise, authentication will fail.</dd> - * <P> * <dt><b><code>useKeyTab</code></b>:</dt> * <dd>Set this to true if you * want the module to get the principal's key from the @@ -144,15 +142,15 @@ * If it is not specified in the Kerberos configuration file * then it will look for the file * <code>{user.home}{file.separator}</code>krb5.keytab.</dd> - * <P> * <dt><b><code>keyTab</code></b>:</dt> * <dd>Set this to the file name of the * keytab to get principal's secret key.</dd> - * <P> * <dt><b><code>storeKey</code></b>:</dt> - * <dd>Set this to true to if you want the - * principal's key to be stored in the Subject's private credentials. </dd> - * <p> + * <dd>Set this to true to if you want the keytab or the + * principal's key to be stored in the Subject's private credentials. + * For <code>isInitiator</code> being false, if <code>principal</code> + * is "*", the {@link KeyTab} stored can be used by anyone, otherwise, + * it's restricted to be used by the specified principal only.</dd> * <dt><b><code>principal</code></b>:</dt> * <dd>The name of the principal that should * be used. The principal can be a simple username such as @@ -165,8 +163,13 @@ * <code>sun.security.krb5.principal</code>. In addition, if this * system property is defined, then it will be used. If this property * is not set, then the principal name from the configuration will be - * used.</dd> - * <P> + * used. + * The principal name can be set to "*" when <code>isInitiator</code> is false. + * In this case, the acceptor is not bound to a single principal. It can + * act as any principal an initiator requests if keys for that principal + * can be found. When <code>isInitiator</code> is true, the principal name + * cannot be set to "*". + * </dd> * <dt><b><code>isInitiator</code></b>:</dt> * <dd>Set this to true, if initiator. Set this to false, if acceptor only. * (Default is true). @@ -177,18 +180,20 @@ * <code>Configuration</code> * options that enable you to share username and passwords across different * authentication modules: - * <pre> + * <blockquote><dl> * - * useFirstPass if, true, this LoginModule retrieves the + * <dt><b><code>useFirstPass</code></b>:</dt> + * <dd>if, true, this LoginModule retrieves the * username and password from the module's shared state, * using "javax.security.auth.login.name" and * "javax.security.auth.login.password" as the respective * keys. The retrieved values are used for authentication. * If authentication fails, no attempt for a retry * is made, and the failure is reported back to the - * calling application. + * calling application.</dd> * - * tryFirstPass if, true, this LoginModule retrieves the + * <dt><b><code>tryFirstPass</code></b>:</dt> + * <dd>if, true, this LoginModule retrieves the * the username and password from the module's shared * state using "javax.security.auth.login.name" and * "javax.security.auth.login.password" as the respective @@ -198,26 +203,28 @@ * CallbackHandler to retrieve a new username * and password, and another attempt to authenticate * is made. If the authentication fails, - * the failure is reported back to the calling application + * the failure is reported back to the calling application</dd> * - * storePass if, true, this LoginModule stores the username and + * <dt><b><code>storePass</code></b>:</dt> + * <dd>if, true, this LoginModule stores the username and * password obtained from the CallbackHandler in the * modules shared state, using * "javax.security.auth.login.name" and * "javax.security.auth.login.password" as the respective * keys. This is not performed if existing values already * exist for the username and password in the shared - * state, or if authentication fails. + * state, or if authentication fails.</dd> * - * clearPass if, true, this LoginModule clears the + * <dt><b><code>clearPass</code></b>:</dt> + * <dd>if, true, this LoginModule clears the * username and password stored in the module's shared * state after both phases of authentication - * (login and commit) have completed. - * </pre> + * (login and commit) have completed.</dd> + * </dl></blockquote> * <p>If the principal system property or key is already provided, the value of * "javax.security.auth.login.name" in the shared state is ignored. * <p>When multiple mechanisms to retrieve a ticket or key is provided, the - * preference order looks like this: + * preference order is: * <ol> * <li>ticket cache * <li>keytab @@ -225,7 +232,7 @@ * <li>user prompt * </ol> * <p>Note that if any step fails, it will fallback to the next step. - * There's only one exception, it the shared state step fails and + * There's only one exception, if the shared state step fails and * <code>useFirstPass</code>=true, no user prompt is made. * <p>Examples of some configuration values for Krb5LoginModule in * JAAS config file and the results are: @@ -318,7 +325,7 @@ * <p> <code>useKeyTab</code> = true * <code>keyTab</code>=<keytabname> * <code>storeKey</code>=true - * <code>doNotPrompt</code>=true; + * <code>doNotPrompt</code>=false; *</ul> * <p>The user will be prompted for the service principal name. * If the principal's @@ -328,6 +335,14 @@ * If successful the TGT will be added to the * Subject's private credentials set. Otherwise the authentication will * fail. + * <ul> + * <p> <code>isInitiator</code> = false <code>useKeyTab</code> = true + * <code>keyTab</code>=<keytabname> + * <code>storeKey</code>=true + * <code>principal</code>=*; + *</ul> + * <p>The acceptor will be an unbound acceptor and it can act as any principal + * as long that principal has keys in the keytab. *<ul> * <p> * <code>useTicketCache</code>=true @@ -409,6 +424,7 @@ private KerberosTicket kerbTicket = null; private KerberosKey[] kerbKeys = null; private StringBuffer krb5PrincName = null; + private boolean unboundServer = false; private char[] password = null; private static final String NAME = "javax.security.auth.login.name"; @@ -520,8 +536,6 @@ */ public boolean login() throws LoginException { - int len; - validateConfiguration(); if (refreshKrb5Config) { try { if (debug) { @@ -544,6 +558,12 @@ } } + validateConfiguration(); + + if (krb5PrincName != null && krb5PrincName.toString().equals("*")) { + unboundServer = true; + } + if (tryFirstPass) { try { attemptAuthentication(true); @@ -698,9 +718,17 @@ * (encKeys == null) to check. */ if (useKeyTab) { - ktab = (keyTabName == null) - ? KeyTab.getInstance() - : KeyTab.getInstance(new File(keyTabName)); + if (!unboundServer) { + KerberosPrincipal kp = + new KerberosPrincipal(principal.getName()); + ktab = (keyTabName == null) + ? KeyTab.getInstance(kp) + : KeyTab.getInstance(kp, new File(keyTabName)); + } else { + ktab = (keyTabName == null) + ? KeyTab.getUnboundInstance() + : KeyTab.getUnboundInstance(new File(keyTabName)); + } if (isInitiator) { if (Krb5Util.keysFromJavaxKeyTab(ktab, principal).length == 0) { @@ -939,6 +967,13 @@ ("Configuration Error" + " - either useTicketCache should be " + " true or renewTGT should be false"); + if (krb5PrincName != null && krb5PrincName.toString().equals("*")) { + if (isInitiator) { + throw new LoginException + ("Configuration Error" + + " - principal cannot be * when isInitiator is true"); + } + } } private boolean isCurrent(Credentials creds) @@ -1052,7 +1087,10 @@ } // Let us add the kerbClientPrinc,kerbTicket and KeyTab/KerbKey (if // storeKey is true) - if (!princSet.contains(kerbClientPrinc)) { + + // We won't add "*" as a KerberosPrincipal + if (!unboundServer && + !princSet.contains(kerbClientPrinc)) { princSet.add(kerbClientPrinc); }
--- a/jdk/src/share/classes/com/sun/security/ntlm/Client.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/com/sun/security/ntlm/Client.java Tue Feb 19 22:23:34 2013 -0800 @@ -138,8 +138,7 @@ domain = domainFromServer; } if (domain == null) { - throw new NTLMException(NTLMException.NO_DOMAIN_INFO, - "No domain info"); + domain = ""; } int flags = 0x88200 | (inputFlags & 3);
--- a/jdk/src/share/classes/com/sun/security/ntlm/NTLM.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/com/sun/security/ntlm/NTLM.java Tue Feb 19 22:23:34 2013 -0800 @@ -136,10 +136,10 @@ int readInt(int offset) throws NTLMException { try { - return internal[offset] & 0xff + - (internal[offset+1] & 0xff << 8) + - (internal[offset+2] & 0xff << 16) + - (internal[offset+3] & 0xff << 24); + return (internal[offset] & 0xff) + + ((internal[offset+1] & 0xff) << 8) + + ((internal[offset+2] & 0xff) << 16) + + ((internal[offset+3] & 0xff) << 24); } catch (ArrayIndexOutOfBoundsException ex) { throw new NTLMException(NTLMException.PACKET_READ_ERROR, "Input message incorrect size"); @@ -148,8 +148,8 @@ int readShort(int offset) throws NTLMException { try { - return internal[offset] & 0xff + - (internal[offset+1] & 0xff << 8); + return (internal[offset] & 0xff) + + ((internal[offset+1] & 0xff << 8)); } catch (ArrayIndexOutOfBoundsException ex) { throw new NTLMException(NTLMException.PACKET_READ_ERROR, "Input message incorrect size");
--- a/jdk/src/share/classes/java/io/Closeable.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/io/Closeable.java Tue Feb 19 22:23:34 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ * * @since 1.5 */ - +@FunctionalInterface public interface Closeable extends AutoCloseable { /**
--- a/jdk/src/share/classes/java/io/FileFilter.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/io/FileFilter.java Tue Feb 19 22:23:34 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2002, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ * * @since 1.2 */ +@FunctionalInterface public interface FileFilter { /** @@ -46,5 +47,4 @@ * should be included */ boolean accept(File pathname); - }
--- a/jdk/src/share/classes/java/io/FilenameFilter.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/io/FilenameFilter.java Tue Feb 19 22:23:34 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,8 +39,8 @@ * @see java.io.File#list(java.io.FilenameFilter) * @since JDK1.0 */ -public -interface FilenameFilter { +@FunctionalInterface +public interface FilenameFilter { /** * Tests if a specified file should be included in a file list. *
--- a/jdk/src/share/classes/java/io/Flushable.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/io/Flushable.java Tue Feb 19 22:23:34 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ * * @since 1.5 */ - +@FunctionalInterface public interface Flushable { /**
--- a/jdk/src/share/classes/java/lang/AutoCloseable.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/lang/AutoCloseable.java Tue Feb 19 22:23:34 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ * @author Josh Bloch * @since 1.7 */ +@FunctionalInterface public interface AutoCloseable { /** * Closes this resource, relinquishing any underlying resources.
--- a/jdk/src/share/classes/java/lang/Class.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/lang/Class.java Tue Feb 19 22:23:34 2013 -0800 @@ -3087,7 +3087,8 @@ * @throws NullPointerException {@inheritDoc} * @since 1.8 */ - public <A extends Annotation> A[] getAnnotations(Class<A> annotationClass) { + @Override + public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationClass) { Objects.requireNonNull(annotationClass); initAnnotationsIfNecessary(); @@ -3106,6 +3107,7 @@ * @throws NullPointerException {@inheritDoc} * @since 1.8 */ + @Override @SuppressWarnings("unchecked") public <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass) { Objects.requireNonNull(annotationClass); @@ -3118,7 +3120,8 @@ * @throws NullPointerException {@inheritDoc} * @since 1.8 */ - public <A extends Annotation> A[] getDeclaredAnnotations(Class<A> annotationClass) { + @Override + public <A extends Annotation> A[] getDeclaredAnnotationsByType(Class<A> annotationClass) { Objects.requireNonNull(annotationClass); initAnnotationsIfNecessary();
--- a/jdk/src/share/classes/java/lang/Comparable.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/lang/Comparable.java Tue Feb 19 22:23:34 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -93,7 +93,7 @@ * @see java.util.Comparator * @since 1.2 */ - +@FunctionalInterface public interface Comparable<T> { /** * Compares this object with the specified object for order. Returns a
--- a/jdk/src/share/classes/java/lang/Iterable.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/lang/Iterable.java Tue Feb 19 22:23:34 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ * * @since 1.5 */ +@FunctionalInterface public interface Iterable<T> { /**
--- a/jdk/src/share/classes/java/lang/Package.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/lang/Package.java Tue Feb 19 22:23:34 2013 -0800 @@ -389,8 +389,9 @@ * @throws NullPointerException {@inheritDoc} * @since 1.8 */ - public <A extends Annotation> A[] getAnnotations(Class<A> annotationClass) { - return getPackageInfo().getAnnotations(annotationClass); + @Override + public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationClass) { + return getPackageInfo().getAnnotationsByType(annotationClass); } /** @@ -404,6 +405,7 @@ * @throws NullPointerException {@inheritDoc} * @since 1.8 */ + @Override public <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass) { return getPackageInfo().getDeclaredAnnotation(annotationClass); } @@ -412,8 +414,9 @@ * @throws NullPointerException {@inheritDoc} * @since 1.8 */ - public <A extends Annotation> A[] getDeclaredAnnotations(Class<A> annotationClass) { - return getPackageInfo().getDeclaredAnnotations(annotationClass); + @Override + public <A extends Annotation> A[] getDeclaredAnnotationsByType(Class<A> annotationClass) { + return getPackageInfo().getDeclaredAnnotationsByType(annotationClass); } /**
--- a/jdk/src/share/classes/java/lang/Readable.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/lang/Readable.java Tue Feb 19 22:23:34 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ * * @since 1.5 */ - +@FunctionalInterface public interface Readable { /** @@ -51,5 +51,4 @@ * @throws java.nio.ReadOnlyBufferException if cb is a read only buffer */ public int read(java.nio.CharBuffer cb) throws IOException; - }
--- a/jdk/src/share/classes/java/lang/Runnable.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/lang/Runnable.java Tue Feb 19 22:23:34 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,8 +52,8 @@ * @see java.util.concurrent.Callable * @since JDK1.0 */ -public -interface Runnable { +@FunctionalInterface +public interface Runnable { /** * When an object implementing interface <code>Runnable</code> is used * to create a thread, starting the thread causes the object's
--- a/jdk/src/share/classes/java/lang/Thread.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/lang/Thread.java Tue Feb 19 22:23:34 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1851,6 +1851,7 @@ * @see ThreadGroup#uncaughtException * @since 1.5 */ + @FunctionalInterface public interface UncaughtExceptionHandler { /** * Method invoked when the given thread terminates due to the
--- a/jdk/src/share/classes/java/lang/reflect/AccessibleObject.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/lang/reflect/AccessibleObject.java Tue Feb 19 22:23:34 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -184,7 +184,8 @@ * @throws NullPointerException {@inheritDoc} * @since 1.8 */ - public <T extends Annotation> T[] getAnnotations(Class<T> annotationClass) { + @Override + public <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) { throw new AssertionError("All subclasses should override this method"); } @@ -199,6 +200,7 @@ * @throws NullPointerException {@inheritDoc} * @since 1.8 */ + @Override public <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) { // Only annotations on classes are inherited, for all other // objects getDeclaredAnnotation is the same as @@ -210,11 +212,12 @@ * @throws NullPointerException {@inheritDoc} * @since 1.8 */ - public <T extends Annotation> T[] getDeclaredAnnotations(Class<T> annotationClass) { + @Override + public <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass) { // Only annotations on classes are inherited, for all other - // objects getDeclaredAnnotations is the same as - // getAnnotations. - return getAnnotations(annotationClass); + // objects getDeclaredAnnotationsByType is the same as + // getAnnotationsByType. + return getAnnotationsByType(annotationClass); } /**
--- a/jdk/src/share/classes/java/lang/reflect/AnnotatedElement.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedElement.java Tue Feb 19 22:23:34 2013 -0800 @@ -35,22 +35,43 @@ * arrays returned by accessors for array-valued enum members; it will * have no affect on the arrays returned to other callers. * - * <p>An annotation A is <em>directly present</em> on an element E if the - * RuntimeVisibleAnnotations or RuntimeVisibleParameterAnnotations attribute - * associated with E either: + * <p>The {@link #getAnnotationsByType(Class)} and {@link + * #getDeclaredAnnotationsByType(Class)} methods support multiple + * annotations of the same type on an element. If the argument to either method + * is a repeatable annotation type (JLS 9.6), then the method will "look + * through" a container annotation (JLS 9.7) which was generated at + * compile-time to wrap multiple annotations of the argument type. + * + * <p>The terms <em>directly present</em> and <em>present</em> are used + * throughout this interface to describe precisely which annotations are + * returned by methods: + * * <ul> - * <li>contains A; or - * <li>for invocations of get[Declared]Annotations(Class<T>), - * contains A or exactly one annotation C whose type is the containing - * annotation type of A's type (JLS 9.6) and whose value element contains A + * <li>An annotation A is <em>directly present</em> on an element E if E is + * associated with a RuntimeVisibleAnnotations or + * RuntimeVisibleParameterAnnotations attribute, and: + * + * <ul> + * <li>for an invocation of {@code get[Declared]Annotation(Class<T>)} or + * {@code get[Declared]Annotations()}, the attribute contains A. + * + * <li>for an invocation of {@code get[Declared]AnnotationsByType(Class<T>)}, the + * attribute either contains A or, if the type of A is repeatable, contains + * exactly one annotation whose value element contains A and whose type is the + * containing annotation type of A's type (JLS 9.6). * </ul> * - * <p>An annotation A is <em>present</em> on an element E if either: + * <p> + * <li>An annotation A is <em>present</em> on an element E if either: + * * <ul> * <li>A is <em>directly present</em> on E; or - * <li>There are no annotations of A's type which are <em>directly present</em> - * on E, and E is a class, and A's type is inheritable (JLS 9.6.3.3), and A is - * present on the superclass of E + * + * <li>A is not <em>directly present</em> on E, and E is a class, and A's type + * is inheritable (JLS 9.6.3.3), and A is <em>present</em> on the superclass of + * E. + * </ul> + * * </ul> * * <p>If an annotation returned by a method in this interface contains @@ -119,12 +140,19 @@ <T extends Annotation> T getAnnotation(Class<T> annotationClass); /** - * Returns an array of all this element's annotations for the - * specified type if one or more of such annotation is present, - * else an array of length zero. + * Returns annotations that are <em>present</em> on this element. * - * The caller of this method is free to modify the returned array; - * it will have no effect on the arrays returned to other callers. + * If there are no annotations <em>present</em> on this element, the return + * value is an array of length 0. + * + * The difference between this method and {@link #getAnnotation(Class)} + * is that this method detects if its argument is a <em>repeatable + * annotation type</em> (JLS 9.6), and if so, attempts to find one or + * more annotations of that type by "looking through" a container + * annotation. + * + * The caller of this method is free to modify the returned array; it will + * have no effect on the arrays returned to other callers. * * @param annotationClass the Class object corresponding to the * annotation type @@ -133,7 +161,7 @@ * @throws NullPointerException if the given annotation class is null * @since 1.8 */ - <T extends Annotation> T[] getAnnotations(Class<T> annotationClass); + <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass); /** * Returns annotations that are <em>present</em> on this element. @@ -165,16 +193,21 @@ */ <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass); - /** - * Returns an array of all this element's annotations for the - * specified type if one or more of such annotation is directly - * present, else an array of length zero. + /** + * Returns annotations that are <em>directly present</em> on this element. + * This method ignores inherited annotations. * - * This method ignores inherited annotations. (Returns - * an array of length zero if no annotations are directly present - * on this element.) The caller of this method is free to modify - * the returned array; it will have no effect on the arrays - * returned to other callers. + * If there are no annotations <em>directly present</em> on this element, + * the return value is an array of length 0. + * + * The difference between this method and {@link + * #getDeclaredAnnotation(Class)} is that this method detects if its + * argument is a <em>repeatable annotation type</em> (JLS 9.6), and if so, + * attempts to find one or more annotations of that type by "looking + * through" a container annotation. + * + * The caller of this method is free to modify the returned array; it will + * have no effect on the arrays returned to other callers. * * @param annotationClass the Class object corresponding to the * annotation type @@ -183,7 +216,7 @@ * @throws NullPointerException if the given annotation class is null * @since 1.8 */ - <T extends Annotation> T[] getDeclaredAnnotations(Class<T> annotationClass); + <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass); /** * Returns annotations that are <em>directly present</em> on this element.
--- a/jdk/src/share/classes/java/lang/reflect/Executable.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/lang/reflect/Executable.java Tue Feb 19 22:23:34 2013 -0800 @@ -278,6 +278,10 @@ * this object. Returns an array of length 0 if the executable * has no parameters. * + * The parameters of the underlying executable do not necessarily + * have unique names, or names that are legal identifiers in the + * Java programming language (JLS 3.8). + * * @return an array of {@code Parameter} objects representing all * the parameters to the executable this object represents */ @@ -445,7 +449,8 @@ * @throws NullPointerException {@inheritDoc} * @since 1.8 */ - public <T extends Annotation> T[] getAnnotations(Class<T> annotationClass) { + @Override + public <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) { Objects.requireNonNull(annotationClass); return AnnotationSupport.getMultipleAnnotations(declaredAnnotations(), annotationClass);
--- a/jdk/src/share/classes/java/lang/reflect/Field.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/lang/reflect/Field.java Tue Feb 19 22:23:34 2013 -0800 @@ -1029,7 +1029,8 @@ * @throws NullPointerException {@inheritDoc} * @since 1.8 */ - public <T extends Annotation> T[] getAnnotations(Class<T> annotationClass) { + @Override + public <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) { Objects.requireNonNull(annotationClass); return AnnotationSupport.getMultipleAnnotations(declaredAnnotations(), annotationClass);
--- a/jdk/src/share/classes/java/lang/reflect/Modifier.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/lang/reflect/Modifier.java Tue Feb 19 22:23:34 2013 -0800 @@ -342,13 +342,13 @@ static final int SYNTHETIC = 0x00001000; static final int ANNOTATION = 0x00002000; static final int ENUM = 0x00004000; - static final int SYNTHESIZED = 0x00010000; + static final int MANDATED = 0x00008000; static boolean isSynthetic(int mod) { return (mod & SYNTHETIC) != 0; } - static boolean isSynthesized(int mod) { - return (mod & SYNTHESIZED) != 0; + static boolean isMandated(int mod) { + return (mod & MANDATED) != 0; } /**
--- a/jdk/src/share/classes/java/lang/reflect/Parameter.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/lang/reflect/Parameter.java Tue Feb 19 22:23:34 2013 -0800 @@ -44,7 +44,7 @@ private final String name; private final int modifiers; private final Executable executable; - private int index; + private final int index; /** * Package-private constructor for {@code Parameter}. @@ -95,9 +95,14 @@ } /** - * Returns a string representation of the parameter's modifiers, - * its attributes, its type, its name, and a trailing ... if it is - * a variadic parameter. + * Returns a string describing this parameter. The format is the + * modifiers for the parameter, if any, in canonical order as + * recommended by <cite>The Java™ Language + * Specification</cite>, followed by the fully- qualified type of + * the parameter (excluding the last [] if the parameter is + * variable arity), followed by "..." if the parameter is variable + * arity, followed by a space, followed by the name of the + * parameter. * * @return A string representation of the parameter and associated * information. @@ -118,7 +123,7 @@ sb.append(typename); sb.append(" "); - sb.append(name); + sb.append(getName()); return sb.toString(); } @@ -143,11 +148,23 @@ } /** - * Returns the name of the parameter represented by this - * {@code Parameter} object. + * Returns the name of the parameter. The names of the parameters + * of a single executable must all the be distinct. When names + * from the originating source are available, they are returned. + * Otherwise, an implementation of this method is free to create a + * name of this parameter, subject to the unquiness requirments. */ public String getName() { - return name; + // As per the spec, if a parameter has no name, return argX, + // where x is the index. + // + // Note: spec updates now outlaw empty strings as parameter + // names. The .equals("") is for compatibility with current + // JVM behavior. It may be removed at some point. + if(name == null || name.equals("")) + return "arg" + index; + else + return name; } /** @@ -190,20 +207,21 @@ private transient volatile Class<?> parameterClassCache = null; /** - * Returns {@code true} if this parameter is a synthesized - * construct; returns {@code false} otherwise. + * Returns {@code true} if this parameter is implicitly declared + * in source code; returns {@code false} otherwise. * - * @return true if and only if this parameter is a synthesized - * construct as defined by - * <cite>The Java™ Language Specification</cite>. + * @return true if and only if this parameter is implicitly + * declared as defined by <cite>The Java™ Language + * Specification</cite>. */ - public boolean isSynthesized() { - return Modifier.isSynthesized(getModifiers()); + public boolean isImplicit() { + return Modifier.isMandated(getModifiers()); } /** - * Returns {@code true} if this parameter is a synthetic - * construct; returns {@code false} otherwise. + * Returns {@code true} if this parameter is neither implicitly + * nor explicitly declared in source code; returns {@code false} + * otherwise. * * @jls 13.1 The Form of a Binary * @return true if and only if this parameter is a synthetic @@ -240,7 +258,8 @@ * {@inheritDoc} * @throws NullPointerException {@inheritDoc} */ - public <T extends Annotation> T[] getAnnotations(Class<T> annotationClass) { + @Override + public <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) { Objects.requireNonNull(annotationClass); return AnnotationSupport.getMultipleAnnotations(declaredAnnotations(), annotationClass); @@ -266,11 +285,12 @@ /** * @throws NullPointerException {@inheritDoc} */ - public <T extends Annotation> T[] getDeclaredAnnotations(Class<T> annotationClass) { + @Override + public <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass) { // Only annotations on classes are inherited, for all other // objects getDeclaredAnnotations is the same as // getAnnotations. - return getAnnotations(annotationClass); + return getAnnotationsByType(annotationClass); } /**
--- a/jdk/src/share/classes/java/nio/file/DirectoryStream.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/nio/file/DirectoryStream.java Tue Feb 19 22:23:34 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -117,8 +117,7 @@ */ public interface DirectoryStream<T> - extends Closeable, Iterable<T> -{ + extends Closeable, Iterable<T> { /** * An interface that is implemented by objects that decide if a directory * entry should be accepted or filtered. A {@code Filter} is passed as the @@ -130,6 +129,7 @@ * * @since 1.7 */ + @FunctionalInterface public static interface Filter<T> { /** * Decides if the given directory entry should be accepted or filtered.
--- a/jdk/src/share/classes/java/nio/file/PathMatcher.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/nio/file/PathMatcher.java Tue Feb 19 22:23:34 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ * @see FileSystem#getPathMatcher * @see Files#newDirectoryStream(Path,String) */ - +@FunctionalInterface public interface PathMatcher { /** * Tells if given path matches this matcher's pattern.
--- a/jdk/src/share/classes/java/security/KeyStore.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/security/KeyStore.java Tue Feb 19 22:23:34 2013 -0800 @@ -219,6 +219,150 @@ } /** + * Configuration data that specifies the keystores in a keystore domain. + * A keystore domain is a collection of keystores that are presented as a + * single logical keystore. The configuration data is used during + * {@code KeyStore} + * {@link #load(KeyStore.LoadStoreParameter) load} and + * {@link #store(KeyStore.LoadStoreParameter) store} operations. + * <p> + * The following syntax is supported for configuration data: + * <pre> + * + * domain <domainName> [<property> ...] { + * keystore <keystoreName> [<property> ...] ; + * ... + * }; + * ... + * + * </pre> + * where {@code domainName} and {@code keystoreName} are identifiers + * and {@code property} is a key/value pairing. The key and value are + * separated by an 'equals' symbol and the value is enclosed in double + * quotes. A property value may be either a printable string or a binary + * string of colon-separated pairs of hexadecimal digits. Multi-valued + * properties are represented as a comma-separated list of values, + * enclosed in square brackets. + * See {@link Arrays#toString(java.lang.Object[])}. + * <p> + * To ensure that keystore entries are uniquely identified, each + * entry's alias is prefixed by its {@code keystoreName} followed + * by the entry name separator and each {@code keystoreName} must be + * unique within its domain. Entry name prefixes are omitted when + * storing a keystore. + * <p> + * Properties are context-sensitive: properties that apply to + * all the keystores in a domain are located in the domain clause, + * and properties that apply only to a specific keystore are located + * in that keystore's clause. + * Unless otherwise specified, a property in a keystore clause overrides + * a property of the same name in the domain clause. All property names + * are case-insensitive. The following properties are supported: + * <dl> + * <dt> {@code keystoreType="<type>"} </dt> + * <dd> The keystore type. </dd> + * <dt> {@code keystoreURI="<url>"} </dt> + * <dd> The keystore location. </dd> + * <dt> {@code keystoreProviderName="<name>"} </dt> + * <dd> The name of the keystore's JCE provider. </dd> + * <dt> {@code keystorePasswordEnv="<environment-variable>"} </dt> + * <dd> The environment variable that stores a keystore password. + * Alternatively, passwords may be supplied to the constructor + * method in a {@code Map<String, ProtectionParameter>}. </dd> + * <dt> {@code entryNameSeparator="<separator>"} </dt> + * <dd> The separator between a keystore name prefix and an entry name. + * When specified, it applies to all the entries in a domain. + * Its default value is a space. </dd> + * </dl> + * <p> + * For example, configuration data for a simple keystore domain + * comprising three keystores is shown below: + * <pre> + * + * domain app1 { + * keystore app1-truststore + * keystoreURI="file:///app1/etc/truststore.jks" + * + * keystore system-truststore + * keystoreURI="${java.home}/lib/security/cacerts" + * + * keystore app1-keystore + * keystoreType="PKCS12" + * keystoreURI="file:///app1/etc/keystore.p12" + * }; + * + * </pre> + * @since 1.8 + */ + public static final class DomainLoadStoreParameter + implements LoadStoreParameter { + + private final URI configuration; + private final Map<String,ProtectionParameter> protectionParams; + + /** + * Constructs a DomainLoadStoreParameter for a keystore domain with + * the parameters used to protect keystore data. + * + * @param configuration identifier for the domain configuration data. + * The name of the target domain should be specified in the + * {@code java.net.URI} fragment component when it is necessary + * to distinguish between several domain configurations at the + * same location. + * + * @param protectionParams the map from keystore name to the parameter + * used to protect keystore data. + * A {@code java.util.Collections.EMPTY_MAP} should be used + * when protection parameters are not required or when they have + * been specified by properties in the domain configuration data. + * It is cloned to prevent subsequent modification. + * + * @exception NullPointerExcetion if {@code configuration} or + * {@code protectionParams} is {@code null} + */ + public DomainLoadStoreParameter(URI configuration, + Map<String,ProtectionParameter> protectionParams) { + if (configuration == null || protectionParams == null) { + throw new NullPointerException("invalid null input"); + } + this.configuration = configuration; + this.protectionParams = + Collections.unmodifiableMap(new HashMap<>(protectionParams)); + } + + /** + * Gets the identifier for the domain configuration data. + * + * @return the identifier for the configuration data + */ + public URI getConfiguration() { + return configuration; + } + + /** + * Gets the keystore protection parameters for keystores in this + * domain. + * + * @return an unmodifiable map of keystore names to protection + * parameters + */ + public Map<String,ProtectionParameter> getProtectionParams() { + return protectionParams; + } + + /** + * Gets the keystore protection parameters for this domain. + * Keystore domains do not support a protection parameter. + * + * @return always returns {@code null} + */ + @Override + public KeyStore.ProtectionParameter getProtectionParameter() { + return null; + } + } + + /** * A marker interface for keystore protection parameters. * * <p> The information stored in a <code>ProtectionParameter</code>
--- a/jdk/src/share/classes/java/sql/Date.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/sql/Date.java Tue Feb 19 22:23:34 2013 -0800 @@ -25,6 +25,9 @@ package java.sql; +import java.time.Instant; +import java.time.LocalDate; + /** * <P>A thin wrapper around a millisecond value that allows * JDBC to identify this as an SQL <code>DATE</code> value. A @@ -113,7 +116,6 @@ int firstDash; int secondDash; Date d = null; - if (s == null) { throw new java.lang.IllegalArgumentException(); } @@ -255,4 +257,50 @@ * compatibility. */ static final long serialVersionUID = 1511598038487230103L; + + /** + * Obtains an instance of {@code Date} from a {@link LocalDate} object + * with the same year, month and day of month value as the given + * {@code LocalDate}. + * <p> + * The provided {@code LocalDate} is interpreted as the local date + * in the local time zone. + * + * @param date a {@code LocalDate} to convert + * @return a {@code Date} object + * @exception NullPointerException if {@code date} is null + * @since 1.8 + */ + @SuppressWarnings("deprecation") + public static Date valueOf(LocalDate date) { + return new Date(date.getYear() - 1900, date.getMonthValue() -1, + date.getDayOfMonth()); + } + + /** + * Converts this {@code Date} object to a {@code LocalDate} + * <p> + * The conversion creates a {@code LocalDate} that represents the same + * date value as this {@code Date} in local time zone + * + * @return a {@code LocalDate} object representing the same date value + * + * @since 1.8 + */ + @SuppressWarnings("deprecation") + public LocalDate toLocalDate() { + return LocalDate.of(getYear() + 1900, getMonth() + 1, getDate()); + } + + /** + * This method always throws an UnsupportedOperationException and should + * not be used because SQL {@code Date} values do not have a time + * component. + * + * @exception java.lang.UnsupportedOperationException if this method is invoked + */ + @Override + public Instant toInstant() { + throw new java.lang.UnsupportedOperationException(); + } }
--- a/jdk/src/share/classes/java/sql/JDBCType.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/sql/JDBCType.java Tue Feb 19 22:23:34 2013 -0800 @@ -190,7 +190,17 @@ /** * Identifies the generic SQL type {@code REF_CURSOR}. */ - REF_CURSOR(Types.REF_CURSOR); + REF_CURSOR(Types.REF_CURSOR), + + /** + * Identifies the generic SQL type {@code TIME_WITH_TIMEZONE}. + */ + TIME_WITH_TIMEZONE(Types.TIME_WITH_TIMEZONE), + + /** + * Identifies the generic SQL type {@code TIMESTAMP_WITH_TIMEZONE}. + */ + TIMESTAMP_WITH_TIMEZONE(Types.TIMESTAMP_WITH_TIMEZONE); /** * The Integer value for the JDBCType. It maps to a value in
--- a/jdk/src/share/classes/java/sql/SQLInput.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/sql/SQLInput.java Tue Feb 19 22:23:34 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -421,4 +421,38 @@ */ RowId readRowId() throws SQLException; + //--------------------------JDBC 4.2 ----------------------------- + + /** + * Reads the next attribute in the stream and returns it as an + * {@code Object} in the Java programming language. The + * actual type of the object returned is determined by the specified + * Java data type, and any customizations present in this + * stream's type map. + * + * <P>A type map is registered with the stream by the JDBC driver before the + * stream is passed to the application. + * + * <P>When the attribute at the head of the stream is an SQL {@code NULL} + * the method returns {@code null}. If the attribute is an SQL + * structured or distinct + * type, it determines the SQL type of the attribute at the head of the stream. + * If the stream's type map has an entry for that SQL type, the driver + * constructs an object of the appropriate class and calls the method + * {@code SQLData.readSQL} on that object, which reads additional data from the + * stream, using the protocol described for that method. + *<p> + * The default implementation will throw {@code SQLFeatureNotSupportedException} + * + * @param type Class representing the Java data type to convert the attribute to. + * @return the attribute at the head of the stream as an {@code Object} in the + * Java programming language;{@code null} if the attribute is SQL {@code NULL} + * @exception SQLException if a database access error occurs + * @exception SQLFeatureNotSupportedException if the JDBC driver does not support + * this method + * @since 1.8 + */ + default <T> T readObject(Class<T> type) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } }
--- a/jdk/src/share/classes/java/sql/SQLOutput.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/sql/SQLOutput.java Tue Feb 19 22:23:34 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -272,7 +272,7 @@ * Otherwise, it calls the <code>SQLData.writeSQL</code> * method of the given object, which * writes the object's attributes to the stream. - * The implementation of the method <code>SQLData.writeSQ</code> + * The implementation of the method <code>SQLData.writeSQL</code> * calls the appropriate <code>SQLOutput</code> writer method(s) * for writing each of the object's attributes in order. * The attributes must be read from an <code>SQLInput</code> @@ -433,5 +433,43 @@ */ void writeSQLXML(SQLXML x) throws SQLException; + //--------------------------JDBC 4.2 ----------------------------- + + /** + * Writes to the stream the data contained in the given object. The + * object will be converted to the specified targetSqlType + * before being sent to the stream. + *<p> + * When the {@code object} is {@code null}, this + * method writes an SQL {@code NULL} to the stream. + * <p> + * If the object has a custom mapping (is of a class implementing the + * interface {@code SQLData}), + * the JDBC driver should call the method {@code SQLData.writeSQL} to + * write it to the SQL data stream. + * If, on the other hand, the object is of a class implementing + * {@code Ref}, {@code Blob}, {@code Clob}, {@code NClob}, + * {@code Struct}, {@code java.net.URL}, + * or {@code Array}, the driver should pass it to the database as a + * value of the corresponding SQL type. + *<P> + * The default implementation will throw {@code SQLFeatureNotSupportedException} + * + * @param x the object containing the input parameter value + * @param targetSqlType the SQL type to be sent to the database. + * @exception SQLException if a database access error occurs or + * if the Java Object specified by x is an InputStream + * or Reader object and the value of the scale parameter is less + * than zero + * @exception SQLFeatureNotSupportedException if + * the JDBC driver does not support this data type + * @see JDBCType + * @see SQLType + * @since 1.8 + */ + default void writeObject(Object x, SQLType targetSqlType) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } } +
--- a/jdk/src/share/classes/java/sql/Time.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/sql/Time.java Tue Feb 19 22:23:34 2013 -0800 @@ -25,6 +25,9 @@ package java.sql; +import java.time.Instant; +import java.time.LocalTime; + /** * <P>A thin wrapper around the <code>java.util.Date</code> class that allows the JDBC * API to identify this as an SQL <code>TIME</code> value. The <code>Time</code> @@ -246,4 +249,45 @@ * compatibility. */ static final long serialVersionUID = 8397324403548013681L; + + /** + * Obtains an instance of {@code Time} from a {@link LocalTime} object + * with the same hour, minute and second time value as the given + * {@code LocalTime}. + * + * @param time a {@code LocalTime} to convert + * @return a {@code Time} object + * @exception NullPointerException if {@code time} is null + * @since 1.8 + */ + @SuppressWarnings("deprecation") + public static Time valueOf(LocalTime time) { + return new Time(time.getHour(), time.getMinute(), time.getSecond()); + } + + /** + * Converts this {@code Time} object to a {@code LocalTime}. + * <p> + * The conversion creates a {@code LocalTime} that represents the same + * hour, minute, and second time value as this {@code Time}. + * + * @return a {@code LocalTime} object representing the same time value + * @since 1.8 + */ + @SuppressWarnings("deprecation") + public LocalTime toLocalTime() { + return LocalTime.of(getHours(), getMinutes(), getSeconds()); + } + + /** + * This method always throws an UnsupportedOperationException and should + * not be used because SQL {@code Time} values do not have a date + * component. + * + * @exception java.lang.UnsupportedOperationException if this method is invoked + */ + @Override + public Instant toInstant() { + throw new java.lang.UnsupportedOperationException(); + } }
--- a/jdk/src/share/classes/java/sql/Timestamp.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/sql/Timestamp.java Tue Feb 19 22:23:34 2013 -0800 @@ -25,6 +25,8 @@ package java.sql; +import java.time.Instant; +import java.time.LocalDateTime; import java.util.StringTokenizer; /** @@ -485,7 +487,6 @@ } } return i; - } /** @@ -530,4 +531,89 @@ static final long serialVersionUID = 2745179027874758501L; + private static final int MILLIS_PER_SECOND = 1000; + + /** + * Obtains an instance of {@code Timestamp} from a {@code LocalDateTime} + * object, with the same year, month, day of month, hours, minutes, + * seconds and nanos date-time value as the provided {@code LocalDateTime}. + * <p> + * The provided {@code LocalDateTime} is interpreted as the local + * date-time in the local time zone. + * + * @param dateTime a {@code LocalDateTime} to convert + * @return a {@code Timestamp} object + * @exception NullPointerException if {@code dateTime} is null. + * @since 1.8 + */ + @SuppressWarnings("deprecation") + public static Timestamp valueOf(LocalDateTime dateTime) { + return new Timestamp(dateTime.getYear() - 1900, + dateTime.getMonthValue() - 1, + dateTime.getDayOfMonth(), + dateTime.getHour(), + dateTime.getMinute(), + dateTime.getSecond(), + dateTime.getNano()); + } + + /** + * Converts this {@code Timestamp} object to a {@code LocalDateTime}. + * <p> + * The conversion creates a {@code LocalDateTime} that represents the + * same year, month, day of month, hours, minutes, seconds and nanos + * date-time value as this {@code Timestamp} in the local time zone. + * + * @return a {@code LocalDateTime} object representing the same date-time value + * @since 1.8 + */ + @SuppressWarnings("deprecation") + public LocalDateTime toLocalDateTime() { + return LocalDateTime.of(getYear() + 1900, + getMonth() + 1, + getDate(), + getHours(), + getMinutes(), + getSeconds(), + getNanos()); + } + + /** + * Obtains an instance of {@code Timestamp} from an {@link Instant} object. + * <p> + * {@code Instant} can store points on the time-line further in the future + * and further in the past than {@code Date}. In this scenario, this method + * will throw an exception. + * + * @param instant the instant to convert + * @return an {@code Timestamp} representing the same point on the time-line as + * the provided instant + * @exception NullPointerException if {@code instant} is null. + * @exception IllegalArgumentException if the instant is too large to + * represent as a {@code Timesamp} + * @since 1.8 + */ + public static Timestamp from(Instant instant) { + try { + Timestamp stamp = new Timestamp(instant.getEpochSecond() * MILLIS_PER_SECOND); + stamp.nanos = instant.getNano(); + return stamp; + } catch (ArithmeticException ex) { + throw new IllegalArgumentException(ex); + } + } + + /** + * Converts this {@code Timestamp} object to an {@code Instant}. + * <p> + * The conversion creates an {@code Instant} that represents the same + * point on the time-line as this {@code Timestamp}. + * + * @return an instant representing the same point on the time-line + * @since 1.8 + */ + @Override + public Instant toInstant() { + return Instant.ofEpochSecond(super.getTime() / MILLIS_PER_SECOND, nanos); + } }
--- a/jdk/src/share/classes/java/sql/Types.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/sql/Types.java Tue Feb 19 22:23:34 2013 -0800 @@ -319,6 +319,24 @@ */ public static final int REF_CURSOR = 2012; + /** + * The constant in the Java programming language, sometimes referred to + * as a type code, that identifies the generic SQL type + * {@code TIME WITH TIMEZONE}. + * + * @since 1.8 + */ + public static final int TIME_WITH_TIMEZONE = 2013; + + /** + * The constant in the Java programming language, sometimes referred to + * as a type code, that identifies the generic SQL type + * {@code TIMESTAMP WITH TIMEZONE}. + * + * @since 1.8 + */ + public static final int TIMESTAMP_WITH_TIMEZONE = 2014; + // Prevent instantiation private Types() {} }
--- a/jdk/src/share/classes/java/time/Clock.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/time/Clock.java Tue Feb 19 22:23:34 2013 -0800 @@ -377,60 +377,57 @@ * 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. + * <p> + * The default implementation currently calls {@link #instant}. * * @return the current millisecond instant from this clock, measured from * the Java epoch of 1970-01-01T00:00 UTC, not null * @throws DateTimeException if the instant cannot be obtained, not thrown by most implementations */ - public abstract long millis(); + public long millis() { + return instant().toEpochMilli(); + } //----------------------------------------------------------------------- /** * Gets the current instant of the clock. * <p> * This returns an instant representing the current instant as defined by the clock. - * <p> - * The default implementation currently calls {@link #millis}. * * @return the current instant from this clock, not null * @throws DateTimeException if the instant cannot be obtained, not thrown by most implementations */ - public Instant instant() { - return Instant.ofEpochMilli(millis()); - } + public abstract Instant instant(); //----------------------------------------------------------------------- /** * Checks if this clock is equal to another clock. * <p> - * Clocks must compare equal based on their state and behavior. + * Clocks should override this method to compare equals based on + * their state and to meet the contract of {@link Object#equals}. + * If not overridden, the behavior is defined by {@link Object#equals} * * @param obj the object to check, null returns false * @return true if this is equal to the other clock */ @Override - public abstract boolean equals(Object obj); + public boolean equals(Object obj) { + return super.equals(obj); + } /** * A hash code for this clock. + * <p> + * Clocks should override this method based on + * their state and to meet the contract of {@link Object#hashCode}. + * If not overridden, the behavior is defined by {@link Object#hashCode} * * @return a suitable hash code */ @Override - public abstract int hashCode(); - - //----------------------------------------------------------------------- - /** - * Returns a string describing this clock. - * <p> - * Clocks must have a string representation based on their state and behavior. - * For example, 'System[Europe/Paris]' could be used to represent the System - * clock in the 'Europe/Paris' time-zone. - * - * @return a string representation of this clock, not null - */ - @Override - public abstract String toString(); + public int hashCode() { + return super.hashCode(); + } //----------------------------------------------------------------------- /** @@ -460,6 +457,10 @@ return System.currentTimeMillis(); } @Override + public Instant instant() { + return Instant.ofEpochMilli(millis()); + } + @Override public boolean equals(Object obj) { if (obj instanceof SystemClock) { return zone.equals(((SystemClock) obj).zone);
--- a/jdk/src/share/classes/java/time/DayOfWeek.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/time/DayOfWeek.java Tue Feb 19 22:23:34 2013 -0800 @@ -170,8 +170,9 @@ /** * Obtains an instance of {@code DayOfWeek} from a temporal object. * <p> - * A {@code TemporalAccessor} represents some form of date and time information. - * This factory converts the arbitrary temporal object to an instance of {@code DayOfWeek}. + * This obtains a day-of-week based on the specified temporal. + * A {@code TemporalAccessor} represents an arbitrary set of date and time information, + * which this factory converts to an instance of {@code DayOfWeek}. * <p> * The conversion extracts the {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} field. * <p> @@ -206,8 +207,9 @@ /** * Gets the textual representation, such as 'Mon' or 'Friday'. * <p> - * This returns the textual name used to identify the day-of-week. - * The parameters control the length of the returned text and the locale. + * This returns the textual name used to identify the day-of-week, + * suitable for presentation to the user. + * The parameters control the style of the returned text and the locale. * <p> * If no textual mapping is found then the {@link #getValue() numeric value} is returned. * @@ -215,8 +217,8 @@ * @param locale the locale to use, not null * @return the text value of the day-of-week, not null */ - public String getText(TextStyle style, Locale locale) { - return new DateTimeFormatterBuilder().appendText(DAY_OF_WEEK, style).toFormatter(locale).print(this); + public String getDisplayName(TextStyle style, Locale locale) { + return new DateTimeFormatterBuilder().appendText(DAY_OF_WEEK, style).toFormatter(locale).format(this); } //----------------------------------------------------------------------- @@ -232,7 +234,7 @@ * All other {@code ChronoField} instances will return false. * <p> * If the field is not a {@code ChronoField}, then the result of this method - * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)} + * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} * passing {@code this} as the argument. * Whether the field is supported is determined by the field. * @@ -244,7 +246,7 @@ if (field instanceof ChronoField) { return field == DAY_OF_WEEK; } - return field != null && field.doIsSupported(this); + return field != null && field.isSupportedBy(this); } /** @@ -260,7 +262,7 @@ * All other {@code ChronoField} instances will throw a {@code DateTimeException}. * <p> * If the field is not a {@code ChronoField}, then the result of this method - * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)} + * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)} * passing {@code this} as the argument. * Whether the range can be obtained is determined by the field. * @@ -289,15 +291,13 @@ * All other {@code ChronoField} instances will throw a {@code DateTimeException}. * <p> * If the field is not a {@code ChronoField}, then the result of this method - * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)} + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} * passing {@code this} as the argument. Whether the value can be obtained, * and what the value represents, is determined by the field. * * @param field the field to get, not null * @return the value for the field, within the valid range of values * @throws DateTimeException if a value for the field cannot be obtained - * @throws DateTimeException if the range of valid values for the field exceeds an {@code int} - * @throws DateTimeException if the value is outside the range of valid values for the field * @throws ArithmeticException if numeric overflow occurs */ @Override @@ -320,7 +320,7 @@ * All other {@code ChronoField} instances will throw a {@code DateTimeException}. * <p> * If the field is not a {@code ChronoField}, then the result of this method - * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)} + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} * passing {@code this} as the argument. Whether the value can be obtained, * and what the value represents, is determined by the field. * @@ -336,7 +336,7 @@ } else if (field instanceof ChronoField) { throw new DateTimeException("Unsupported field: " + field.getName()); } - return field.doGet(this); + return field.getFrom(this); } //-----------------------------------------------------------------------
--- a/jdk/src/share/classes/java/time/Duration.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/time/Duration.java Tue Feb 19 22:23:34 2013 -0800 @@ -61,10 +61,14 @@ */ package java.time; +import static java.time.LocalTime.NANOS_PER_SECOND; import static java.time.LocalTime.SECONDS_PER_DAY; -import static java.time.temporal.ChronoField.INSTANT_SECONDS; +import static java.time.LocalTime.SECONDS_PER_HOUR; +import static java.time.LocalTime.SECONDS_PER_MINUTE; import static java.time.temporal.ChronoField.NANO_OF_SECOND; import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.NANOS; +import static java.time.temporal.ChronoUnit.SECONDS; import java.io.DataInput; import java.io.DataOutput; @@ -79,17 +83,23 @@ import java.time.temporal.ChronoField; import java.time.temporal.ChronoUnit; import java.time.temporal.Temporal; -import java.time.temporal.TemporalAccessor; -import java.time.temporal.TemporalAdder; -import java.time.temporal.TemporalSubtractor; +import java.time.temporal.TemporalAmount; import java.time.temporal.TemporalUnit; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** - * A duration between two instants on the time-line. + * A time-based amount of time, such as '34.5 seconds'. * <p> - * This class models a duration of time and is not tied to any instant. - * The model is of a directed duration, meaning that the duration may be negative. + * This class models a quantity or amount of time in terms of seconds and nanoseconds. + * It can be accessed using other duration-based units, such as minutes and hours. + * In addition, the {@link ChronoUnit#DAYS DAYS} unit can be used and is treated as + * exactly equal to 24 hours, thus ignoring daylight savings effects. + * See {@link Period} for the date-based equivalent to this class. * <p> * A physical duration could be of infinite length. * For practicality, the duration is stored with constraints similar to {@link Instant}. @@ -99,6 +109,7 @@ * The range of a duration requires the storage of a number larger than a {@code long}. * To achieve this, the class stores a {@code long} representing seconds and an {@code int} * representing nanosecond-of-second, which will always be between 0 and 999,999,999. + * The model is of a directed duration, meaning that the duration may be negative. * <p> * The duration is measured in "seconds", but these are not necessarily identical to * the scientific "SI second" definition based on atomic clocks. @@ -112,7 +123,7 @@ * @since 1.8 */ public final class Duration - implements TemporalAdder, TemporalSubtractor, Comparable<Duration>, Serializable { + implements TemporalAmount, Comparable<Duration>, Serializable { /** * Constant for a duration of zero. @@ -125,11 +136,14 @@ /** * Constant for nanos per second. */ - private static final int NANOS_PER_SECOND = 1000_000_000; + private static final BigInteger BI_NANOS_PER_SECOND = BigInteger.valueOf(NANOS_PER_SECOND); /** - * Constant for nanos per second. + * The pattern for parsing. */ - private static final BigInteger BI_NANOS_PER_SECOND = BigInteger.valueOf(NANOS_PER_SECOND); + private final static Pattern PATTERN = + Pattern.compile("([-+]?)P(?:([-+]?[0-9]+)D)?" + + "(T(?:([-+]?[0-9]+)H)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)(?:[.,]([0-9]{0,9}))?S)?)?", + Pattern.CASE_INSENSITIVE); /** * The number of seconds in the duration. @@ -143,7 +157,53 @@ //----------------------------------------------------------------------- /** - * Obtains an instance of {@code Duration} from a number of seconds. + * Obtains a {@code Duration} representing a number of standard 24 hour days. + * <p> + * The seconds are calculated based on the standard definition of a day, + * where each day is 86400 seconds which implies a 24 hour day. + * The nanosecond in second field is set to zero. + * + * @param days the number of days, positive or negative + * @return a {@code Duration}, not null + * @throws ArithmeticException if the input days exceeds the capacity of {@code Duration} + */ + public static Duration ofDays(long days) { + return create(Math.multiplyExact(days, SECONDS_PER_DAY), 0); + } + + /** + * Obtains a {@code Duration} representing a number of standard hours. + * <p> + * The seconds are calculated based on the standard definition of an hour, + * where each hour is 3600 seconds. + * The nanosecond in second field is set to zero. + * + * @param hours the number of hours, positive or negative + * @return a {@code Duration}, not null + * @throws ArithmeticException if the input hours exceeds the capacity of {@code Duration} + */ + public static Duration ofHours(long hours) { + return create(Math.multiplyExact(hours, SECONDS_PER_HOUR), 0); + } + + /** + * Obtains a {@code Duration} representing a number of standard minutes. + * <p> + * The seconds are calculated based on the standard definition of a minute, + * where each minute is 60 seconds. + * The nanosecond in second field is set to zero. + * + * @param minutes the number of minutes, positive or negative + * @return a {@code Duration}, not null + * @throws ArithmeticException if the input minutes exceeds the capacity of {@code Duration} + */ + public static Duration ofMinutes(long minutes) { + return create(Math.multiplyExact(minutes, SECONDS_PER_MINUTE), 0); + } + + //----------------------------------------------------------------------- + /** + * Obtains a {@code Duration} representing a number of seconds. * <p> * The nanosecond in second field is set to zero. * @@ -155,8 +215,8 @@ } /** - * Obtains an instance of {@code Duration} from a number of seconds - * and an adjustment in nanoseconds. + * Obtains a {@code Duration} representing a number of seconds and an + * adjustment in nanoseconds. * <p> * This method allows an arbitrary number of nanoseconds to be passed in. * The factory will alter the values of the second and nanosecond in order @@ -175,13 +235,13 @@ */ public static Duration ofSeconds(long seconds, long nanoAdjustment) { long secs = Math.addExact(seconds, Math.floorDiv(nanoAdjustment, NANOS_PER_SECOND)); - int nos = (int)Math.floorMod(nanoAdjustment, NANOS_PER_SECOND); + int nos = (int) Math.floorMod(nanoAdjustment, NANOS_PER_SECOND); return create(secs, nos); } //----------------------------------------------------------------------- /** - * Obtains an instance of {@code Duration} from a number of milliseconds. + * Obtains a {@code Duration} representing a number of milliseconds. * <p> * The seconds and nanoseconds are extracted from the specified milliseconds. * @@ -200,7 +260,7 @@ //----------------------------------------------------------------------- /** - * Obtains an instance of {@code Duration} from a number of nanoseconds. + * Obtains a {@code Duration} representing a number of nanoseconds. * <p> * The seconds and nanoseconds are extracted from the specified nanoseconds. * @@ -219,53 +279,7 @@ //----------------------------------------------------------------------- /** - * Obtains an instance of {@code Duration} from a number of standard length minutes. - * <p> - * The seconds are calculated based on the standard definition of a minute, - * where each minute is 60 seconds. - * The nanosecond in second field is set to zero. - * - * @param minutes the number of minutes, positive or negative - * @return a {@code Duration}, not null - * @throws ArithmeticException if the input minutes exceeds the capacity of {@code Duration} - */ - public static Duration ofMinutes(long minutes) { - return create(Math.multiplyExact(minutes, 60), 0); - } - - /** - * Obtains an instance of {@code Duration} from a number of standard length hours. - * <p> - * The seconds are calculated based on the standard definition of an hour, - * where each hour is 3600 seconds. - * The nanosecond in second field is set to zero. - * - * @param hours the number of hours, positive or negative - * @return a {@code Duration}, not null - * @throws ArithmeticException if the input hours exceeds the capacity of {@code Duration} - */ - public static Duration ofHours(long hours) { - return create(Math.multiplyExact(hours, 3600), 0); - } - - /** - * Obtains an instance of {@code Duration} from a number of standard 24 hour days. - * <p> - * The seconds are calculated based on the standard definition of a day, - * where each day is 86400 seconds which implies a 24 hour day. - * The nanosecond in second field is set to zero. - * - * @param days the number of days, positive or negative - * @return a {@code Duration}, not null - * @throws ArithmeticException if the input days exceeds the capacity of {@code Duration} - */ - public static Duration ofDays(long days) { - return create(Math.multiplyExact(days, 86400), 0); - } - - //----------------------------------------------------------------------- - /** - * Obtains an instance of {@code Duration} from a duration in the specified unit. + * Obtains a {@code Duration} representing an amount in the specified unit. * <p> * The parameters represent the two parts of a phrase like '6 Hours'. For example: * <pre> @@ -288,110 +302,139 @@ //----------------------------------------------------------------------- /** - * Obtains an instance of {@code Duration} representing the duration between two instants. + * Obtains a {@code Duration} representing the duration between two instants. * <p> - * A {@code Duration} represents a directed distance between two points on the time-line. - * As such, this method will return a negative duration if the end is before the start. - * To guarantee to obtain a positive duration call {@link #abs()} on the result of this factory. + * This calculates the duration between two temporal objects of the same type. + * The difference in seconds is calculated using + * {@link Temporal#periodUntil(Temporal, TemporalUnit)}. + * The difference in nanoseconds is calculated using by querying the + * {@link ChronoField#NANO_OF_SECOND NANO_OF_SECOND} field. + * <p> + * The result of this method can be a negative period if the end is before the start. + * To guarantee to obtain a positive duration call {@link #abs()} on the result. * * @param startInclusive the start instant, inclusive, not null * @param endExclusive the end instant, exclusive, not null * @return a {@code Duration}, not null * @throws ArithmeticException if the calculation exceeds the capacity of {@code Duration} */ - public static Duration between(TemporalAccessor startInclusive, TemporalAccessor endExclusive) { - long secs = Math.subtractExact(endExclusive.getLong(INSTANT_SECONDS), startInclusive.getLong(INSTANT_SECONDS)); - long nanos = endExclusive.getLong(NANO_OF_SECOND) - startInclusive.getLong(NANO_OF_SECOND); - secs = Math.addExact(secs, Math.floorDiv(nanos, NANOS_PER_SECOND)); - nanos = Math.floorMod(nanos, NANOS_PER_SECOND); - return create(secs, (int) nanos); // safe from overflow + public static Duration between(Temporal startInclusive, Temporal endExclusive) { + long secs = startInclusive.periodUntil(endExclusive, SECONDS); + long nanos; + try { + nanos = endExclusive.getLong(NANO_OF_SECOND) - startInclusive.getLong(NANO_OF_SECOND); + } catch (DateTimeException ex) { + nanos = 0; + } + return ofSeconds(secs, nanos); } //----------------------------------------------------------------------- /** - * Obtains an instance of {@code Duration} by parsing a text string. + * Obtains a {@code Duration} from a text string such as {@code PnDTnHnMn.nS}. * <p> - * This will parse the string produced by {@link #toString()} which is - * the ISO-8601 format {@code PTnS} where {@code n} is - * the number of seconds with optional decimal part. - * The number must consist of ASCII numerals. - * There must only be a negative sign at the start of the number and it can - * only be present if the value is less than zero. - * There must be at least one digit before any decimal point. - * There must be between 1 and 9 inclusive digits after any decimal point. - * The letters (P, T and S) will be accepted in upper or lower case. + * This will parse a textual representation of a duration, including the + * string produced by {@code toString()}. The formats accepted are based + * on the ISO-8601 duration format {@code PnDTnHnMn.nS} with days + * considered to be exactly 24 hours. + * <p> + * The string starts with an optional sign, denoted by the ASCII negative + * or positive symbol. If negative, the whole period is negated. + * The ASCII letter "P" is next in upper or lower case. + * There are then four sections, each consisting of a number and a suffix. + * The sections have suffixes in ASCII of "D", "H", "M" and "S" for + * days, hours, minutes and seconds, accepted in upper or lower case. + * The suffixes must occur in order. The ASCII letter "T" must occur before + * the first occurrence, if any, of an hour, minute or second section. + * At least one of the four sections must be present, and if "T" is present + * there must be at least one section after the "T". + * The number part of each section must consist of one or more ASCII digits. + * The number may be prefixed by the ASCII negative or positive symbol. + * The number of days, hours and minutes must parse to an {@code long}. + * The number of seconds must parse to an {@code long} with optional fraction. * The decimal point may be either a dot or a comma. + * The fractional part may have from zero to 9 digits. + * <p> + * The leading plus/minus sign, and negative values for other units are + * not part of the ISO-8601 standard. + * <p> + * Examples: + * <pre> + * "PT20.345S" -> parses as "20.345 seconds" + * "PT15M" -> parses as "15 minutes" (where a minute is 60 seconds) + * "PT10H" -> parses as "10 hours" (where an hour is 3600 seconds) + * "P2D" -> parses as "2 days" (where a day is 24 hours or 86400 seconds) + * "P2DT3H4M" -> parses as "2 days, 3 hours and 4 minutes" + * "P-6H3M" -> parses as "-6 hours and +3 minutes" + * "-P6H3M" -> parses as "-6 hours and -3 minutes" + * "-P-6H+3M" -> parses as "+6 hours and -3 minutes" + * </pre> * * @param text the text to parse, not null - * @return a {@code Duration}, not null - * @throws DateTimeParseException if the text cannot be parsed to a {@code Duration} + * @return the parsed duration, not null + * @throws DateTimeParseException if the text cannot be parsed to a duration */ - public static Duration parse(final CharSequence text) { + public static Duration parse(CharSequence text) { Objects.requireNonNull(text, "text"); - int len = text.length(); - if (len < 4 || - (text.charAt(0) != 'P' && text.charAt(0) != 'p') || - (text.charAt(1) != 'T' && text.charAt(1) != 't') || - (text.charAt(len - 1) != 'S' && text.charAt(len - 1) != 's') || - (len == 5 && text.charAt(2) == '-' && text.charAt(3) == '0')) { - throw new DateTimeParseException("Duration could not be parsed: " + text, text, 0); + Matcher matcher = PATTERN.matcher(text); + if (matcher.matches()) { + // check for letter T but no time sections + if ("T".equals(matcher.group(3)) == false) { + boolean negate = "-".equals(matcher.group(1)); + String dayMatch = matcher.group(2); + String hourMatch = matcher.group(4); + String minuteMatch = matcher.group(5); + String secondMatch = matcher.group(6); + String fractionMatch = matcher.group(7); + if (dayMatch != null || hourMatch != null || minuteMatch != null || secondMatch != null) { + long daysAsSecs = parseNumber(text, dayMatch, SECONDS_PER_DAY, "days"); + long hoursAsSecs = parseNumber(text, hourMatch, SECONDS_PER_HOUR, "hours"); + long minsAsSecs = parseNumber(text, minuteMatch, SECONDS_PER_MINUTE, "minutes"); + long seconds = parseNumber(text, secondMatch, 1, "seconds"); + int nanos = parseFraction(text, fractionMatch, seconds < 0 ? -1 : 1); + try { + return create(negate, daysAsSecs, hoursAsSecs, minsAsSecs, seconds, nanos); + } catch (ArithmeticException ex) { + throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: overflow", text, 0).initCause(ex); + } + } + } } - String numberText = text.subSequence(2, len - 1).toString().replace(',', '.'); - if (numberText.charAt(0) == '+') { - throw new DateTimeParseException("Duration could not be parsed: " + text, text, 2); + throw new DateTimeParseException("Text cannot be parsed to a Duration", text, 0); + } + + private static long parseNumber(CharSequence text, String parsed, int multiplier, String errorText) { + // regex limits to [-+]?[0-9]+ + if (parsed == null) { + return 0; } - 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); + long val = Long.parseLong(parsed); + return Math.multiplyExact(val, multiplier); + } catch (NumberFormatException | ArithmeticException ex) { + throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: " + errorText, text, 0).initCause(ex); + } + } - } catch (ArithmeticException | NumberFormatException ex) { - throw new DateTimeParseException("Duration could not be parsed: " + text, text, 2, ex); + private static int parseFraction(CharSequence text, String parsed, int negate) { + // regex limits to [0-9]{0,9} + if (parsed == null || parsed.length() == 0) { + return 0; } + try { + parsed = (parsed + "000000000").substring(0, 9); + return Integer.parseInt(parsed) * negate; + } catch (NumberFormatException | ArithmeticException ex) { + throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: fraction", text, 0).initCause(ex); + } + } + + private static Duration create(boolean negate, long daysAsSecs, long hoursAsSecs, long minsAsSecs, long secs, int nanos) { + long seconds = Math.addExact(daysAsSecs, Math.addExact(hoursAsSecs, Math.addExact(minsAsSecs, secs))); + if (negate) { + return ofSeconds(seconds, nanos).negated(); + } + return ofSeconds(seconds, nanos); } //----------------------------------------------------------------------- @@ -422,6 +465,56 @@ //----------------------------------------------------------------------- /** + * Gets the value of the requested unit. + * <p> + * This returns a value for each of the two supported units, + * {@link ChronoUnit#SECONDS SECONDS} and {@link ChronoUnit#NANOS NANOS}. + * All other units throw an exception. + * + * @param unit the {@code TemporalUnit} for which to return the value + * @return the long value of the unit + * @throws DateTimeException if the unit is not supported + */ + @Override + public long get(TemporalUnit unit) { + if (unit == SECONDS) { + return seconds; + } else if (unit == NANOS) { + return nanos; + } else { + throw new DateTimeException("Unsupported unit: " + unit.getName()); + } + } + + /** + * Gets the set of units supported by this duration. + * <p> + * The supported units are {@link ChronoUnit#SECONDS SECONDS}, + * and {@link ChronoUnit#NANOS NANOS}. + * They are returned in the order seconds, nanos. + * <p> + * This set can be used in conjunction with {@link #get(TemporalUnit)} + * to access the entire state of the period. + * + * @return a list containing the seconds and nanos units, not null + */ + @Override + public List<TemporalUnit> getUnits() { + return DurationUnits.UNITS; + } + + /** + * Private class to delay initialization of this list until needed. + * The circular dependency between Duration and ChronoUnit prevents + * the simple initialization in Duration. + */ + private static class DurationUnits { + final static List<TemporalUnit> UNITS = + Collections.unmodifiableList(Arrays.<TemporalUnit>asList(SECONDS, NANOS)); + } + + //----------------------------------------------------------------------- + /** * Checks if this duration is zero length. * <p> * A {@code Duration} represents a directed distance between two points on @@ -435,19 +528,6 @@ } /** - * Checks if this duration is positive, excluding zero. - * <p> - * A {@code Duration} represents a directed distance between two points on - * the time-line and can therefore be positive, zero or negative. - * This method checks whether the length is greater than zero. - * - * @return true if this duration has a total length greater than zero - */ - public boolean isPositive() { - return seconds >= 0 && ((seconds | nanos) != 0); - } - - /** * Checks if this duration is negative, excluding zero. * <p> * A {@code Duration} represents a directed distance between two points on @@ -499,6 +579,39 @@ //----------------------------------------------------------------------- /** + * Returns a copy of this duration with the specified amount of seconds. + * <p> + * This returns a duration with the specified seconds, retaining the + * nano-of-second part of this duration. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param seconds the seconds to represent, may be negative + * @return a {@code Duration} based on this period with the requested seconds, not null + */ + public Duration withSeconds(long seconds) { + return create(seconds, nanos); + } + + /** + * Returns a copy of this duration with the specified nano-of-second. + * <p> + * This returns a duration with the specified nano-of-second, retaining the + * seconds part of this duration. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param nanoOfSecond the nano-of-second to represent, from 0 to 999,999,999 + * @return a {@code Duration} based on this period with the requested nano-of-second, not null + * @throws DateTimeException if the nano-of-second is invalid + */ + public Duration withNanos(int nanoOfSecond) { + NANO_OF_SECOND.checkValidIntValue(nanoOfSecond); + return create(seconds, nanoOfSecond); + } + + //----------------------------------------------------------------------- + /** * Returns a copy of this duration with the specified duration added. * <p> * This instance is immutable and unaffected by this method call. @@ -552,6 +665,48 @@ //----------------------------------------------------------------------- /** + * Returns a copy of this duration with the specified duration in standard 24 hour days added. + * <p> + * The number of days is multiplied by 86400 to obtain the number of seconds to add. + * This is based on the standard definition of a day as 24 hours. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param daysToAdd the days to add, positive or negative + * @return a {@code Duration} based on this duration with the specified days added, not null + * @throws ArithmeticException if numeric overflow occurs + */ + public Duration plusDays(long daysToAdd) { + return plus(Math.multiplyExact(daysToAdd, SECONDS_PER_DAY), 0); + } + + /** + * Returns a copy of this duration with the specified duration in hours added. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param hoursToAdd the hours to add, positive or negative + * @return a {@code Duration} based on this duration with the specified hours added, not null + * @throws ArithmeticException if numeric overflow occurs + */ + public Duration plusHours(long hoursToAdd) { + return plus(Math.multiplyExact(hoursToAdd, SECONDS_PER_HOUR), 0); + } + + /** + * Returns a copy of this duration with the specified duration in minutes added. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param minutesToAdd the minutes to add, positive or negative + * @return a {@code Duration} based on this duration with the specified minutes added, not null + * @throws ArithmeticException if numeric overflow occurs + */ + public Duration plusMinutes(long minutesToAdd) { + return plus(Math.multiplyExact(minutesToAdd, SECONDS_PER_MINUTE), 0); + } + + /** * Returns a copy of this duration with the specified duration in seconds added. * <p> * This instance is immutable and unaffected by this method call. @@ -651,6 +806,52 @@ //----------------------------------------------------------------------- /** + * Returns a copy of this duration with the specified duration in standard 24 hour days subtracted. + * <p> + * The number of days is multiplied by 86400 to obtain the number of seconds to subtract. + * This is based on the standard definition of a day as 24 hours. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param daysToSubtract the days to subtract, positive or negative + * @return a {@code Duration} based on this duration with the specified days subtracted, not null + * @throws ArithmeticException if numeric overflow occurs + */ + public Duration minusDays(long daysToSubtract) { + return (daysToSubtract == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-daysToSubtract)); + } + + /** + * Returns a copy of this duration with the specified duration in hours subtracted. + * <p> + * The number of hours is multiplied by 3600 to obtain the number of seconds to subtract. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param hoursToSubtract the hours to subtract, positive or negative + * @return a {@code Duration} based on this duration with the specified hours subtracted, not null + * @throws ArithmeticException if numeric overflow occurs + */ + public Duration minusHours(long hoursToSubtract) { + return (hoursToSubtract == Long.MIN_VALUE ? plusHours(Long.MAX_VALUE).plusHours(1) : plusHours(-hoursToSubtract)); + } + + /** + * Returns a copy of this duration with the specified duration in minutes subtracted. + * <p> + * The number of hours is multiplied by 60 to obtain the number of seconds to subtract. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param minutesToSubtract the minutes to subtract, positive or negative + * @return a {@code Duration} based on this duration with the specified minutes subtracted, not null + * @throws ArithmeticException if numeric overflow occurs + */ + public Duration minusMinutes(long minutesToSubtract) { + return (minutesToSubtract == Long.MIN_VALUE ? plusMinutes(Long.MAX_VALUE).plusMinutes(1) : plusMinutes(-minutesToSubtract)); + } + + /** * Returns a copy of this duration with the specified duration in seconds subtracted. * <p> * This instance is immutable and unaffected by this method call. @@ -716,8 +917,7 @@ * * @param divisor the value to divide the duration by, positive or negative, not zero * @return a {@code Duration} based on this duration divided by the specified divisor, not null - * @throws ArithmeticException if the divisor is zero - * @throws ArithmeticException if numeric overflow occurs + * @throws ArithmeticException if the divisor is zero or if numeric overflow occurs */ public Duration dividedBy(long divisor) { if (divisor == 0) { @@ -794,15 +994,15 @@ * with this duration added. * <p> * In most cases, it is clearer to reverse the calling pattern by using - * {@link Temporal#plus(TemporalAdder)}. + * {@link Temporal#plus(TemporalAmount)}. * <pre> * // these two lines are equivalent, but the second approach is recommended * dateTime = thisDuration.addTo(dateTime); * dateTime = dateTime.plus(thisDuration); * </pre> * <p> - * A {@code Duration} can only be added to a {@code Temporal} that - * represents an instant and can supply {@link ChronoField#INSTANT_SECONDS}. + * The calculation will add the seconds, then nanos. + * Only non-zero amounts will be added. * <p> * This instance is immutable and unaffected by this method call. * @@ -813,13 +1013,13 @@ */ @Override public Temporal addTo(Temporal temporal) { - long instantSecs = temporal.getLong(INSTANT_SECONDS); - long instantNanos = temporal.getLong(NANO_OF_SECOND); - instantSecs = Math.addExact(instantSecs, seconds); - instantNanos = Math.addExact(instantNanos, nanos); - instantSecs = Math.addExact(instantSecs, Math.floorDiv(instantNanos, NANOS_PER_SECOND)); - instantNanos = Math.floorMod(instantNanos, NANOS_PER_SECOND); - return temporal.with(INSTANT_SECONDS, instantSecs).with(NANO_OF_SECOND, instantNanos); + if (seconds != 0) { + temporal = temporal.plus(seconds, SECONDS); + } + if (nanos != 0) { + temporal = temporal.plus(nanos, NANOS); + } + return temporal; } /** @@ -829,15 +1029,15 @@ * with this duration subtracted. * <p> * In most cases, it is clearer to reverse the calling pattern by using - * {@link Temporal#minus(TemporalSubtractor)}. + * {@link Temporal#minus(TemporalAmount)}. * <pre> * // these two lines are equivalent, but the second approach is recommended * dateTime = thisDuration.subtractFrom(dateTime); * dateTime = dateTime.minus(thisDuration); * </pre> * <p> - * A {@code Duration} can only be subtracted from a {@code Temporal} that - * represents an instant and can supply {@link ChronoField#INSTANT_SECONDS}. + * The calculation will subtract the seconds, then nanos. + * Only non-zero amounts will be added. * <p> * This instance is immutable and unaffected by this method call. * @@ -848,17 +1048,60 @@ */ @Override public Temporal subtractFrom(Temporal temporal) { - long instantSecs = temporal.getLong(INSTANT_SECONDS); - long instantNanos = temporal.getLong(NANO_OF_SECOND); - instantSecs = Math.subtractExact(instantSecs, seconds); - instantNanos = Math.subtractExact(instantNanos, nanos); - instantSecs = Math.addExact(instantSecs, Math.floorDiv(instantNanos, NANOS_PER_SECOND)); - instantNanos = Math.floorMod(instantNanos, NANOS_PER_SECOND); - return temporal.with(INSTANT_SECONDS, instantSecs).with(NANO_OF_SECOND, instantNanos); + if (seconds != 0) { + temporal = temporal.minus(seconds, SECONDS); + } + if (nanos != 0) { + temporal = temporal.minus(nanos, NANOS); + } + return temporal; } //----------------------------------------------------------------------- /** + * Gets the number of minutes in this duration. + * <p> + * This returns the total number of minutes in the duration by dividing the + * number of seconds by 86400. + * This is based on the standard definition of a day as 24 hours. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @return the number of minutes in the duration, may be negative + */ + public long toDays() { + return seconds / SECONDS_PER_DAY; + } + + /** + * Gets the number of minutes in this duration. + * <p> + * This returns the total number of minutes in the duration by dividing the + * number of seconds by 3600. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @return the number of minutes in the duration, may be negative + */ + public long toHours() { + return seconds / SECONDS_PER_HOUR; + } + + /** + * Gets the number of minutes in this duration. + * <p> + * This returns the total number of minutes in the duration by dividing the + * number of seconds by 60. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @return the number of minutes in the duration, may be negative + */ + public long toMinutes() { + return seconds / SECONDS_PER_MINUTE; + } + + /** * Converts this duration to the total length in milliseconds. * <p> * If this duration is too large to fit in a {@code long} milliseconds, then an @@ -887,7 +1130,7 @@ * @throws ArithmeticException if numeric overflow occurs */ public long toNanos() { - long millis = Math.multiplyExact(seconds, 1000_000_000); + long millis = Math.multiplyExact(seconds, NANOS_PER_SECOND); millis = Math.addExact(millis, nanos); return millis; } @@ -911,30 +1154,6 @@ return nanos - otherDuration.nanos; } - /** - * Checks if this duration is greater than the specified {@code Duration}. - * <p> - * The comparison is based on the total length of the durations. - * - * @param otherDuration the other duration to compare to, not null - * @return true if this duration is greater than the specified duration - */ - public boolean isGreaterThan(Duration otherDuration) { - return compareTo(otherDuration) > 0; - } - - /** - * Checks if this duration is less than the specified {@code Duration}. - * <p> - * The comparison is based on the total length of the durations. - * - * @param otherDuration the other duration to compare to, not null - * @return true if this duration is less than the specified duration - */ - public boolean isLessThan(Duration otherDuration) { - return compareTo(otherDuration) < 0; - } - //----------------------------------------------------------------------- /** * Checks if this duration is equal to the specified {@code Duration}. @@ -970,29 +1189,57 @@ //----------------------------------------------------------------------- /** * A string representation of this duration using ISO-8601 seconds - * based representation, such as {@code PT12.345S}. + * based representation, such as {@code PT8H6M12.345S}. * <p> - * The format of the returned string will be {@code PTnS} where n is - * the seconds and fractional seconds of the duration. + * The format of the returned string will be {@code PTnHnMnS}, where n is + * the relevant hours, minutes or seconds part of the duration. + * Any fractional seconds are placed after a decimal point i the seconds section. + * If a section has a zero value, it is omitted. + * The hours, minutes and seconds will all have the same sign. + * <p> + * Examples: + * <pre> + * "20.345 seconds" -> "PT20.345S + * "15 minutes" (15 * 60 seconds) -> "PT15M" + * "10 hours" (10 * 3600 seconds) -> "PT10H" + * "2 days" (2 * 86400 seconds) -> "PT48H" + * </pre> + * Note that multiples of 24 hours are not output as days to avoid confusion + * with {@code Period}. * * @return an ISO-8601 representation of this duration, not null */ @Override public String toString() { + if (this == ZERO) { + return "PT0S"; + } + long hours = seconds / SECONDS_PER_HOUR; + int minutes = (int) ((seconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE); + int secs = (int) (seconds % SECONDS_PER_MINUTE); StringBuilder buf = new StringBuilder(24); buf.append("PT"); - if (seconds < 0 && nanos > 0) { - if (seconds == -1) { + if (hours != 0) { + buf.append(hours).append('H'); + } + if (minutes != 0) { + buf.append(minutes).append('M'); + } + if (secs == 0 && nanos == 0 && buf.length() > 2) { + return buf.toString(); + } + if (secs < 0 && nanos > 0) { + if (secs == -1) { buf.append("-0"); } else { - buf.append(seconds + 1); + buf.append(secs + 1); } } else { - buf.append(seconds); + buf.append(secs); } if (nanos > 0) { int pos = buf.length(); - if (seconds < 0) { + if (secs < 0) { buf.append(2 * NANOS_PER_SECOND - nanos); } else { buf.append(nanos + NANOS_PER_SECOND);
--- a/jdk/src/share/classes/java/time/Instant.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/time/Instant.java Tue Feb 19 22:23:34 2013 -0800 @@ -61,6 +61,7 @@ */ package java.time; +import static java.time.LocalTime.NANOS_PER_SECOND; import static java.time.LocalTime.SECONDS_PER_DAY; import static java.time.LocalTime.SECONDS_PER_HOUR; import static java.time.LocalTime.SECONDS_PER_MINUTE; @@ -76,18 +77,17 @@ import java.io.InvalidObjectException; import java.io.ObjectStreamException; import java.io.Serializable; -import java.time.format.DateTimeFormatters; +import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.time.temporal.ChronoField; import java.time.temporal.ChronoUnit; import java.time.temporal.Queries; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; -import java.time.temporal.TemporalAdder; import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalAmount; import java.time.temporal.TemporalField; import java.time.temporal.TemporalQuery; -import java.time.temporal.TemporalSubtractor; import java.time.temporal.TemporalUnit; import java.time.temporal.ValueRange; import java.util.Objects; @@ -225,10 +225,6 @@ * Serialization version. */ private static final long serialVersionUID = -665713676816604388L; - /** - * Constant for nanos per second. - */ - private static final int NANOS_PER_SECOND = 1000_000_000; /** * The number of seconds from the epoch of 1970-01-01T00:00:00Z. @@ -333,8 +329,9 @@ /** * Obtains an instance of {@code Instant} from a temporal object. * <p> - * A {@code TemporalAccessor} represents some form of date and time information. - * This factory converts the arbitrary temporal object to an instance of {@code Instant}. + * This obtains an instant based on the specified temporal. + * A {@code TemporalAccessor} represents an arbitrary set of date and time information, + * which this factory converts to an instance of {@code Instant}. * <p> * The conversion extracts the {@link ChronoField#INSTANT_SECONDS INSTANT_SECONDS} * and {@link ChronoField#NANO_OF_SECOND NANO_OF_SECOND} fields. @@ -358,14 +355,14 @@ * {@code 2007-12-03T10:15:30:00}. * <p> * The string must represent a valid instant in UTC and is parsed using - * {@link DateTimeFormatters#isoInstant()}. + * {@link DateTimeFormatter#ISO_INSTANT}. * * @param text the text to parse, not null * @return the parsed instant, not null * @throws DateTimeParseException if the text cannot be parsed */ public static Instant parse(final CharSequence text) { - return DateTimeFormatters.isoInstant().parse(text, Instant::from); + return DateTimeFormatter.ISO_INSTANT.parse(text, Instant::from); } //----------------------------------------------------------------------- @@ -418,7 +415,7 @@ * All other {@code ChronoField} instances will return false. * <p> * If the field is not a {@code ChronoField}, then the result of this method - * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)} + * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} * passing {@code this} as the argument. * Whether the field is supported is determined by the field. * @@ -430,7 +427,7 @@ if (field instanceof ChronoField) { return field == INSTANT_SECONDS || field == NANO_OF_SECOND || field == MICRO_OF_SECOND || field == MILLI_OF_SECOND; } - return field != null && field.doIsSupported(this); + return field != null && field.isSupportedBy(this); } /** @@ -447,7 +444,7 @@ * All other {@code ChronoField} instances will throw a {@code DateTimeException}. * <p> * If the field is not a {@code ChronoField}, then the result of this method - * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)} + * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)} * passing {@code this} as the argument. * Whether the range can be obtained is determined by the field. * @@ -475,7 +472,7 @@ * All other {@code ChronoField} instances will throw a {@code DateTimeException}. * <p> * If the field is not a {@code ChronoField}, then the result of this method - * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)} + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} * passing {@code this} as the argument. Whether the value can be obtained, * and what the value represents, is determined by the field. * @@ -495,7 +492,7 @@ } throw new DateTimeException("Unsupported field: " + field.getName()); } - return range(field).checkValidIntValue(field.doGet(this), field); + return range(field).checkValidIntValue(field.getFrom(this), field); } /** @@ -511,7 +508,7 @@ * All other {@code ChronoField} instances will throw a {@code DateTimeException}. * <p> * If the field is not a {@code ChronoField}, then the result of this method - * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)} + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} * passing {@code this} as the argument. Whether the value can be obtained, * and what the value represents, is determined by the field. * @@ -531,7 +528,7 @@ } throw new DateTimeException("Unsupported field: " + field.getName()); } - return field.doGet(this); + return field.getFrom(this); } //----------------------------------------------------------------------- @@ -565,7 +562,7 @@ /** * Returns an adjusted copy of this instant. * <p> - * This returns a new {@code Instant}, based on this one, with the date adjusted. + * This returns an {@code Instant}, based on this one, with the instant adjusted. * The adjustment takes place using the specified adjuster strategy object. * Read the documentation of the adjuster to understand what adjustment will be made. * <p> @@ -588,7 +585,7 @@ /** * Returns a copy of this instant with the specified field set to a new value. * <p> - * This returns a new {@code Instant}, based on this one, with the value + * This returns an {@code Instant}, based on this one, with the value * for the specified field changed. * If it is not possible to set the value, because the field is not supported or for * some other reason, an exception is thrown. @@ -616,7 +613,7 @@ * All other {@code ChronoField} instances will throw a {@code DateTimeException}. * <p> * If the field is not a {@code ChronoField}, then the result of this method - * is obtained by invoking {@code TemporalField.doWith(Temporal, long)} + * is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)} * passing {@code this} as the argument. In this case, the field determines * whether and how to adjust the instant. * <p> @@ -647,24 +644,130 @@ } throw new DateTimeException("Unsupported field: " + field.getName()); } - return field.doWith(this, newValue); + return field.adjustInto(this, newValue); } //----------------------------------------------------------------------- /** - * {@inheritDoc} - * @throws DateTimeException {@inheritDoc} - * @throws ArithmeticException {@inheritDoc} + * Returns a copy of this {@code Instant} truncated to the specified unit. + * <p> + * Truncating the instant returns a copy of the original with fields + * smaller than the specified unit set to zero. + * The fields are calculated on the basis of using a UTC offset as seen + * in {@code toString}. + * For example, truncating with the {@link ChronoUnit#MINUTES MINUTES} unit will + * round down to the nearest minute, setting the seconds and nanoseconds to zero. + * <p> + * The unit must have a {@linkplain TemporalUnit#getDuration() duration} + * that divides into the length of a standard day without remainder. + * This includes all supplied time units on {@link ChronoUnit} and + * {@link ChronoUnit#DAYS DAYS}. Other units throw an exception. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param unit the unit to truncate to, not null + * @return an {@code Instant} based on this instant with the time truncated, not null + * @throws DateTimeException if the unit is invalid for truncation + */ + public Instant truncatedTo(TemporalUnit unit) { + if (unit == ChronoUnit.NANOS) { + return this; + } + Duration unitDur = unit.getDuration(); + if (unitDur.getSeconds() > LocalTime.SECONDS_PER_DAY) { + throw new DateTimeException("Unit is too large to be used for truncation"); + } + long dur = unitDur.toNanos(); + if ((LocalTime.NANOS_PER_DAY % dur) != 0) { + throw new DateTimeException("Unit must divide into a standard day without remainder"); + } + long nod = (seconds % LocalTime.SECONDS_PER_DAY) * LocalTime.NANOS_PER_SECOND + nanos; + long result = (nod / dur) * dur; + return plusNanos(result - nod); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this instant with the specified amount added. + * <p> + * This returns an {@code Instant}, based on this one, with the specified amount added. + * The amount is typically {@link Duration} but may be any other type implementing + * the {@link TemporalAmount} interface. + * <p> + * The calculation is delegated to the amount object by calling + * {@link TemporalAmount#addTo(Temporal)}. The amount implementation is free + * to implement the addition in any way it wishes, however it typically + * calls back to {@link #plus(long, TemporalUnit)}. Consult the documentation + * of the amount implementation to determine if it can be successfully added. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param amountToAdd the amount to add, not null + * @return an {@code Instant} based on this instant with the addition made, not null + * @throws DateTimeException if the addition cannot be made + * @throws ArithmeticException if numeric overflow occurs */ @Override - public Instant plus(TemporalAdder adder) { - return (Instant) adder.addTo(this); + public Instant plus(TemporalAmount amountToAdd) { + return (Instant) amountToAdd.addTo(this); } /** - * {@inheritDoc} - * @throws DateTimeException {@inheritDoc} - * @throws ArithmeticException {@inheritDoc} + * Returns a copy of this instant with the specified amount added. + * <p> + * This returns an {@code Instant}, based on this one, with the amount + * in terms of the unit added. If it is not possible to add the amount, because the + * unit is not supported or for some other reason, an exception is thrown. + * <p> + * If the field is a {@link ChronoUnit} then the addition is implemented here. + * The supported fields behave as follows: + * <ul> + * <li>{@code NANOS} - + * Returns a {@code Instant} with the specified number of nanoseconds added. + * This is equivalent to {@link #plusNanos(long)}. + * <li>{@code MICROS} - + * Returns a {@code Instant} with the specified number of microseconds added. + * This is equivalent to {@link #plusNanos(long)} with the amount + * multiplied by 1,000. + * <li>{@code MILLIS} - + * Returns a {@code Instant} with the specified number of milliseconds added. + * This is equivalent to {@link #plusNanos(long)} with the amount + * multiplied by 1,000,000. + * <li>{@code SECONDS} - + * Returns a {@code Instant} with the specified number of seconds added. + * This is equivalent to {@link #plusSeconds(long)}. + * <li>{@code MINUTES} - + * Returns a {@code Instant} with the specified number of minutes added. + * This is equivalent to {@link #plusSeconds(long)} with the amount + * multiplied by 60. + * <li>{@code HOURS} - + * Returns a {@code Instant} with the specified number of hours added. + * This is equivalent to {@link #plusSeconds(long)} with the amount + * multiplied by 3,600. + * <li>{@code HALF_DAYS} - + * Returns a {@code Instant} with the specified number of half-days added. + * This is equivalent to {@link #plusSeconds(long)} with the amount + * multiplied by 43,200 (12 hours). + * <li>{@code DAYS} - + * Returns a {@code Instant} with the specified number of days added. + * This is equivalent to {@link #plusSeconds(long)} with the amount + * multiplied by 86,400 (24 hours). + * </ul> + * <p> + * All other {@code ChronoUnit} instances will throw a {@code DateTimeException}. + * <p> + * If the field is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)} + * passing {@code this} as the argument. In this case, the unit determines + * whether and how to perform the addition. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param amountToAdd the amount of the unit to add to the result, may be negative + * @param unit the unit of the amount to add, not null + * @return an {@code Instant} based on this instant with the specified amount added, not null + * @throws DateTimeException if the addition cannot be made + * @throws ArithmeticException if numeric overflow occurs */ @Override public Instant plus(long amountToAdd, TemporalUnit unit) { @@ -681,7 +784,7 @@ } throw new DateTimeException("Unsupported unit: " + unit.getName()); } - return unit.doPlus(this, amountToAdd); + return unit.addTo(this, amountToAdd); } //----------------------------------------------------------------------- @@ -751,19 +854,47 @@ //----------------------------------------------------------------------- /** - * {@inheritDoc} - * @throws DateTimeException {@inheritDoc} - * @throws ArithmeticException {@inheritDoc} + * Returns a copy of this instant with the specified amount subtracted. + * <p> + * This returns an {@code Instant}, based on this one, with the specified amount subtracted. + * The amount is typically {@link Duration} but may be any other type implementing + * the {@link TemporalAmount} interface. + * <p> + * The calculation is delegated to the amount object by calling + * {@link TemporalAmount#subtractFrom(Temporal)}. The amount implementation is free + * to implement the subtraction in any way it wishes, however it typically + * calls back to {@link #minus(long, TemporalUnit)}. Consult the documentation + * of the amount implementation to determine if it can be successfully subtracted. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param amountToSubtract the amount to subtract, not null + * @return an {@code Instant} based on this instant with the subtraction made, not null + * @throws DateTimeException if the subtraction cannot be made + * @throws ArithmeticException if numeric overflow occurs */ @Override - public Instant minus(TemporalSubtractor subtractor) { - return (Instant) subtractor.subtractFrom(this); + public Instant minus(TemporalAmount amountToSubtract) { + return (Instant) amountToSubtract.subtractFrom(this); } /** - * {@inheritDoc} - * @throws DateTimeException {@inheritDoc} - * @throws ArithmeticException {@inheritDoc} + * Returns a copy of this instant with the specified amount subtracted. + * <p> + * This returns a {@code Instant}, based on this one, with the amount + * in terms of the unit subtracted. If it is not possible to subtract the amount, + * because the unit is not supported or for some other reason, an exception is thrown. + * <p> + * This method is equivalent to {@link #plus(long, TemporalUnit)} with the amount negated. + * See that method for a full description of how addition, and thus subtraction, works. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param amountToSubtract the amount of the unit to subtract from the result, may be negative + * @param unit the unit of the amount to subtract, not null + * @return an {@code Instant} based on this instant with the specified amount subtracted, not null + * @throws DateTimeException if the subtraction cannot be made + * @throws ArithmeticException if numeric overflow occurs */ @Override public Instant minus(long amountToSubtract, TemporalUnit unit) { @@ -848,7 +979,7 @@ return (R) NANOS; } // inline TemporalAccessor.super.query(query) as an optimization - if (query == Queries.chrono() || query == Queries.zoneId() || query == Queries.zone() || query == Queries.offset()) { + if (query == Queries.chronology() || query == Queries.zoneId() || query == Queries.zone() || query == Queries.offset()) { return null; } return query.queryFrom(this); @@ -945,7 +1076,7 @@ } throw new DateTimeException("Unsupported unit: " + unit.getName()); } - return unit.between(this, endInstant).getAmount(); + return unit.between(this, endInstant); } private long nanosUntil(Instant end) { @@ -959,6 +1090,43 @@ //----------------------------------------------------------------------- /** + * Combines this instant with an offset to create an {@code OffsetDateTime}. + * <p> + * This returns an {@code OffsetDateTime} formed from this instant at the + * specified offset from UTC/Greenwich. An exception will be thrown if the + * instant is too large to fit into an offset date-time. + * <p> + * This method is equivalent to + * {@link OffsetDateTime#ofInstant(Instant, ZoneId) OffsetDateTime.ofInstant(this, offset)}. + * + * @param offset the offset to combine with, not null + * @return the offset date-time formed from this instant and the specified offset, not null + * @throws DateTimeException if the result exceeds the supported range + */ + public OffsetDateTime atOffset(ZoneOffset offset) { + return OffsetDateTime.ofInstant(this, offset); + } + + /** + * Combines this instant with a time-zone to create a {@code ZonedDateTime}. + * <p> + * This returns an {@code ZonedDateTime} formed from this instant at the + * specified time-zone. An exception will be thrown if the instant is too + * large to fit into a zoned date-time. + * <p> + * This method is equivalent to + * {@link ZonedDateTime#ofInstant(Instant, ZoneId) ZonedDateTime.ofInstant(this, zone)}. + * + * @param zone the zone to combine with, not null + * @return the zoned date-time formed from this instant and the specified zone, not null + * @throws DateTimeException if the result exceeds the supported range + */ + public ZonedDateTime atZone(ZoneId zone) { + return ZonedDateTime.ofInstant(this, zone); + } + + //----------------------------------------------------------------------- + /** * Converts this instant to the number of milliseconds from the epoch * of 1970-01-01T00:00:00Z. * <p> @@ -1059,13 +1227,13 @@ /** * A string representation of this instant using ISO-8601 representation. * <p> - * The format used is the same as {@link DateTimeFormatters#isoInstant()}. + * The format used is the same as {@link DateTimeFormatter#ISO_INSTANT}. * * @return an ISO-8601 representation of this instant, not null */ @Override public String toString() { - return DateTimeFormatters.isoInstant().print(this); + return DateTimeFormatter.ISO_INSTANT.format(this); } // -----------------------------------------------------------------------
--- a/jdk/src/share/classes/java/time/LocalDate.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/time/LocalDate.java Tue Feb 19 22:23:34 2013 -0800 @@ -80,26 +80,22 @@ import java.io.InvalidObjectException; import java.io.ObjectStreamException; import java.io.Serializable; -import java.time.format.DateTimeBuilder; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.Era; +import java.time.chrono.IsoChronology; import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatters; import java.time.format.DateTimeParseException; import java.time.temporal.ChronoField; -import java.time.temporal.ChronoLocalDate; import java.time.temporal.ChronoUnit; -import java.time.temporal.Era; -import java.time.temporal.ISOChrono; -import java.time.temporal.OffsetDate; +import java.time.temporal.Queries; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; -import java.time.temporal.TemporalAdder; import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalAmount; import java.time.temporal.TemporalField; import java.time.temporal.TemporalQuery; -import java.time.temporal.TemporalSubtractor; import java.time.temporal.TemporalUnit; import java.time.temporal.ValueRange; -import java.time.temporal.Year; import java.time.zone.ZoneOffsetTransition; import java.time.zone.ZoneRules; import java.util.Objects; @@ -131,7 +127,7 @@ * @since 1.8 */ public final class LocalDate - implements Temporal, TemporalAdjuster, ChronoLocalDate<ISOChrono>, Serializable { + implements Temporal, TemporalAdjuster, ChronoLocalDate<LocalDate>, Serializable { /** * The minimum supported {@code LocalDate}, '-999999999-01-01'. @@ -216,7 +212,7 @@ */ public static LocalDate now(Clock clock) { Objects.requireNonNull(clock, "clock"); - // inline OffsetDate factory to avoid creating object and InstantProvider checks + // inline to avoid creating object and Instant checks final Instant now = clock.instant(); // called once ZoneOffset offset = clock.getZone().getRules().getOffset(now); long epochSec = now.getEpochSecond() + offset.getTotalSeconds(); // overflow caught later @@ -228,14 +224,15 @@ /** * Obtains an instance of {@code LocalDate} from a year, month and day. * <p> + * This returns a {@code LocalDate} with the specified year, month and day-of-month. * The day must be valid for the year and month, otherwise an exception will be thrown. * * @param year the year to represent, from MIN_YEAR to MAX_YEAR * @param month the month-of-year to represent, not null * @param dayOfMonth the day-of-month to represent, from 1 to 31 * @return the local date, not null - * @throws DateTimeException if the value of any field is out of range - * @throws DateTimeException if the day-of-month is invalid for the month-year + * @throws DateTimeException if the value of any field is out of range, + * or if the day-of-month is invalid for the month-year */ public static LocalDate of(int year, Month month, int dayOfMonth) { YEAR.checkValidValue(year); @@ -247,14 +244,15 @@ /** * Obtains an instance of {@code LocalDate} from a year, month and day. * <p> + * This returns a {@code LocalDate} with the specified year, month and day-of-month. * The day must be valid for the year and month, otherwise an exception will be thrown. * * @param year the year to represent, from MIN_YEAR to MAX_YEAR * @param month the month-of-year to represent, from 1 (January) to 12 (December) * @param dayOfMonth the day-of-month to represent, from 1 to 31 * @return the local date, not null - * @throws DateTimeException if the value of any field is out of range - * @throws DateTimeException if the day-of-month is invalid for the month-year + * @throws DateTimeException if the value of any field is out of range, + * or if the day-of-month is invalid for the month-year */ public static LocalDate of(int year, int month, int dayOfMonth) { YEAR.checkValidValue(year); @@ -267,18 +265,19 @@ /** * Obtains an instance of {@code LocalDate} from a year and day-of-year. * <p> + * This returns a {@code LocalDate} with the specified year and day-of-year. * The day-of-year must be valid for the year, otherwise an exception will be thrown. * * @param year the year to represent, from MIN_YEAR to MAX_YEAR * @param dayOfYear the day-of-year to represent, from 1 to 366 * @return the local date, not null - * @throws DateTimeException if the value of any field is out of range - * @throws DateTimeException if the day-of-year is invalid for the month-year + * @throws DateTimeException if the value of any field is out of range, + * or if the day-of-year is invalid for the month-year */ public static LocalDate ofYearDay(int year, int dayOfYear) { YEAR.checkValidValue(year); DAY_OF_YEAR.checkValidValue(dayOfYear); - boolean leap = ISOChrono.INSTANCE.isLeapYear(year); + boolean leap = IsoChronology.INSTANCE.isLeapYear(year); if (dayOfYear == 366 && leap == false) { throw new DateTimeException("Invalid date 'DayOfYear 366' as '" + year + "' is not a leap year"); } @@ -295,8 +294,9 @@ /** * Obtains an instance of {@code LocalDate} from the epoch day count. * <p> - * The Epoch Day count is a simple incrementing count of days - * where day 0 is 1970-01-01. Negative numbers represent earlier days. + * This returns a {@code LocalDate} with the specified epoch-day. + * The {@link ChronoField#EPOCH_DAY EPOCH_DAY} is a simple incrementing count + * of days where day 0 is 1970-01-01. Negative numbers represent earlier days. * * @param epochDay the Epoch Day to convert, based on the epoch 1970-01-01 * @return the local date, not null @@ -338,10 +338,12 @@ /** * Obtains an instance of {@code LocalDate} from a temporal object. * <p> - * A {@code TemporalAccessor} represents some form of date and time information. - * This factory converts the arbitrary temporal object to an instance of {@code LocalDate}. + * This obtains a local date based on the specified temporal. + * A {@code TemporalAccessor} represents an arbitrary set of date and time information, + * which this factory converts to an instance of {@code LocalDate}. * <p> - * The conversion extracts the {@link ChronoField#EPOCH_DAY EPOCH_DAY} field. + * The conversion uses the {@link Queries#localDate()} query, which relies + * on extracting the {@link ChronoField#EPOCH_DAY EPOCH_DAY} field. * <p> * This method matches the signature of the functional interface {@link TemporalQuery} * allowing it to be used as a query via method reference, {@code LocalDate::from}. @@ -351,26 +353,11 @@ * @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(); + LocalDate date = temporal.query(Queries.localDate()); + if (date == null) { + throw new DateTimeException("Unable to obtain LocalDate from TemporalAccessor: " + temporal.getClass()); } - // 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); - } + return date; } //----------------------------------------------------------------------- @@ -378,14 +365,14 @@ * Obtains an instance of {@code LocalDate} from a text string such as {@code 2007-12-03}. * <p> * The string must represent a valid date and is parsed using - * {@link java.time.format.DateTimeFormatters#isoLocalDate()}. + * {@link java.time.format.DateTimeFormatter#ISO_LOCAL_DATE}. * * @param text the text to parse such as "2007-12-03", not null * @return the parsed local date, not null * @throws DateTimeParseException if the text cannot be parsed */ public static LocalDate parse(CharSequence text) { - return parse(text, DateTimeFormatters.isoLocalDate()); + return parse(text, DateTimeFormatter.ISO_LOCAL_DATE); } /** @@ -414,7 +401,7 @@ * @throws DateTimeException if the day-of-month is invalid for the month-year */ private static LocalDate create(int year, Month month, int dayOfMonth) { - if (dayOfMonth > 28 && dayOfMonth > month.length(ISOChrono.INSTANCE.isLeapYear(year))) { + if (dayOfMonth > 28 && dayOfMonth > month.length(IsoChronology.INSTANCE.isLeapYear(year))) { if (dayOfMonth == 29) { throw new DateTimeException("Invalid date 'February 29' as '" + year + "' is not a leap year"); } else { @@ -435,7 +422,7 @@ private static LocalDate resolvePreviousValid(int year, int month, int day) { switch (month) { case 2: - day = Math.min(day, ISOChrono.INSTANCE.isLeapYear(year) ? 29 : 28); + day = Math.min(day, IsoChronology.INSTANCE.isLeapYear(year) ? 29 : 28); break; case 4: case 6: @@ -469,8 +456,6 @@ * {@link #get(TemporalField) get} methods will throw an exception. * <p> * If the field is a {@link ChronoField} then the query is implemented here. - * The {@link #isSupported(TemporalField) supported fields} will return valid - * values based on this date-time. * The supported fields are: * <ul> * <li>{@code DAY_OF_WEEK} @@ -490,7 +475,7 @@ * All other {@code ChronoField} instances will return false. * <p> * If the field is not a {@code ChronoField}, then the result of this method - * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)} + * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} * passing {@code this} as the argument. * Whether the field is supported is determined by the field. * @@ -516,7 +501,7 @@ * All other {@code ChronoField} instances will throw a {@code DateTimeException}. * <p> * If the field is not a {@code ChronoField}, then the result of this method - * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)} + * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)} * passing {@code this} as the argument. * Whether the range can be obtained is determined by the field. * @@ -540,7 +525,7 @@ } throw new DateTimeException("Unsupported field: " + field.getName()); } - return field.doRange(this); + return field.rangeRefinedBy(this); } /** @@ -558,7 +543,7 @@ * All other {@code ChronoField} instances will throw a {@code DateTimeException}. * <p> * If the field is not a {@code ChronoField}, then the result of this method - * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)} + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} * passing {@code this} as the argument. Whether the value can be obtained, * and what the value represents, is determined by the field. * @@ -588,7 +573,7 @@ * All other {@code ChronoField} instances will throw a {@code DateTimeException}. * <p> * If the field is not a {@code ChronoField}, then the result of this method - * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)} + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} * passing {@code this} as the argument. Whether the value can be obtained, * and what the value represents, is determined by the field. * @@ -608,7 +593,7 @@ } return get0(field); } - return field.doGet(this); + return field.getFrom(this); } private int get0(TemporalField field) { @@ -638,7 +623,7 @@ /** * Gets the chronology of this date, which is the ISO calendar system. * <p> - * The {@code Chrono} represents the calendar system in use. + * The {@code Chronology} 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. @@ -646,14 +631,14 @@ * @return the ISO chronology, not null */ @Override - public ISOChrono getChrono() { - return ISOChrono.INSTANCE; + public IsoChronology getChronology() { + return IsoChronology.INSTANCE; } /** * Gets the era applicable at this date. * <p> - * The official ISO-8601 standard does not define eras, however {@code ISOChrono} does. + * The official ISO-8601 standard does not define eras, however {@code IsoChronology} 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 @@ -664,12 +649,12 @@ * the Japanese calendar system. * <p> * The returned era will be a singleton capable of being compared with the constants - * in {@link ISOChrono} using the {@code ==} operator. + * in {@link IsoChronology} using the {@code ==} operator. * - * @return the {@code ISOChrono} era constant applicable at this date, not null + * @return the {@code IsoChronology} era constant applicable at this date, not null */ @Override // override for Javadoc - public Era<ISOChrono> getEra() { + public Era getEra() { return ChronoLocalDate.super.getEra(); } @@ -679,7 +664,7 @@ * This method returns the primitive {@code int} value for the year. * <p> * The year returned by this method is proleptic as per {@code get(YEAR)}. - * To obtain the year-of-era, use {@code get(YEAR_OF_ERA}. + * To obtain the year-of-era, use {@code get(YEAR_OF_ERA)}. * * @return the year, from MIN_YEAR to MAX_YEAR */ @@ -777,7 +762,7 @@ */ @Override // override for Javadoc and performance public boolean isLeapYear() { - return ISOChrono.INSTANCE.isLeapYear(year); + return IsoChronology.INSTANCE.isLeapYear(year); } /** @@ -819,7 +804,7 @@ /** * Returns an adjusted copy of this date. * <p> - * This returns a new {@code LocalDate}, based on this one, with the date adjusted. + * This returns a {@code LocalDate}, based on this one, with the date adjusted. * The adjustment takes place using the specified adjuster strategy object. * Read the documentation of the adjuster to understand what adjustment will be made. * <p> @@ -828,7 +813,7 @@ * 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}. + * such as {@link Month} and {@link java.time.MonthDay MonthDay}. * The adjuster is responsible for handling special cases, such as the varying * lengths of month and leap years. * <p> @@ -863,7 +848,7 @@ /** * Returns a copy of this date with the specified field set to a new value. * <p> - * This returns a new {@code LocalDate}, based on this one, with the value + * This returns a {@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 @@ -951,7 +936,7 @@ * All other {@code ChronoField} instances will throw a {@code DateTimeException}. * <p> * If the field is not a {@code ChronoField}, then the result of this method - * is obtained by invoking {@code TemporalField.doWith(Temporal, long)} + * is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)} * passing {@code this} as the argument. In this case, the field determines * whether and how to adjust the instant. * <p> @@ -985,7 +970,7 @@ } throw new DateTimeException("Unsupported field: " + field.getName()); } - return field.doWith(this, newValue); + return field.adjustInto(this, newValue); } //----------------------------------------------------------------------- @@ -1033,8 +1018,8 @@ * * @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 + * @throws DateTimeException if the day-of-month value is invalid, + * or if the day-of-month is invalid for the month-year */ public LocalDate withDayOfMonth(int dayOfMonth) { if (this.day == dayOfMonth) { @@ -1051,8 +1036,8 @@ * * @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 + * @throws DateTimeException if the day-of-year value is invalid, + * or if the day-of-year is invalid for the year */ public LocalDate withDayOfYear(int dayOfYear) { if (this.getDayOfYear() == dayOfYear) { @@ -1063,40 +1048,109 @@ //----------------------------------------------------------------------- /** - * Returns a copy of this date with the specified period added. + * Returns a copy of this date with the specified amount added. * <p> - * This method returns a new date based on this date with the specified period added. - * The adder is typically {@link Period} but may be any other type implementing - * the {@link TemporalAdder} interface. - * The calculation is delegated to the specified adjuster, which typically calls - * back to {@link #plus(long, TemporalUnit)}. + * This returns a {@code LocalDate}, based on this one, with the specified amount added. + * The amount is typically {@link Period} but may be any other type implementing + * the {@link TemporalAmount} interface. + * <p> + * The calculation is delegated to the amount object by calling + * {@link TemporalAmount#addTo(Temporal)}. The amount implementation is free + * to implement the addition in any way it wishes, however it typically + * calls back to {@link #plus(long, TemporalUnit)}. Consult the documentation + * of the amount implementation to determine if it can be successfully added. * <p> * This instance is immutable and unaffected by this method call. * - * @param adder the adder to use, not null + * @param amountToAdd the amount to add, 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); + public LocalDate plus(TemporalAmount amountToAdd) { + return (LocalDate) amountToAdd.addTo(this); } /** - * Returns a copy of this date with the specified period added. + * Returns a copy of this date with the specified amount added. * <p> - * This method returns a new date based on this date with the specified period added. - * This can be used to add any period that is defined by a unit, for example to add years, months or days. - * The unit is responsible for the details of the calculation, including the resolution - * of any edge cases in the calculation. + * This returns a {@code LocalDate}, based on this one, with the amount + * in terms of the unit added. If it is not possible to add the amount, because the + * unit is not supported or for some other reason, an exception is thrown. + * <p> + * In some cases, adding the amount can cause the resulting date to become invalid. + * For example, adding one month to 31st January would result in 31st February. + * In cases like this, the unit is responsible for resolving the date. + * Typically it will choose the previous valid date, which would be the last valid + * day of February in this example. + * <p> + * If the field is a {@link ChronoUnit} then the addition is implemented here. + * The supported fields behave as follows: + * <ul> + * <li>{@code DAYS} - + * Returns a {@code LocalDate} with the specified number of days added. + * This is equivalent to {@link #plusDays(long)}. + * <li>{@code WEEKS} - + * Returns a {@code LocalDate} with the specified number of weeks added. + * This is equivalent to {@link #plusWeeks(long)} and uses a 7 day week. + * <li>{@code MONTHS} - + * Returns a {@code LocalDate} with the specified number of months added. + * This is equivalent to {@link #plusMonths(long)}. + * The day-of-month will be unchanged unless it would be invalid for the new + * month and year. In that case, the day-of-month is adjusted to the maximum + * valid value for the new month and year. + * <li>{@code YEARS} - + * Returns a {@code LocalDate} with the specified number of years added. + * This is equivalent to {@link #plusYears(long)}. + * The day-of-month will be unchanged unless it would be invalid for the new + * month and year. In that case, the day-of-month is adjusted to the maximum + * valid value for the new month and year. + * <li>{@code DECADES} - + * Returns a {@code LocalDate} with the specified number of decades added. + * This is equivalent to calling {@link #plusYears(long)} with the amount + * multiplied by 10. + * The day-of-month will be unchanged unless it would be invalid for the new + * month and year. In that case, the day-of-month is adjusted to the maximum + * valid value for the new month and year. + * <li>{@code CENTURIES} - + * Returns a {@code LocalDate} with the specified number of centuries added. + * This is equivalent to calling {@link #plusYears(long)} with the amount + * multiplied by 100. + * The day-of-month will be unchanged unless it would be invalid for the new + * month and year. In that case, the day-of-month is adjusted to the maximum + * valid value for the new month and year. + * <li>{@code MILLENNIA} - + * Returns a {@code LocalDate} with the specified number of millennia added. + * This is equivalent to calling {@link #plusYears(long)} with the amount + * multiplied by 1,000. + * The day-of-month will be unchanged unless it would be invalid for the new + * month and year. In that case, the day-of-month is adjusted to the maximum + * valid value for the new month and year. + * <li>{@code ERAS} - + * Returns a {@code LocalDate} with the specified number of eras added. + * Only two eras are supported so the amount must be one, zero or minus one. + * If the amount is non-zero then the year is changed such that the year-of-era + * is unchanged. + * The day-of-month will be unchanged unless it would be invalid for the new + * month and year. In that case, the day-of-month is adjusted to the maximum + * valid value for the new month and year. + * </ul> + * <p> + * All other {@code ChronoUnit} instances will throw a {@code DateTimeException}. + * <p> + * If the field is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)} + * passing {@code this} as the argument. In this case, the unit determines + * whether and how to perform the addition. * <p> * This instance is immutable and unaffected by this method call. * * @param amountToAdd the amount of the unit to add to the result, may be negative - * @param unit the unit of the period to add, not null - * @return a {@code LocalDate} based on this date with the specified period added, not null - * @throws DateTimeException if the unit cannot be added to this type + * @param unit the unit of the amount to add, not null + * @return a {@code LocalDate} based on this date with the specified amount added, not null + * @throws DateTimeException if the addition cannot be made + * @throws ArithmeticException if numeric overflow occurs */ @Override public LocalDate plus(long amountToAdd, TemporalUnit unit) { @@ -1114,7 +1168,7 @@ } throw new DateTimeException("Unsupported unit: " + unit.getName()); } - return unit.doPlus(this, amountToAdd); + return unit.addTo(this, amountToAdd); } //----------------------------------------------------------------------- @@ -1221,40 +1275,47 @@ //----------------------------------------------------------------------- /** - * Returns a copy of this date with the specified period subtracted. + * Returns a copy of this date with the specified amount subtracted. * <p> - * This method returns a new date based on this date with the specified period subtracted. - * The subtractor is typically {@link Period} but may be any other type implementing - * the {@link TemporalSubtractor} interface. - * The calculation is delegated to the specified adjuster, which typically calls - * back to {@link #minus(long, TemporalUnit)}. + * This returns a {@code LocalDate}, based on this one, with the specified amount subtracted. + * The amount is typically {@link Period} but may be any other type implementing + * the {@link TemporalAmount} interface. + * <p> + * The calculation is delegated to the amount object by calling + * {@link TemporalAmount#subtractFrom(Temporal)}. The amount implementation is free + * to implement the subtraction in any way it wishes, however it typically + * calls back to {@link #minus(long, TemporalUnit)}. Consult the documentation + * of the amount implementation to determine if it can be successfully subtracted. * <p> * This instance is immutable and unaffected by this method call. * - * @param subtractor the subtractor to use, not null + * @param amountToSubtract the amount to subtract, 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); + public LocalDate minus(TemporalAmount amountToSubtract) { + return (LocalDate) amountToSubtract.subtractFrom(this); } /** - * Returns a copy of this date with the specified period subtracted. + * Returns a copy of this date with the specified amount subtracted. * <p> - * This method returns a new date based on this date with the specified period subtracted. - * This can be used to subtract any period that is defined by a unit, for example to subtract years, months or days. - * The unit is responsible for the details of the calculation, including the resolution - * of any edge cases in the calculation. + * This returns a {@code LocalDate}, based on this one, with the amount + * in terms of the unit subtracted. If it is not possible to subtract the amount, + * because the unit is not supported or for some other reason, an exception is thrown. + * <p> + * This method is equivalent to {@link #plus(long, TemporalUnit)} with the amount negated. + * See that method for a full description of how addition, and thus subtraction, works. * <p> * This instance is immutable and unaffected by this method call. * * @param amountToSubtract the amount of the unit to subtract from the result, may be negative - * @param unit the unit of the period to subtract, not null - * @return a {@code LocalDate} based on this date with the specified period subtracted, not null - * @throws DateTimeException if the unit cannot be added to this type + * @param unit the unit of the amount to subtract, not null + * @return a {@code LocalDate} based on this date with the specified amount subtracted, not null + * @throws DateTimeException if the subtraction cannot be made + * @throws ArithmeticException if numeric overflow occurs */ @Override public LocalDate minus(long amountToSubtract, TemporalUnit unit) { @@ -1367,8 +1428,12 @@ * @throws DateTimeException if unable to query (defined by the query) * @throws ArithmeticException if numeric overflow occurs (defined by the query) */ - @Override // override for Javadoc + @SuppressWarnings("unchecked") + @Override public <R> R query(TemporalQuery<R> query) { + if (query == Queries.localDate()) { + return (R) this; + } return ChronoLocalDate.super.query(query); } @@ -1417,14 +1482,15 @@ * For example, the period in months between 2012-06-15 and 2012-08-14 * will only be one month as it is one day short of two months. * <p> - * This method operates in association with {@link TemporalUnit#between}. - * The result of this method is a {@code long} representing the amount of - * the specified unit. By contrast, the result of {@code between} is an - * object that can be used directly in addition/subtraction: + * There are two equivalent ways of using this method. + * The first is to invoke this method. + * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: * <pre> - * long period = start.periodUntil(end, MONTHS); // this method - * dateTime.plus(MONTHS.between(start, end)); // use in plus/minus + * // these two lines are equivalent + * amount = start.periodUntil(end, MONTHS); + * amount = MONTHS.between(start, end); * </pre> + * The choice should be made based on which makes the code more readable. * <p> * The calculation is implemented in this method for {@link ChronoUnit}. * The units {@code DAYS}, {@code WEEKS}, {@code MONTHS}, {@code YEARS}, @@ -1464,7 +1530,7 @@ } throw new DateTimeException("Unsupported unit: " + unit.getName()); } - return unit.between(this, endDate).getAmount(); + return unit.between(this, endDate); } long daysUntil(LocalDate end) { @@ -1477,14 +1543,64 @@ return (packed2 - packed1) / 32; } + /** + * Calculates the period between this date and another date as a {@code Period}. + * <p> + * This calculates the period between two dates in terms of years, months and days. + * The start and end points are {@code this} and the specified date. + * The result will be negative if the end is before the start. + * <p> + * The calculation is performed using the ISO calendar system. + * If necessary, the input date will be converted to ISO. + * <p> + * The start date is included, but the end date is not. + * The period is calculated by removing complete months, then calculating + * the remaining number of days, adjusting to ensure that both have the same sign. + * The number of months is then normalized into years and months based on a 12 month year. + * A month is considered to be complete 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 "1 year, 2 months and 3 days". + * <p> + * The result of this method can be a negative period if the end is before the start. + * The negative sign will be the same in each of year, month and day. + * <p> + * There are two equivalent ways of using this method. + * The first is to invoke this method. + * The second is to use {@link Period#between(LocalDate, LocalDate)}: + * <pre> + * // these two lines are equivalent + * period = start.periodUntil(end); + * period = Period.between(start, end); + * </pre> + * The choice should be made based on which makes the code more readable. + * + * @param endDate the end date, exclusive, which may be in any chronology, not null + * @return the period between this date and the end date, not null + */ + @Override + public Period periodUntil(ChronoLocalDate<?> endDate) { + LocalDate end = LocalDate.from(endDate); + long totalMonths = end.getEpochMonth() - this.getEpochMonth(); // safe + int days = end.day - this.day; + if (totalMonths > 0 && days < 0) { + totalMonths--; + LocalDate calcDate = this.plusMonths(totalMonths); + days = (int) (end.toEpochDay() - calcDate.toEpochDay()); // safe + } else if (totalMonths < 0 && days > 0) { + totalMonths++; + days -= end.lengthOfMonth(); + } + long years = totalMonths / 12; // safe + int months = (int) (totalMonths % 12); // safe + return Period.of(Math.toIntExact(years), months, days); + } + //----------------------------------------------------------------------- /** - * Returns a local date-time formed from this date at the specified time. + * Combines this date with a time to create a {@code LocalDateTime}. * <p> - * This combines this date with the specified time to form a {@code LocalDateTime}. + * This returns a {@code LocalDateTime} formed from this date at the specified time. * All possible combinations of date and time are valid. - * <p> - * This instance is immutable and unaffected by this method call. * * @param time the time to combine with, not null * @return the local date-time formed from this date and the specified time, not null @@ -1495,13 +1611,13 @@ } /** - * Returns a local date-time formed from this date at the specified time. + * Combines this date with a time to create a {@code LocalDateTime}. * <p> - * This combines this date with the specified time to form a {@code LocalDateTime}. + * This returns a {@code LocalDateTime} formed from this date at the + * specified hour and minute. + * The seconds and nanosecond fields will be set to zero. * The individual time fields must be within their valid range. * All possible combinations of date and time are valid. - * <p> - * This instance is immutable and unaffected by this method call. * * @param hour the hour-of-day to use, from 0 to 23 * @param minute the minute-of-hour to use, from 0 to 59 @@ -1513,13 +1629,13 @@ } /** - * Returns a local date-time formed from this date at the specified time. + * Combines this date with a time to create a {@code LocalDateTime}. * <p> - * This combines this date with the specified time to form a {@code LocalDateTime}. + * This returns a {@code LocalDateTime} formed from this date at the + * specified hour, minute and second. + * The nanosecond field will be set to zero. * The individual time fields must be within their valid range. * All possible combinations of date and time are valid. - * <p> - * This instance is immutable and unaffected by this method call. * * @param hour the hour-of-day to use, from 0 to 23 * @param minute the minute-of-hour to use, from 0 to 59 @@ -1532,13 +1648,12 @@ } /** - * Returns a local date-time formed from this date at the specified time. + * Combines this date with a time to create a {@code LocalDateTime}. * <p> - * This combines this date with the specified time to form a {@code LocalDateTime}. + * This returns a {@code LocalDateTime} formed from this date at the + * specified hour, minute, second and nanosecond. * The individual time fields must be within their valid range. * All possible combinations of date and time are valid. - * <p> - * This instance is immutable and unaffected by this method call. * * @param hour the hour-of-day to use, from 0 to 23 * @param minute the minute-of-hour to use, from 0 to 59 @@ -1552,18 +1667,29 @@ } /** - * Returns an offset date formed from this date and the specified offset. + * Combines this date with an offset time to create an {@code OffsetDateTime}. * <p> - * This combines this date with the specified offset to form an {@code OffsetDate}. - * All possible combinations of date and offset are valid. + * This returns an {@code OffsetDateTime} formed from this date at the specified time. + * All possible combinations of date and time are valid. + * + * @param time the time to combine with, not null + * @return the offset date-time formed from this date and the specified time, not null + */ + public OffsetDateTime atTime(OffsetTime time) { + return OffsetDateTime.of(LocalDateTime.of(this, time.toLocalTime()), time.getOffset()); + } + + /** + * Combines this date with the time of midnight to create a {@code LocalDateTime} + * at the start of this date. * <p> - * This instance is immutable and unaffected by this method call. + * This returns a {@code LocalDateTime} formed from this date at the time of + * midnight, 00:00, at the start of this date. * - * @param offset the offset to combine with, not null - * @return the offset date formed from this date and the specified offset, not null + * @return the local date-time of midnight at the start of this date, not null */ - public OffsetDate atOffset(ZoneOffset offset) { - return OffsetDate.of(this, offset); + public LocalDateTime atStartOfDay() { + return LocalDateTime.of(this, LocalTime.MIDNIGHT); } /** @@ -1582,8 +1708,6 @@ * <p> * To convert to a specific time in a given time-zone call {@link #atTime(LocalTime)} * followed by {@link LocalDateTime#atZone(ZoneId)}. - * <p> - * This instance is immutable and unaffected by this method call. * * @param zone the zone ID to use, not null * @return the zoned date-time formed from this date and the earliest valid time for the zone, not null @@ -1636,7 +1760,7 @@ * 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}. + * chronology is also considered, see {@link java.time.chrono.ChronoLocalDate#compareTo}. * * @param other the other date to compare to, not null * @return the comparator value, negative if less, positive if greater @@ -1822,7 +1946,7 @@ * Outputs this date as a {@code String} using the formatter. * <p> * This date will be passed to the formatter - * {@link DateTimeFormatter#print(TemporalAccessor) print method}. + * {@link DateTimeFormatter#format(TemporalAccessor) format method}. * * @param formatter the formatter to use, not null * @return the formatted date string, not null
--- a/jdk/src/share/classes/java/time/LocalDateTime.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/time/LocalDateTime.java Tue Feb 19 22:23:34 2013 -0800 @@ -70,6 +70,7 @@ 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 static java.time.temporal.ChronoField.NANO_OF_SECOND; import java.io.DataInput; import java.io.DataOutput; @@ -77,21 +78,19 @@ import java.io.InvalidObjectException; import java.io.ObjectStreamException; import java.io.Serializable; +import java.time.chrono.ChronoLocalDateTime; +import java.time.chrono.IsoChronology; import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatters; import java.time.format.DateTimeParseException; import java.time.temporal.ChronoField; -import java.time.temporal.ChronoLocalDateTime; import java.time.temporal.ChronoUnit; -import java.time.temporal.ISOChrono; -import java.time.temporal.OffsetDateTime; +import java.time.temporal.Queries; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; -import java.time.temporal.TemporalAdder; import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalAmount; import java.time.temporal.TemporalField; import java.time.temporal.TemporalQuery; -import java.time.temporal.TemporalSubtractor; import java.time.temporal.TemporalUnit; import java.time.temporal.ValueRange; import java.time.zone.ZoneRules; @@ -127,7 +126,7 @@ * @since 1.8 */ public final class LocalDateTime - implements Temporal, TemporalAdjuster, ChronoLocalDateTime<ISOChrono>, Serializable { + implements Temporal, TemporalAdjuster, ChronoLocalDateTime<LocalDate>, Serializable { /** * The minimum supported {@code LocalDateTime}, '-999999999-01-01T00:00:00'. @@ -212,6 +211,8 @@ * Obtains an instance of {@code LocalDateTime} from year, month, * day, hour and minute, setting the second and nanosecond to zero. * <p> + * This returns a {@code LocalDateTime} with the specified year, month, + * day-of-month, hour and minute. * 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. * @@ -221,8 +222,8 @@ * @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 + * @throws DateTimeException if the value of any field is out of range, + * or if the day-of-month is invalid for the month-year */ public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute) { LocalDate date = LocalDate.of(year, month, dayOfMonth); @@ -234,6 +235,8 @@ * Obtains an instance of {@code LocalDateTime} from year, month, * day, hour, minute and second, setting the nanosecond to zero. * <p> + * This returns a {@code LocalDateTime} with the specified year, month, + * day-of-month, hour, minute and second. * The day must be valid for the year and month, otherwise an exception will be thrown. * The nanosecond field will be set to zero. * @@ -244,8 +247,8 @@ * @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 + * @throws DateTimeException if the value of any field is out of range, + * or if the day-of-month is invalid for the month-year */ public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute, int second) { LocalDate date = LocalDate.of(year, month, dayOfMonth); @@ -257,6 +260,8 @@ * Obtains an instance of {@code LocalDateTime} from year, month, * day, hour, minute, second and nanosecond. * <p> + * This returns a {@code LocalDateTime} with the specified year, month, + * day-of-month, 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 @@ -267,8 +272,8 @@ * @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 + * @throws DateTimeException if the value of any field is out of range, + * or if the day-of-month is invalid for the month-year */ public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond) { LocalDate date = LocalDate.of(year, month, dayOfMonth); @@ -281,6 +286,8 @@ * Obtains an instance of {@code LocalDateTime} from year, month, * day, hour and minute, setting the second and nanosecond to zero. * <p> + * This returns a {@code LocalDateTime} with the specified year, month, + * day-of-month, hour and minute. * 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. * @@ -290,8 +297,8 @@ * @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 + * @throws DateTimeException if the value of any field is out of range, + * or if the day-of-month is invalid for the month-year */ public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute) { LocalDate date = LocalDate.of(year, month, dayOfMonth); @@ -303,6 +310,8 @@ * Obtains an instance of {@code LocalDateTime} from year, month, * day, hour, minute and second, setting the nanosecond to zero. * <p> + * This returns a {@code LocalDateTime} with the specified year, month, + * day-of-month, hour, minute and second. * The day must be valid for the year and month, otherwise an exception will be thrown. * The nanosecond field will be set to zero. * @@ -313,8 +322,8 @@ * @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 + * @throws DateTimeException if the value of any field is out of range, + * or if the day-of-month is invalid for the month-year */ public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second) { LocalDate date = LocalDate.of(year, month, dayOfMonth); @@ -326,6 +335,8 @@ * Obtains an instance of {@code LocalDateTime} from year, month, * day, hour, minute, second and nanosecond. * <p> + * This returns a {@code LocalDateTime} with the specified year, month, + * day-of-month, 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 @@ -336,8 +347,8 @@ * @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 + * @throws DateTimeException if the value of any field is out of range, + * or if the day-of-month is invalid for the month-year */ public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond) { LocalDate date = LocalDate.of(year, month, dayOfMonth); @@ -392,15 +403,17 @@ * @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 + * @throws DateTimeException if the result exceeds the supported range, + * or if the nano-of-second is invalid */ public static LocalDateTime ofEpochSecond(long epochSecond, int nanoOfSecond, ZoneOffset offset) { Objects.requireNonNull(offset, "offset"); + NANO_OF_SECOND.checkValidValue(nanoOfSecond); 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); + LocalTime time = LocalTime.ofNanoOfDay(secsOfDay * NANOS_PER_SECOND + nanoOfSecond); return new LocalDateTime(date, time); } @@ -408,10 +421,14 @@ /** * Obtains an instance of {@code LocalDateTime} from a temporal object. * <p> - * A {@code TemporalAccessor} represents some form of date and time information. - * This factory converts the arbitrary temporal object to an instance of {@code LocalDateTime}. + * This obtains an offset time based on the specified temporal. + * A {@code TemporalAccessor} represents an arbitrary set of date and time information, + * which this factory converts to an instance of {@code LocalDateTime}. * <p> - * The conversion extracts and combines {@code LocalDate} and {@code LocalTime}. + * The conversion extracts and combines the {@code LocalDate} and the + * {@code LocalTime} from the temporal object. + * Implementations are permitted to perform optimizations such as accessing + * those fields that are equivalent to the relevant objects. * <p> * This method matches the signature of the functional interface {@link TemporalQuery} * allowing it to be used as a query via method reference, {@code LocalDateTime::from}. @@ -424,7 +441,9 @@ if (temporal instanceof LocalDateTime) { return (LocalDateTime) temporal; } else if (temporal instanceof ZonedDateTime) { - return ((ZonedDateTime) temporal).getDateTime(); + return ((ZonedDateTime) temporal).toLocalDateTime(); + } else if (temporal instanceof OffsetDateTime) { + return ((OffsetDateTime) temporal).toLocalDateTime(); } try { LocalDate date = LocalDate.from(temporal); @@ -440,14 +459,14 @@ * Obtains an instance of {@code LocalDateTime} from a text string such as {@code 2007-12-03T10:15:30}. * <p> * The string must represent a valid date-time and is parsed using - * {@link java.time.format.DateTimeFormatters#isoLocalDateTime()}. + * {@link java.time.format.DateTimeFormatter#ISO_LOCAL_DATE_TIME}. * * @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()); + return parse(text, DateTimeFormatter.ISO_LOCAL_DATE_TIME); } /** @@ -535,7 +554,7 @@ * All other {@code ChronoField} instances will return false. * <p> * If the field is not a {@code ChronoField}, then the result of this method - * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)} + * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} * passing {@code this} as the argument. * Whether the field is supported is determined by the field. * @@ -548,7 +567,7 @@ ChronoField f = (ChronoField) field; return f.isDateField() || f.isTimeField(); } - return field != null && field.doIsSupported(this); + return field != null && field.isSupportedBy(this); } /** @@ -565,7 +584,7 @@ * All other {@code ChronoField} instances will throw a {@code DateTimeException}. * <p> * If the field is not a {@code ChronoField}, then the result of this method - * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)} + * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)} * passing {@code this} as the argument. * Whether the range can be obtained is determined by the field. * @@ -579,7 +598,7 @@ ChronoField f = (ChronoField) field; return (f.isTimeField() ? time.range(field) : date.range(field)); } - return field.doRange(this); + return field.rangeRefinedBy(this); } /** @@ -598,7 +617,7 @@ * All other {@code ChronoField} instances will throw a {@code DateTimeException}. * <p> * If the field is not a {@code ChronoField}, then the result of this method - * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)} + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} * passing {@code this} as the argument. Whether the value can be obtained, * and what the value represents, is determined by the field. * @@ -629,7 +648,7 @@ * All other {@code ChronoField} instances will throw a {@code DateTimeException}. * <p> * If the field is not a {@code ChronoField}, then the result of this method - * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)} + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} * passing {@code this} as the argument. Whether the value can be obtained, * and what the value represents, is determined by the field. * @@ -644,7 +663,7 @@ ChronoField f = (ChronoField) field; return (f.isTimeField() ? time.getLong(field) : date.getLong(field)); } - return field.doGet(this); + return field.getFrom(this); } //----------------------------------------------------------------------- @@ -657,7 +676,7 @@ * @return the date part of this date-time, not null */ @Override - public LocalDate getDate() { + public LocalDate toLocalDate() { return date; } @@ -667,7 +686,7 @@ * This method returns the primitive {@code int} value for the year. * <p> * The year returned by this method is proleptic as per {@code get(YEAR)}. - * To obtain the year-of-era, use {@code get(YEAR_OF_ERA}. + * To obtain the year-of-era, use {@code get(YEAR_OF_ERA)}. * * @return the year, from MIN_YEAR to MAX_YEAR */ @@ -753,7 +772,7 @@ * @return the time part of this date-time, not null */ @Override - public LocalTime getTime() { + public LocalTime toLocalTime() { return time; } @@ -797,7 +816,7 @@ /** * Returns an adjusted copy of this date-time. * <p> - * This returns a new {@code LocalDateTime}, based on this one, with the date-time adjusted. + * This returns a {@code LocalDateTime}, based on this one, with the date-time adjusted. * The adjustment takes place using the specified adjuster strategy object. * Read the documentation of the adjuster to understand what adjustment will be made. * <p> @@ -806,7 +825,7 @@ * 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}. + * such as {@link Month} and {@link java.time.MonthDay MonthDay}. * The adjuster is responsible for handling special cases, such as the varying * lengths of month and leap years. * <p> @@ -852,7 +871,7 @@ /** * Returns a copy of this date-time with the specified field set to a new value. * <p> - * This returns a new {@code LocalDateTime}, based on this one, with the value + * This returns a {@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 @@ -870,7 +889,7 @@ * All other {@code ChronoField} instances will throw a {@code DateTimeException}. * <p> * If the field is not a {@code ChronoField}, then the result of this method - * is obtained by invoking {@code TemporalField.doWith(Temporal, long)} + * is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)} * passing {@code this} as the argument. In this case, the field determines * whether and how to adjust the instant. * <p> @@ -892,7 +911,7 @@ return with(date.with(field, newValue), time); } } - return field.doWith(this, newValue); + return field.adjustInto(this, newValue); } //----------------------------------------------------------------------- @@ -935,8 +954,8 @@ * * @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 + * @throws DateTimeException if the day-of-month value is invalid, + * or if the day-of-month is invalid for the month-year */ public LocalDateTime withDayOfMonth(int dayOfMonth) { return with(date.withDayOfMonth(dayOfMonth), time); @@ -950,8 +969,8 @@ * * @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 + * @throws DateTimeException if the day-of-year value is invalid, + * or if the day-of-year is invalid for the year */ public LocalDateTime withDayOfYear(int dayOfYear) { return with(date.withDayOfYear(dayOfYear), time); @@ -1023,8 +1042,10 @@ * For example, truncating with the {@link ChronoUnit#MINUTES minutes} unit * will set the second-of-minute and nano-of-second field to zero. * <p> - * Not all units are accepted. The {@link ChronoUnit#DAYS days} unit and time - * units with an exact duration can be used, other units throw an exception. + * The unit must have a {@linkplain TemporalUnit#getDuration() duration} + * that divides into the length of a standard day without remainder. + * This includes all supplied time units on {@link ChronoUnit} and + * {@link ChronoUnit#DAYS DAYS}. Other units throw an exception. * <p> * This instance is immutable and unaffected by this method call. * @@ -1038,40 +1059,54 @@ //----------------------------------------------------------------------- /** - * Returns a copy of this date-time with the specified period added. + * Returns a copy of this date-time with the specified amount added. * <p> - * This method returns a new date-time based on this time with the specified period added. - * The adder is typically {@link Period} but may be any other type implementing - * the {@link TemporalAdder} interface. - * The calculation is delegated to the specified adjuster, which typically calls - * back to {@link #plus(long, TemporalUnit)}. + * This returns a {@code LocalDateTime}, based on this one, with the specified amount added. + * The amount is typically {@link Period} or {@link Duration} but may be + * any other type implementing the {@link TemporalAmount} interface. + * <p> + * The calculation is delegated to the amount object by calling + * {@link TemporalAmount#addTo(Temporal)}. The amount implementation is free + * to implement the addition in any way it wishes, however it typically + * calls back to {@link #plus(long, TemporalUnit)}. Consult the documentation + * of the amount implementation to determine if it can be successfully added. * <p> * This instance is immutable and unaffected by this method call. * - * @param adder the adder to use, not null + * @param amountToAdd the amount to add, 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); + public LocalDateTime plus(TemporalAmount amountToAdd) { + return (LocalDateTime) amountToAdd.addTo(this); } /** - * Returns a copy of this date-time with the specified period added. + * Returns a copy of this date-time with the specified amount added. * <p> - * This method returns a new date-time based on this date-time with the specified period added. - * This can be used to add any period that is defined by a unit, for example to add years, months or days. - * The unit is responsible for the details of the calculation, including the resolution - * of any edge cases in the calculation. + * This returns a {@code LocalDateTime}, based on this one, with the amount + * in terms of the unit added. If it is not possible to add the amount, because the + * unit is not supported or for some other reason, an exception is thrown. + * <p> + * If the field is a {@link ChronoUnit} then the addition is implemented here. + * Date units are added as per {@link LocalDate#plus(long, TemporalUnit)}. + * Time units are added as per {@link LocalTime#plus(long, TemporalUnit)} with + * any overflow in days added equivalent to using {@link #plusDays(long)}. + * <p> + * If the field is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)} + * passing {@code this} as the argument. In this case, the unit determines + * whether and how to perform the addition. * <p> * This instance is immutable and unaffected by this method call. * * @param amountToAdd the amount of the unit to add to the result, may be negative - * @param unit the unit of the period to add, not null - * @return a {@code LocalDateTime} based on this date-time with the specified period added, not null - * @throws DateTimeException if the unit cannot be added to this type + * @param unit the unit of the amount to add, not null + * @return a {@code LocalDateTime} based on this date-time with the specified amount added, not null + * @throws DateTimeException if the addition cannot be made + * @throws ArithmeticException if numeric overflow occurs */ @Override public LocalDateTime plus(long amountToAdd, TemporalUnit unit) { @@ -1088,7 +1123,7 @@ } return with(date.plus(amountToAdd, unit), time); } - return unit.doPlus(this, amountToAdd); + return unit.addTo(this, amountToAdd); } //----------------------------------------------------------------------- @@ -1237,40 +1272,47 @@ //----------------------------------------------------------------------- /** - * Returns a copy of this date-time with the specified period subtracted. + * Returns a copy of this date-time with the specified amount subtracted. * <p> - * This method returns a new date-time based on this time with the specified period subtracted. - * The subtractor is typically {@link Period} but may be any other type implementing - * the {@link TemporalSubtractor} interface. - * The calculation is delegated to the specified adjuster, which typically calls - * back to {@link #minus(long, TemporalUnit)}. + * This returns a {@code LocalDateTime}, based on this one, with the specified amount subtracted. + * The amount is typically {@link Period} or {@link Duration} but may be + * any other type implementing the {@link TemporalAmount} interface. + * <p> + * The calculation is delegated to the amount object by calling + * {@link TemporalAmount#subtractFrom(Temporal)}. The amount implementation is free + * to implement the subtraction in any way it wishes, however it typically + * calls back to {@link #minus(long, TemporalUnit)}. Consult the documentation + * of the amount implementation to determine if it can be successfully subtracted. * <p> * This instance is immutable and unaffected by this method call. * - * @param subtractor the subtractor to use, not null + * @param amountToSubtract the amount to subtract, 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); + public LocalDateTime minus(TemporalAmount amountToSubtract) { + return (LocalDateTime) amountToSubtract.subtractFrom(this); } /** - * Returns a copy of this date-time with the specified period subtracted. + * Returns a copy of this date-time with the specified amount subtracted. * <p> - * This method returns a new date-time based on this date-time with the specified period subtracted. - * This can be used to subtract any period that is defined by a unit, for example to subtract years, months or days. - * The unit is responsible for the details of the calculation, including the resolution - * of any edge cases in the calculation. + * This returns a {@code LocalDateTime}, based on this one, with the amount + * in terms of the unit subtracted. If it is not possible to subtract the amount, + * because the unit is not supported or for some other reason, an exception is thrown. + * <p> + * This method is equivalent to {@link #plus(long, TemporalUnit)} with the amount negated. + * See that method for a full description of how addition, and thus subtraction, works. * <p> * This instance is immutable and unaffected by this method call. * * @param amountToSubtract the amount of the unit to subtract from the result, may be negative - * @param unit the unit of the period to subtract, not null - * @return a {@code LocalDateTime} based on this date-time with the specified period subtracted, not null - * @throws DateTimeException if the unit cannot be added to this type + * @param unit the unit of the amount to subtract, not null + * @return a {@code LocalDateTime} based on this date-time with the specified amount subtracted, not null + * @throws DateTimeException if the subtraction cannot be made + * @throws ArithmeticException if numeric overflow occurs */ @Override public LocalDateTime minus(long amountToSubtract, TemporalUnit unit) { @@ -1472,8 +1514,12 @@ * @throws DateTimeException if unable to query (defined by the query) * @throws ArithmeticException if numeric overflow occurs (defined by the query) */ + @SuppressWarnings("unchecked") @Override // override for Javadoc public <R> R query(TemporalQuery<R> query) { + if (query == Queries.localDate()) { + return (R) date; + } return ChronoLocalDateTime.super.query(query); } @@ -1523,14 +1569,15 @@ * For example, the period in months between 2012-06-15T00:00 and 2012-08-14T23:59 * will only be one month as it is one minute short of two months. * <p> - * This method operates in association with {@link TemporalUnit#between}. - * The result of this method is a {@code long} representing the amount of - * the specified unit. By contrast, the result of {@code between} is an - * object that can be used directly in addition/subtraction: + * There are two equivalent ways of using this method. + * The first is to invoke this method. + * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: * <pre> - * long period = start.periodUntil(end, MONTHS); // this method - * dateTime.plus(MONTHS.between(start, end)); // use in plus/minus + * // these two lines are equivalent + * amount = start.periodUntil(end, MONTHS); + * amount = MONTHS.between(start, end); * </pre> + * The choice should be made based on which makes the code more readable. * <p> * The calculation is implemented in this method for {@link ChronoUnit}. * The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS}, @@ -1580,17 +1627,15 @@ } return date.periodUntil(endDate, unit); } - return unit.between(this, endDateTime).getAmount(); + return unit.between(this, endDateTime); } //----------------------------------------------------------------------- /** - * Returns an offset date-time formed from this date-time and the specified offset. + * Combines this time with a date to create an {@code OffsetTime}. * <p> - * This combines this date-time with the specified offset to form an {@code OffsetDateTime}. + * This returns an {@code OffsetTime} formed from this time at the specified offset. * All possible combinations of date-time and offset are valid. - * <p> - * This instance is immutable and unaffected by this method call. * * @param offset the offset to combine with, not null * @return the offset date-time formed from this date-time and the specified offset, not null @@ -1600,9 +1645,10 @@ } /** - * Returns a zoned date-time formed from this date-time and the specified time-zone. + * Combines this time with a time-zone to create a {@code ZonedDateTime}. * <p> - * This creates a zoned date-time matching the input date-time as closely as possible. + * This returns a {@code ZonedDateTime} formed from this date-time at the + * specified time-zone. The result will match this date-time as closely as possible. * Time-zone rules, such as daylight savings, mean that not every local date-time * is valid for the specified zone, thus the local date-time may be adjusted. * <p> @@ -1623,8 +1669,6 @@ * {@link ZonedDateTime#withLaterOffsetAtOverlap()} on the result of this method. * To throw an exception when there is a gap or overlap, use * {@link ZonedDateTime#ofStrict(LocalDateTime, ZoneOffset, ZoneId)}. - * <p> - * This instance is immutable and unaffected by this method call. * * @param zone the time-zone to use, not null * @return the zoned date-time formed from this date-time, not null @@ -1658,9 +1702,9 @@ } private int compareTo0(LocalDateTime other) { - int cmp = date.compareTo0(other.getDate()); + int cmp = date.compareTo0(other.toLocalDate()); if (cmp == 0) { - cmp = time.compareTo(other.getTime()); + cmp = time.compareTo(other.toLocalTime()); } return cmp; } @@ -1810,7 +1854,7 @@ * Outputs this date-time as a {@code String} using the formatter. * <p> * This date-time will be passed to the formatter - * {@link DateTimeFormatter#print(TemporalAccessor) print method}. + * {@link DateTimeFormatter#format(TemporalAccessor) format method}. * * @param formatter the formatter to use, not null * @return the formatted date-time string, not null
--- a/jdk/src/share/classes/java/time/LocalTime.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/time/LocalTime.java Tue Feb 19 22:23:34 2013 -0800 @@ -76,23 +76,17 @@ 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.TemporalAmount; import java.time.temporal.TemporalField; import java.time.temporal.TemporalQuery; -import java.time.temporal.TemporalSubtractor; import java.time.temporal.TemporalUnit; import java.time.temporal.ValueRange; import java.util.Objects; @@ -129,7 +123,7 @@ */ public static final LocalTime MIN; /** - * The minimum supported {@code LocalTime}, '23:59:59.999999999'. + * The maximum 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; @@ -273,21 +267,17 @@ // 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()); + long localSecond = now.getEpochSecond() + offset.getTotalSeconds(); // overflow caught later + int secsOfDay = (int) Math.floorMod(localSecond, SECONDS_PER_DAY); + return ofNanoOfDay(secsOfDay * NANOS_PER_SECOND + now.getNano()); } //------------------------get----------------------------------------------- /** * Obtains an instance of {@code LocalTime} from an hour and minute. * <p> - * The second and nanosecond fields will be set to zero by this factory method. - * <p> - * This factory may return a cached value, but applications must not rely on this. + * This returns a {@code LocalTime} with the specified hour and minute. + * The second and nanosecond fields will be set to zero. * * @param hour the hour-of-day to represent, from 0 to 23 * @param minute the minute-of-hour to represent, from 0 to 59 @@ -306,9 +296,8 @@ /** * Obtains an instance of {@code LocalTime} from an hour, minute and second. * <p> - * The nanosecond field will be set to zero by this factory method. - * <p> - * This factory may return a cached value, but applications must not rely on this. + * This returns a {@code LocalTime} with the specified hour, minute and second. + * The nanosecond field will be set to zero. * * @param hour the hour-of-day to represent, from 0 to 23 * @param minute the minute-of-hour to represent, from 0 to 59 @@ -329,7 +318,7 @@ /** * Obtains an instance of {@code LocalTime} from an hour, minute, second and nanosecond. * <p> - * This factory may return a cached value, but applications must not rely on this. + * This returns a {@code LocalTime} with the specified hour, minute, second and nanosecond. * * @param hour the hour-of-day to represent, from 0 to 23 * @param minute the minute-of-hour to represent, from 0 to 59 @@ -350,7 +339,8 @@ /** * Obtains an instance of {@code LocalTime} from a second-of-day value. * <p> - * This factory may return a cached value, but applications must not rely on this. + * This returns a {@code LocalTime} with the specified second-of-day. + * The nanosecond field will be set to zero. * * @param secondOfDay the second-of-day, from {@code 0} to {@code 24 * 60 * 60 - 1} * @return the local time, not null @@ -366,30 +356,9 @@ } /** - * Obtains an instance of {@code LocalTime} from a second-of-day value, with - * associated nanos of second. - * <p> - * This factory may return a cached value, but applications must not rely on this. - * - * @param secondOfDay the second-of-day, from {@code 0} to {@code 24 * 60 * 60 - 1} - * @param nanoOfSecond the nano-of-second, from 0 to 999,999,999 - * @return the local time, not null - * @throws DateTimeException if the either input value is invalid - */ - public static LocalTime ofSecondOfDay(long secondOfDay, int nanoOfSecond) { - SECOND_OF_DAY.checkValidValue(secondOfDay); - NANO_OF_SECOND.checkValidValue(nanoOfSecond); - int hours = (int) (secondOfDay / SECONDS_PER_HOUR); - secondOfDay -= hours * SECONDS_PER_HOUR; - int minutes = (int) (secondOfDay / SECONDS_PER_MINUTE); - secondOfDay -= minutes * SECONDS_PER_MINUTE; - return create(hours, minutes, (int) secondOfDay, nanoOfSecond); - } - - /** * Obtains an instance of {@code LocalTime} from a nanos-of-day value. * <p> - * This factory may return a cached value, but applications must not rely on this. + * This returns a {@code LocalTime} with the specified nanosecond-of-day. * * @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 @@ -410,10 +379,12 @@ /** * Obtains an instance of {@code LocalTime} from a temporal object. * <p> - * A {@code TemporalAccessor} represents some form of date and time information. - * This factory converts the arbitrary temporal object to an instance of {@code LocalTime}. + * This obtains a local time based on the specified temporal. + * A {@code TemporalAccessor} represents an arbitrary set of date and time information, + * which this factory converts to an instance of {@code LocalTime}. * <p> - * The conversion extracts the {@link ChronoField#NANO_OF_DAY NANO_OF_DAY} field. + * The conversion uses the {@link Queries#localTime()} query, which relies + * on extracting the {@link ChronoField#NANO_OF_DAY NANO_OF_DAY} field. * <p> * This method matches the signature of the functional interface {@link TemporalQuery} * allowing it to be used in queries via method reference, {@code LocalTime::from}. @@ -423,26 +394,11 @@ * @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(); + LocalTime time = temporal.query(Queries.localTime()); + if (time == null) { + throw new DateTimeException("Unable to obtain LocalTime from TemporalAccessor: " + temporal.getClass()); } - // 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); - } + return time; } //----------------------------------------------------------------------- @@ -450,14 +406,14 @@ * Obtains an instance of {@code LocalTime} from a text string such as {@code 10:15}. * <p> * The string must represent a valid time and is parsed using - * {@link java.time.format.DateTimeFormatters#isoLocalTime()}. + * {@link java.time.format.DateTimeFormatter#ISO_LOCAL_TIME}. * * @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()); + return parse(text, DateTimeFormatter.ISO_LOCAL_TIME); } /** @@ -539,7 +495,7 @@ * All other {@code ChronoField} instances will return false. * <p> * If the field is not a {@code ChronoField}, then the result of this method - * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)} + * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} * passing {@code this} as the argument. * Whether the field is supported is determined by the field. * @@ -551,7 +507,7 @@ if (field instanceof ChronoField) { return ((ChronoField) field).isTimeField(); } - return field != null && field.doIsSupported(this); + return field != null && field.isSupportedBy(this); } /** @@ -568,7 +524,7 @@ * All other {@code ChronoField} instances will throw a {@code DateTimeException}. * <p> * If the field is not a {@code ChronoField}, then the result of this method - * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)} + * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)} * passing {@code this} as the argument. * Whether the range can be obtained is determined by the field. * @@ -596,7 +552,7 @@ * All other {@code ChronoField} instances will throw a {@code DateTimeException}. * <p> * If the field is not a {@code ChronoField}, then the result of this method - * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)} + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} * passing {@code this} as the argument. Whether the value can be obtained, * and what the value represents, is determined by the field. * @@ -626,7 +582,7 @@ * All other {@code ChronoField} instances will throw a {@code DateTimeException}. * <p> * If the field is not a {@code ChronoField}, then the result of this method - * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)} + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} * passing {@code this} as the argument. Whether the value can be obtained, * and what the value represents, is determined by the field. * @@ -646,7 +602,7 @@ } return get0(field); } - return field.doGet(this); + return field.getFrom(this); } private int get0(TemporalField field) { @@ -711,7 +667,7 @@ /** * Returns an adjusted copy of this time. * <p> - * This returns a new {@code LocalTime}, based on this one, with the time adjusted. + * This returns a {@code LocalTime}, based on this one, with the time adjusted. * The adjustment takes place using the specified adjuster strategy object. * Read the documentation of the adjuster to understand what adjustment will be made. * <p> @@ -741,7 +697,7 @@ /** * Returns a copy of this time with the specified field set to a new value. * <p> - * This returns a new {@code LocalTime}, based on this one, with the value + * This returns a {@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 @@ -807,7 +763,7 @@ * All other {@code ChronoField} instances will throw a {@code DateTimeException}. * <p> * If the field is not a {@code ChronoField}, then the result of this method - * is obtained by invoking {@code TemporalField.doWith(Temporal, long)} + * is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)} * passing {@code this} as the argument. In this case, the field determines * whether and how to adjust the instant. * <p> @@ -843,7 +799,7 @@ } throw new DateTimeException("Unsupported field: " + field.getName()); } - return field.doWith(this, newValue); + return field.adjustInto(this, newValue); } //----------------------------------------------------------------------- @@ -924,8 +880,10 @@ * For example, truncating with the {@link ChronoUnit#MINUTES minutes} unit * will set the second-of-minute and nano-of-second field to zero. * <p> - * Not all units are accepted. The {@link ChronoUnit#DAYS days} unit and time - * units with an exact duration can be used, other units throw an exception. + * The unit must have a {@linkplain TemporalUnit#getDuration() duration} + * that divides into the length of a standard day without remainder. + * This includes all supplied time units on {@link ChronoUnit} and + * {@link ChronoUnit#DAYS DAYS}. Other units throw an exception. * <p> * This instance is immutable and unaffected by this method call. * @@ -936,56 +894,98 @@ 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"); + } + Duration unitDur = unit.getDuration(); + if (unitDur.getSeconds() > SECONDS_PER_DAY) { + throw new DateTimeException("Unit is too large to be used for truncation"); + } + long dur = unitDur.toNanos(); + if ((NANOS_PER_DAY % dur) != 0) { + throw new DateTimeException("Unit must divide into a standard day without remainder"); } 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); + return ofNanoOfDay((nod / dur) * dur); } //----------------------------------------------------------------------- /** - * Returns a copy of this date with the specified period added. + * Returns a copy of this time with the specified amount added. * <p> - * This method returns a new time based on this time with the specified period added. - * The adder is typically {@link Period} but may be any other type implementing - * the {@link TemporalAdder} interface. - * The calculation is delegated to the specified adjuster, which typically calls - * back to {@link #plus(long, TemporalUnit)}. + * This returns a {@code LocalTime}, based on this one, with the specified amount added. + * The amount is typically {@link Duration} but may be any other type implementing + * the {@link TemporalAmount} interface. + * <p> + * The calculation is delegated to the amount object by calling + * {@link TemporalAmount#addTo(Temporal)}. The amount implementation is free + * to implement the addition in any way it wishes, however it typically + * calls back to {@link #plus(long, TemporalUnit)}. Consult the documentation + * of the amount implementation to determine if it can be successfully added. * <p> * This instance is immutable and unaffected by this method call. * - * @param adder the adder to use, not null + * @param amountToAdd the amount to add, 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); + public LocalTime plus(TemporalAmount amountToAdd) { + return (LocalTime) amountToAdd.addTo(this); } /** - * Returns a copy of this time with the specified period added. + * Returns a copy of this time with the specified amount added. * <p> - * This method returns a new time based on this time with the specified period added. - * This can be used to add any period that is defined by a unit, for example to add hours, minutes or seconds. - * The unit is responsible for the details of the calculation, including the resolution - * of any edge cases in the calculation. + * This returns a {@code LocalTime}, based on this one, with the amount + * in terms of the unit added. If it is not possible to add the amount, because the + * unit is not supported or for some other reason, an exception is thrown. + * <p> + * If the field is a {@link ChronoUnit} then the addition is implemented here. + * The supported fields behave as follows: + * <ul> + * <li>{@code NANOS} - + * Returns a {@code LocalTime} with the specified number of nanoseconds added. + * This is equivalent to {@link #plusNanos(long)}. + * <li>{@code MICROS} - + * Returns a {@code LocalTime} with the specified number of microseconds added. + * This is equivalent to {@link #plusNanos(long)} with the amount + * multiplied by 1,000. + * <li>{@code MILLIS} - + * Returns a {@code LocalTime} with the specified number of milliseconds added. + * This is equivalent to {@link #plusNanos(long)} with the amount + * multiplied by 1,000,000. + * <li>{@code SECONDS} - + * Returns a {@code LocalTime} with the specified number of seconds added. + * This is equivalent to {@link #plusSeconds(long)}. + * <li>{@code MINUTES} - + * Returns a {@code LocalTime} with the specified number of minutes added. + * This is equivalent to {@link #plusMinutes(long)}. + * <li>{@code HOURS} - + * Returns a {@code LocalTime} with the specified number of hours added. + * This is equivalent to {@link #plusHours(long)}. + * <li>{@code HALF_DAYS} - + * Returns a {@code LocalTime} with the specified number of half-days added. + * This is equivalent to {@link #plusHours(long)} with the amount + * multiplied by 12. + * <li>{@code DAYS} - + * Returns a {@code LocalTime} with the specified number of days added. + * This returns {@code this} time. + * </ul> + * <p> + * All other {@code ChronoUnit} instances will throw a {@code DateTimeException}. + * <p> + * If the field is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)} + * passing {@code this} as the argument. In this case, the unit determines + * whether and how to perform the addition. * <p> * This instance is immutable and unaffected by this method call. * * @param amountToAdd the amount of the unit to add to the result, may be negative - * @param unit the unit of the period to add, not null - * @return a {@code LocalTime} based on this time with the specified period added, not null - * @throws DateTimeException if the unit cannot be added to this type + * @param unit the unit of the amount to add, not null + * @return a {@code LocalTime} based on this time with the specified amount added, not null + * @throws DateTimeException if the addition cannot be made + * @throws ArithmeticException if numeric overflow occurs */ @Override public LocalTime plus(long amountToAdd, TemporalUnit unit) { @@ -1003,7 +1003,7 @@ } throw new DateTimeException("Unsupported unit: " + unit.getName()); } - return unit.doPlus(this, amountToAdd); + return unit.addTo(this, amountToAdd); } //----------------------------------------------------------------------- @@ -1107,40 +1107,47 @@ //----------------------------------------------------------------------- /** - * Returns a copy of this time with the specified period subtracted. + * Returns a copy of this time with the specified amount subtracted. * <p> - * This method returns a new time based on this time with the specified period subtracted. - * The subtractor is typically {@link Period} but may be any other type implementing - * the {@link TemporalSubtractor} interface. - * The calculation is delegated to the specified adjuster, which typically calls - * back to {@link #minus(long, TemporalUnit)}. + * This returns a {@code LocalTime}, based on this one, with the specified amount subtracted. + * The amount is typically {@link Duration} but may be any other type implementing + * the {@link TemporalAmount} interface. + * <p> + * The calculation is delegated to the amount object by calling + * {@link TemporalAmount#subtractFrom(Temporal)}. The amount implementation is free + * to implement the subtraction in any way it wishes, however it typically + * calls back to {@link #minus(long, TemporalUnit)}. Consult the documentation + * of the amount implementation to determine if it can be successfully subtracted. * <p> * This instance is immutable and unaffected by this method call. * - * @param subtractor the subtractor to use, not null + * @param amountToSubtract the amount to subtract, 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); + public LocalTime minus(TemporalAmount amountToSubtract) { + return (LocalTime) amountToSubtract.subtractFrom(this); } /** - * Returns a copy of this time with the specified period subtracted. + * Returns a copy of this time with the specified amount subtracted. * <p> - * This method returns a new time based on this time with the specified period subtracted. - * This can be used to subtract any period that is defined by a unit, for example to subtract hours, minutes or seconds. - * The unit is responsible for the details of the calculation, including the resolution - * of any edge cases in the calculation. + * This returns a {@code LocalTime}, based on this one, with the amount + * in terms of the unit subtracted. If it is not possible to subtract the amount, + * because the unit is not supported or for some other reason, an exception is thrown. + * <p> + * This method is equivalent to {@link #plus(long, TemporalUnit)} with the amount negated. + * See that method for a full description of how addition, and thus subtraction, works. * <p> * This instance is immutable and unaffected by this method call. * * @param amountToSubtract the amount of the unit to subtract from the result, may be negative - * @param unit the unit of the period to subtract, not null - * @return a {@code LocalTime} based on this time with the specified period subtracted, not null - * @throws DateTimeException if the unit cannot be added to this type + * @param unit the unit of the amount to subtract, not null + * @return a {@code LocalTime} based on this time with the specified amount subtracted, not null + * @throws DateTimeException if the subtraction cannot be made + * @throws ArithmeticException if numeric overflow occurs */ @Override public LocalTime minus(long amountToSubtract, TemporalUnit unit) { @@ -1230,13 +1237,17 @@ @SuppressWarnings("unchecked") @Override public <R> R query(TemporalQuery<R> query) { - if (query == Queries.precision()) { + if (query == Queries.chronology() || query == Queries.zoneId() || query == Queries.zone() || query == Queries.offset()) { + return null; + } else if (query == Queries.localTime()) { + return (R) this; + } else if (query == Queries.localDate()) { + return null; + } else if (query == Queries.precision()) { return (R) NANOS; } // inline TemporalAccessor.super.query(query) as an optimization - if (query == Queries.chrono() || query == Queries.zoneId() || query == Queries.zone() || query == Queries.offset()) { - return null; - } + // non-JDK classes are not permitted to make this optimization return query.queryFrom(this); } @@ -1285,14 +1296,15 @@ * For example, the period in hours between 11:30 and 13:29 will only * be one hour as it is one minute short of two hours. * <p> - * This method operates in association with {@link TemporalUnit#between}. - * The result of this method is a {@code long} representing the amount of - * the specified unit. By contrast, the result of {@code between} is an - * object that can be used directly in addition/subtraction: + * There are two equivalent ways of using this method. + * The first is to invoke this method. + * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: * <pre> - * long period = start.periodUntil(end, HOURS); // this method - * dateTime.plus(HOURS.between(start, end)); // use in plus/minus + * // these two lines are equivalent + * amount = start.periodUntil(end, MINUTES); + * amount = MINUTES.between(start, end); * </pre> + * The choice should be made based on which makes the code more readable. * <p> * The calculation is implemented in this method for {@link ChronoUnit}. * The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS}, @@ -1332,17 +1344,15 @@ } throw new DateTimeException("Unsupported unit: " + unit.getName()); } - return unit.between(this, endTime).getAmount(); + return unit.between(this, endTime); } //----------------------------------------------------------------------- /** - * Returns a local date-time formed from this time at the specified date. + * Combines this time with a date to create a {@code LocalDateTime}. * <p> - * This combines this time with the specified date to form a {@code LocalDateTime}. + * This returns a {@code LocalDateTime} formed from this time at the specified date. * All possible combinations of date and time are valid. - * <p> - * This instance is immutable and unaffected by this method call. * * @param date the date to combine with, not null * @return the local date-time formed from this time and the specified date, not null @@ -1352,12 +1362,10 @@ } /** - * Returns an offset time formed from this time and the specified offset. + * Combines this time with a date to create an {@code OffsetTime}. * <p> - * This combines this time with the specified offset to form an {@code OffsetTime}. + * This returns an {@code OffsetTime} formed from this time at the specified offset. * All possible combinations of time and offset are valid. - * <p> - * This instance is immutable and unaffected by this method call. * * @param offset the offset to combine with, not null * @return the offset time formed from this time and the specified offset, not null @@ -1529,7 +1537,7 @@ * Outputs this time as a {@code String} using the formatter. * <p> * This time will be passed to the formatter - * {@link DateTimeFormatter#print(TemporalAccessor) print method}. + * {@link DateTimeFormatter#format(TemporalAccessor) format method}. * * @param formatter the formatter to use, not null * @return the formatted time string, not null @@ -1537,7 +1545,7 @@ */ public String toString(DateTimeFormatter formatter) { Objects.requireNonNull(formatter, "formatter"); - return formatter.print(this); + return formatter.format(this); } //-----------------------------------------------------------------------
--- a/jdk/src/share/classes/java/time/Month.java Tue Feb 19 20:00:02 2013 +0400 +++ b/jdk/src/share/classes/java/time/Month.java Tue Feb 19 22:23:34 2013 -0800 @@ -64,11 +64,11 @@ import static java.time.temporal.ChronoField.MONTH_OF_YEAR; import static java.time.temporal.ChronoUnit.MONTHS; +import java.time.chrono.Chronology; +import java.time.chrono.IsoChronology; 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; @@ -192,8 +192,9 @@ /** * Obtains an instance of {@code Month} from a temporal object. * <p> - * A {@code TemporalAccessor} represents some form of date and time information. - * This factory converts the arbitrary temporal object to an instance of {@code Month}. + * This obtains a month based on the specified temporal. + * A {@code TemporalAccessor} represents an arbitrary set of date and time information, + * which this factory converts to an instance of {@code Month}. * <p> * The conversion extracts the {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} field. * The extraction is only permitted if the temporal object has an ISO @@ -211,7 +212,7 @@ return (Month) temporal; } try { - if (ISOChrono.INSTANCE.equals(Chrono.from(temporal)) == false) { + if (IsoChronology.INSTANCE.equals(Chronology.from(temporal)) == false) { temporal = LocalDate.from(temporal); } return of(temporal.get(MONTH_OF_YEAR)); @@ -237,8 +238,9 @@ /** * Gets the textual representation, such as 'Jan' or 'December'. * <p> - * This returns the textual name used to identify the month-of-year. - * The parameters control the length of the returned text and the locale. + * This returns the textual name used to identify the month-of-year, + * suitable for presentation to the user. + * The parameters control the style of the returned text and the locale. * <p> * If no textual mapping is found then the {@link #getValue() numeric value} is returned. * @@ -246,8 +248,8 @@ * @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); + public String getDisplayName(TextStyle style, Locale locale) { + return new DateTimeFormatterBuilder().appendText(MONTH_OF_YEAR, style).toFormatter(locale).format(this); } //----------------------------------------------------------------------- @@ -263,7 +265,7 @@ * All other {@code ChronoField} instances will return false. * <p> * If the field is not a {@code ChronoField}, then the result of this method - * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)} + * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} * passing {@code this} as the argument. * Whether the field is supported is determined by the field. * @@ -275,7 +277,7 @@ if (field instanceof ChronoField) { return field == MONTH_OF_YEAR; } - return field != null && field.doIsSupported(this); + return field != null && field.isSupportedBy(this); } /** @@ -291,7 +293,7 @@ * All other {@code ChronoField} instances will throw a {@code DateTimeException}. * <p> * If the field is not a {@code ChronoField}, then the result of this method - * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)} + * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)} * passing {@code this} as the argument. * Whether the range can be obtained is determined by the field. * @@ -320,15 +322,13 @@ * All other {@code ChronoField} instances will throw a {@code DateTimeException}. * <p> * If the field is not a {@code ChronoField}, then the result of this method - * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)} + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} * passing {@code this} as the argument. Whether the value can be obtained, * and what the value represents, is determined by the field. * * @param field the field to get, not null * @return the value for the field, within the valid range of values * @throws DateTimeException if a value for the field cannot be obtained - * @throws DateTimeException if the range of valid values for the field exceeds an {@code int} - * @throws DateTimeException if the value is outside the range of valid values for the field * @throws ArithmeticException if numeric overflow occurs */ @Override @@ -351,7 +351,7 @@ * All other {@code ChronoField} instances will throw a {@code DateTimeException}. * <p> * If the field is not a {@code ChronoField}, then the result of this method - * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)} + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} * passing {@code this} as the argument. Whether the value can be obtained, * and what the value represents, is determined by the field. * @@ -367,7 +367,7 @@ } else if (field instanceof ChronoField) { throw new DateTimeException("Unsupported field: " + field.getName()); } - return field.doGet(this); + return field.getFrom(this); } //----------------------------------------------------------------------- @@ -554,8 +554,8 @@ @SuppressWarnings("unchecked") @Override public <R> R query(TemporalQuery<R> query) { - if (query == Queries.chrono()) { - return (R) ISOChrono.INSTANCE; + if (query == Queries.chronology()) { + return (R) IsoChronology.INSTANCE; } else if (query == Queries.precision()) { return (R) MONTHS; } @@ -599,7 +599,7 @@ */ @Override public Temporal adjustInto(Temporal temporal) { - if (Chrono.from(temporal).equals(ISOChrono.INSTANCE) == false) { + if (Chronology.from(temporal).equals(IsoChronology.INSTANCE) == false) { throw new DateTimeException("Adjustment only supported on ISO date-time"); } return temporal.with(MONTH_OF_YEAR, getValue());
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/time/MonthDay.java Tue Feb 19 22:23:34 2013 -0800 @@ -0,0 +1,776 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * 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_MONTH; +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.time.chrono.Chronology; +import java.time.chrono.IsoChronology; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.DateTimeParseException; +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.util.Objects; + +/** + * A month-day in the ISO-8601 calendar system, such as {@code --12-03}. + * <p> + * {@code MonthDay} is an immutable date-time object that represents the combination + * of a year and month. Any field that can be derived from a month and day, such as + * quarter-of-year, can be obtained. + * <p> + * This class does not store or represent a year, time or time-zone. + * For example, the value "December 3rd" can be stored in a {@code MonthDay}. + * <p> + * Since a {@code MonthDay} does not possess a year, the leap day of + * February 29th is considered valid. + * <p> + * This class implements {@link TemporalAccessor} rather than {@link Temporal}. + * This is because it is not possible to define whether February 29th is valid or not + * without external information, preventing the implementation of plus/minus. + * Related to this, {@code MonthDay} only provides access to query and set the fields + * {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH}. + * <p> + * The ISO-8601 calendar system is the modern civil calendar system used today + * in most of the world. It is equivalent to the proleptic Gregorian calendar + * system, in which today's rules for leap years are applied for all time. + * For most applications written today, the ISO-8601 rules are entirely suitable. + * However, any application that makes use of historical dates, and requires them + * to be accurate will find the ISO-8601 approach unsuitable. + * + * <h3>Specification for implementors</h3> + * This class is immutable and thread-safe. + * + * @since 1.8 + */ +public final class MonthDay + implements TemporalAccessor, TemporalAdjuster, Comparable<MonthDay>, Serializable { + + /** + * Serialization version. + */ + private static final long serialVersionUID = -939150713474957432L; + /** + * Parser. + */ + private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder() + .appendLiteral("--") + .appendValue(MONTH_OF_YEAR, 2) + .appendLiteral('-') + .appendValue(DAY_OF_MONTH, 2) + .toFormatter(); + + /** + * The month-of-year, not null. + */ + private final int month; + /** + * The day-of-month. + */ + private final int day; + + //----------------------------------------------------------------------- + /** + * Obtains the current month-day from the system clock in the default time-zone. + * <p> + * This will query the {@link java.time.Clock#systemDefaultZone() system clock} in the default + * time-zone to obtain the current month-day. + * <p> + * Using this method will prevent the ability to use an alternate clock for testing + * because the clock is hard-coded. + * + * @return the current month-day using the system clock and default time-zone, not null + */ + public static MonthDay now() { + return now(Clock.systemDefaultZone()); + } + + /** + * Obtains the current month-day from the system clock in the specified time-zone. + * <p> + * This will query the {@link Clock#system(java.time.ZoneId) system clock} to obtain the current month-day. + * Specifying the time-zone avoids dependence on the default time-zone. + * <p> + * Using this method will prevent the ability to use an alternate clock for testing + * because the clock is hard-coded. + * + * @param zone the zone ID to use, not null + * @return the current month-day using the system clock, not null + */ + public static MonthDay now(ZoneId zone) { + return now(Clock.system(zone)); + } + + /** + * Obtains the current month-day from the specified clock. + * <p> + * This will query the specified clock to obtain the current month-day. + * Using this method allows the use of an alternate clock for testing. + * The alternate clock may be introduced using {@link Clock dependency injection}. + * + * @param clock the clock to use, not null + * @return the current month-day, not null + */ + public static MonthDay now(Clock clock) { + final LocalDate now = LocalDate.now(clock); // called once + return MonthDay.of(now.getMonth(), now.getDayOfMonth()); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code MonthDay}. + * <p> + * The day-of-month must be valid for the month within a leap year. + * Hence, for February, day 29 is valid. + * <p> + * For example, passing in April and day 31 will throw an exception, as + * there can never be April 31st in any year. By contrast, passing in + * February 29th is permitted, as that month-day can sometimes be valid. + * + * @param month the month-of-year to represent, not null + * @param dayOfMonth the day-of-month to represent, from 1 to 31 + * @return the month-day, not null + * @throws DateTimeException if the value of any field is out of range, + * or if the day-of-month is invalid for the month + */ + public static MonthDay of(Month month, int dayOfMonth) { + Objects.requireNonNull(month, "month"); + DAY_OF_MONTH.checkValidValue(dayOfMonth); + if (dayOfMonth > month.maxLength()) { + throw new DateTimeException("Illegal value for DayOfMonth field, value " + dayOfMonth + + " is not valid for month " + month.name()); + } + return new MonthDay(month.getValue(), dayOfMonth); + } + + /** + * Obtains an instance of {@code MonthDay}. + * <p> + * The day-of-month must be valid for the month within a leap year. + * Hence, for month 2 (February), day 29 is valid. + * <p> + * For example, passing in month 4 (April) and day 31 will throw an exception, as + * there can never be April 31st in any year. By contrast, passing in + * February 29th is permitted, as that month-day can sometimes be valid. + * + * @param month the month-of-year to represent, from 1 (January) to 12 (December) + * @param dayOfMonth the day-of-month to represent, from 1 to 31 + * @return the month-day, not null + * @throws DateTimeException if the value of any field is out of range, + * or if the day-of-month is invalid for the month + */ + public static MonthDay of(int month, int dayOfMonth) { + return of(Month.of(month), dayOfMonth); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code MonthDay} from a temporal object. + * <p> + * This obtains a month-day based on the specified temporal. + * A {@code TemporalAccessor} represents an arbitrary set of date and time information, + * which this factory converts to an instance of {@code MonthDay}. + * <p> + * The conversion extracts the {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} and + * {@link ChronoField#DAY_OF_MONTH DAY_OF_MONTH} fields. + * The extraction is only permitted if the date-time has an ISO chronology. + * <p> + * This method matches the signature of the functional interface {@link TemporalQuery} + * allowing it to be used in queries via method reference, {@code MonthDay::from}. + * + * @param temporal the temporal object to convert, not null + * @return the month-day, not null + * @throws DateTimeException if unable to convert to a {@code MonthDay} + */ + public static MonthDay from(TemporalAccessor temporal) { + if (temporal instanceof MonthDay) { + return (MonthDay) temporal; + } + try { + if (IsoChronology.INSTANCE.equals(Chronology.from(temporal)) == false) { + temporal = LocalDate.from(temporal); + } + return of(temporal.get(MONTH_OF_YEAR), temporal.get(DAY_OF_MONTH)); + } catch (DateTimeException ex) { + throw new DateTimeException("Unable to obtain MonthDay from TemporalAccessor: " + temporal.getClass(), ex); + } + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code MonthDay} from a text string such as {@code --12-03}. + * <p> + * The string must represent a valid month-day. + * The format is {@code --MM-dd}. + * + * @param text the text to parse such as "--12-03", not null + * @return the parsed month-day, not null + * @throws DateTimeParseException if the text cannot be parsed + */ + public static MonthDay parse(CharSequence text) { + return parse(text, PARSER); + } + + /** + * Obtains an instance of {@code MonthDay} from a text string using a specific formatter. + * <p> + * The text is parsed using the formatter, returning a month-day. + * + * @param text the text to parse, not null + * @param formatter the formatter to use, not null + * @return the parsed month-day, not null + * @throws DateTimeParseException if the text cannot be parsed + */ + public static MonthDay parse(CharSequence text, DateTimeFormatter formatter) { + Objects.requireNonNull(formatter, "formatter"); + return formatter.parse(text, MonthDay::from); + } + + //----------------------------------------------------------------------- + /** + * Constructor, previously validated. + * + * @param month the month-of-year to represent, validated from 1 to 12 + * @param dayOfMonth the day-of-month to represent, validated from 1 to 29-31 + */ + private MonthDay(int month, int dayOfMonth) { + this.month = month; + this.day = dayOfMonth; + } + + //----------------------------------------------------------------------- + /** + * Checks if the specified field is supported. + * <p> + * This checks if this month-day can be queried for the specified field. + * If false, then calling the {@link #range(TemporalField) range} and + * {@link #get(TemporalField) get} methods will throw an exception. + * <p> + * If the field is a {@link ChronoField} then the query is implemented here. + * The supported fields are: + * <ul> + * <li>{@code MONTH_OF_YEAR} + * <li>{@code YEAR} + * </ul> + * All other {@code ChronoField} instances will return false. + * <p> + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the field is supported is determined by the field. + * + * @param field the field to check, null returns false + * @return true if the field is supported on this month-day, false if not + */ + @Override + public boolean isSupported(TemporalField field) { + if (field instanceof ChronoField) { + return field == MONTH_OF_YEAR || field == DAY_OF_MONTH; + } + return field != null && field.isSupportedBy(this); + } + + /** + * Gets the range of valid values for the specified field. + * <p> + * The range object expresses the minimum and maximum valid values for a field. + * This month-day is used to enhance the accuracy of the returned range. + * If it is not possible to return the range, because the field is not supported + * or for some other reason, an exception is thrown. + * <p> + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return + * appropriate range instances. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + * <p> + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the range can be obtained is determined by the field. + * + * @param field the field to query the range for, not null + * @return the range of valid values for the field, not null + * @throws DateTimeException if the range for the field cannot be obtained + */ + @Override + public ValueRange range(TemporalField field) { + if (field == MONTH_OF_YEAR) { + return field.range(); + } else if (field == DAY_OF_MONTH) { + return ValueRange.of(1, getMonth().minLength(), getMonth().maxLength()); + } + return TemporalAccessor.super.range(field); + } + + /** + * Gets the value of the specified field from this month-day as an {@code int}. + * <p> + * This queries this month-day for the value for the specified field. + * The returned value will always be within the valid range of values for the field. + * If it is not possible to return the value, because the field is not supported + * or for some other reason, an exception is thrown. + * <p> + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return valid + * values based on this month-day. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + * <p> + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} + * passing {@code this} as the argument. Whether the value can be obtained, + * and what the value represents, is determined by the field. + * + * @param field the field to get, not null + * @return the value for the field + * @throws DateTimeException if a value for the field cannot be obtained + * @throws ArithmeticException if numeric overflow occurs + */ + @Override // override for Javadoc + public int get(TemporalField field) { + return range(field).checkValidIntValue(getLong(field), field); + } + + /** + * Gets the value of the specified field from this month-day as a {@code long}. + * <p> + * This queries this month-day for the value for the specified field. + * If it is not possible to return the value, because the field is not supported + * or for some other reason, an exception is thrown. + * <p> + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return valid + * values based on this month-day. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + * <p> + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} + * passing {@code this} as the argument. Whether the value can be obtained, + * and what the value represents, is determined by the field. + * + * @param field the field to get, not null + * @return the value for the field + * @throws DateTimeException if a value for the field cannot be obtained + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public long getLong(TemporalField field) { + if (field instanceof ChronoField) { + switch ((ChronoField) field) { + // alignedDOW and alignedWOM not supported because they cannot be set in with() + case DAY_OF_MONTH: return day; + case MONTH_OF_YEAR: return month; + } + throw new DateTimeException("Unsupported field: " + field.getName()); + } + return field.getFrom(this); + } + + //----------------------------------------------------------------------- + /** + * Gets the month-of-year field from 1 to 12. + * <p> + * This method returns the month as an {@code int} from 1 to 12. + * Application code is frequently clearer if the enum {@link Month} + * is used by calling {@link #getMonth()}. + * + * @return the month-of-year, from 1 to 12 + * @see #getMonth() + */ + public int getMonthValue() { + return month; + } + + /** + * Gets the month-of-year field using the {@code Month} enum. + * <p> + * This method returns the enum {@link Month} for the month. + * This avoids confusion as to what {@code int} values mean. + * If you need access to the primitive {@code int} value then the enum + * provides the {@link Month#getValue() int value}. + * + * @return the month-of-year, not null + * @see #getMonthValue() + */ + public Month getMonth() { + return Month.of(month); + } + + /** + * Gets the day-of-month field. + * <p> + * This method returns the primitive {@code int} value for the day-of-month. + * + * @return the day-of-month, from 1 to 31 + */ + public int getDayOfMonth() { + return day; + } + + //----------------------------------------------------------------------- + /** + * Checks if the year is valid for this month-day. + * <p> + * This method checks whether this month and day and the input year form + * a valid date. This can only return false for February 29th. + * + * @param year the year to validate, an out of range value returns false + * @return true if the year is valid for this month-day + * @see Year#isValidMonthDay(MonthDay) + */ + public boolean isValidYear(int year) { + return (day == 29 && month == 2 && Year.isLeap(year) == false) == false; + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this {@code MonthDay} with the month-of-year altered. + * <p> + * This returns a month-day with the specified month. + * If the day-of-month is invalid for the specified month, the day will + * be adjusted to the last valid day-of-month. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param month the month-of-year to set in the returned month-day, from 1 (January) to 12 (December) + * @return a {@code MonthDay} based on this month-day with the requested month, not null + * @throws DateTimeException if the month-of-year value is invalid + */ + public MonthDay withMonth(int month) { + return with(Month.of(month)); + } + + /** + * Returns a copy of this {@code MonthDay} with the month-of-year altered. + * <p> + * This returns a month-day with the specified month. + * If the day-of-month is invalid for the specified month, the day will + * be adjusted to the last valid day-of-month. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param month the month-of-year to set in the returned month-day, not null + * @return a {@code MonthDay} based on this month-day with the requested month, not null + */ + public MonthDay with(Month month) { + Objects.requireNonNull(month, "month"); + if (month.getValue() == this.month) { + return this; + } + int day = Math.min(this.day, month.maxLength()); + return new MonthDay(month.getValue(), day); + } + + /** + * Returns a copy of this {@code MonthDay} with the day-of-month altered. + * <p> + * This returns a month-day with the specified day-of-month. + * If the day-of-month is invalid for the month, an exception is thrown. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param dayOfMonth the day-of-month to set in the return month-day, from 1 to 31 + * @return a {@code MonthDay} based on this month-day with the requested day, not null + * @throws DateTimeException if the day-of-month value is invalid, + * or if the day-of-month is invalid for the month + */ + public MonthDay withDayOfMonth(int dayOfMonth) { + if (dayOfMonth == this.day) { + return this; + } + return of(month, dayOfMonth); + } + + //----------------------------------------------------------------------- + /** + * Queries this month-day using the specified query. + * <p> + * This queries this month-day using the specified query strategy object. + * The {@code TemporalQuery} object defines the logic to be used to + * obtain the result. Read the documentation of the query to understand + * what the result of this method will be. + * <p> + * The result of this method is obtained by invoking the + * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the + * specified query passing {@code this} as the argument. + * + * @param <R> the type of the result + * @param query the query to invoke, not null + * @return the query result, null may be returned (defined by the query) + * @throws DateTimeException if unable to query (defined by the query) + * @throws ArithmeticException if numeric overflow occurs (defined by the query) + */ + @SuppressWarnings("unchecked") + @Override + public <R> R query(TemporalQuery<R> query) { + if (query == Queries.chronology()) { + return (R) IsoChronology.INSTANCE; + } + return TemporalAccessor.super.query(query); + } + + /** + * Adjusts the specified temporal object to have this month-day. + * <p> + * This returns a temporal object of the same observable type as the input + * with the month and day-of-month changed to be the same as this. + * <p> + * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)} + * twice, passing {@link ChronoField#MONTH_OF_YEAR} and + * {@link ChronoField#DAY_OF_MONTH} as the fields. + * If the specified temporal object does not use the ISO calendar system then + * a {@code DateTimeException} is thrown. + * <p> + * In most cases, it is clearer to reverse the calling pattern by using + * {@link Temporal#with(TemporalAdjuster)}: + * <pre> + * // these two lines are equivalent, but the second approach is recommended + * temporal = thisMonthDay.adjustInto(temporal); + * temporal = temporal.with(thisMonthDay); + * </pre> + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param temporal the target object to be adjusted, not null + * @return the adjusted object, not null + * @throws DateTimeException if unable to make the adjustment + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public Temporal adjustInto(Temporal temporal) { + if (Chronology.from(temporal).equals(IsoChronology.INSTANCE) == false) { + throw new DateTimeException("Adjustment only supported on ISO date-time"); + } + temporal = temporal.with(MONTH_OF_YEAR, month); + return temporal.with(DAY_OF_MONTH, Math.min(temporal.range(DAY_OF_MONTH).getMaximum(), day)); + } + + //----------------------------------------------------------------------- + /** + * Combines this month-day with a year to create a {@code LocalDate}. + * <p> + * This returns a {@code LocalDate} formed from this month-day and the specified year. + * <p> + * A month-day of February 29th will be adjusted to February 28th in the resulting + * date if the year is not a leap year. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param year the year to use, from MIN_YEAR to MAX_YEAR + * @return the local date formed from this month-day and the specified year, not null + * @throws DateTimeException if the year is outside the valid range of years + */ + public LocalDate atYear(int year) { + return LocalDate.of(year, month, isValidYear(year) ? day : 28); + } + + //----------------------------------------------------------------------- + /** + * Compares this month-day to another month-day. + * <p> + * The comparison is based first on value of the month, then on the value of the day. + * It is "consistent with equals", as defined by {@link Comparable}. + * + * @param other the other month-day to compare to, not null + * @return the comparator value, negative if less, positive if greater + */ + @Override + public int compareTo(MonthDay other) { + int cmp = (month - other.month); + if (cmp == 0) { + cmp = (day - other.day); + } + return cmp; + } + + /** + * Is this month-day after the specified month-day. + * + * @param other the other month-day to compare to, not null + * @return true if this is after the specified month-day + */ + public boolean isAfter(MonthDay other) { + return compareTo(other) > 0; + } + + /** + * Is this month-day before the specified month-day. + * + * @param other the other month-day to compare to, not null + * @return true if this point is before the specified month-day + */ + public boolean isBefore(MonthDay other) { + return compareTo(other) < 0; + } + + //----------------------------------------------------------------------- + /** + * Checks if this month-day is equal to another month-day. + * <p> + * The comparison is based on the time-line position of the month-day within a year. + * + * @param obj the object to check, null returns false + * @return true if this is equal to the other month-day + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof MonthDay) { + MonthDay other = (MonthDay) obj; + return month == other.month && day == other.day; + } + return false; + } + + /** + * A hash code for this month-day. + * + * @return a suitable hash code + */ + @Override + public int hashCode() { + return (month << 6) + day; + } + + //----------------------------------------------------------------------- + /** + * Outputs this month-day as a {@code String}, such as {@code --12-03}. + * <p> + * The output will be in the format {@code --MM-dd}: + * + * @return a string representation of this month-day, not null + */ + @Override + public String toString() { + return new StringBuilder(10).append("--") + .append(month < 10 ? "0" : "").append(month) + .append(day < 10 ? "-0" : "-").append(day) + .toString(); + } + + /** + * Outputs this month-day as a {@code String} using the formatter. + * <p> + * This month-day will be passed to the formatter + * {@link DateTimeFormatter#format(TemporalAccessor) format method}. + * + * @param formatter the formatter to use, not null + * @return the formatted month-day string, not null + * @throws DateTimeException if an error occurs during printing + */ + public String toString(DateTimeFormatter formatter) { + Objects.requireNonNull(formatter, "formatter"); + return formatter.format(this); + } + + //----------------------------------------------------------------------- + /** + * Writes the object using a + * <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>. + * <pre> + * out.writeByte(13); // identifies this as a MonthDay + * out.writeByte(month); + * out.writeByte(day); + * </pre> + * + * @return the instance of {@code Ser}, not null + */ + private Object writeReplace() { + return new Ser(Ser.MONTH_DAY_TYPE, this); + } + + /** + * Defend against malicious streams. + * @return never + * @throws InvalidObjectException always + */ + private Object readResolve() throws ObjectStreamException { + throw new InvalidObjectException("Deserialization via serialization delegate"); + } + + void writeExternal(DataOutput out) throws IOException { + out.writeByte(month); + out.writeByte(day); + } + + static MonthDay readExternal(DataInput in) throws IOException { + byte month = in.readByte(); + byte day = in.readByte(); + return MonthDay.of(month, day); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/time/OffsetDateTime.java Tue Feb 19 22:23:34 2013 -0800 @@ -0,0 +1,1866 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * 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.EPOCH_DAY; +import static java.time.temporal.ChronoField.INSTANT_SECONDS; +import static java.time.temporal.ChronoField.NANO_OF_DAY; +import static java.time.temporal.ChronoField.OFFSET_SECONDS; +import static java.time.temporal.ChronoUnit.NANOS; + +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.time.chrono.IsoChronology; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoField; +import java.time.temporal.ChronoUnit; +import java.time.temporal.Queries; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalAmount; +import java.time.temporal.TemporalField; +import java.time.temporal.TemporalQuery; +import java.time.temporal.TemporalUnit; +import java.time.temporal.ValueRange; +import java.time.zone.ZoneRules; +import java.util.Comparator; +import java.util.Objects; + +/** + * A date-time with an offset from UTC/Greenwich in the ISO-8601 calendar system, + * such as {@code 2007-12-03T10:15:30+01:00}. + * <p> + * {@code OffsetDateTime} is an immutable representation of a date-time with an offset. + * This class stores all date and time fields, to a precision of nanoseconds, + * as well as the offset from UTC/Greenwich. For example, the value + * "2nd October 2007 at 13:45.30.123456789 +02:00" can be stored in an {@code OffsetDateTime}. + * <p> + * {@code OffsetDateTime}, {@link java.time.ZonedDateTime} and {@link java.time.Instant} all store an instant + * on the time-line to nanosecond precision. + * {@code Instant} is the simplest, simply representing the instant. + * {@code OffsetDateTime} adds to the instant the offset from UTC/Greenwich, which allows + * the local date-time to be obtained. + * {@code ZonedDateTime} adds full time-zone rules. + * <p> + * It is intended that {@code ZonedDateTime} or {@code Instant} is used to model data + * in simpler applications. This class may be used when modeling date-time concepts in + * more detail, or when communicating to a database or in a network protocol. + * + * <h3>Specification for implementors</h3> + * This class is immutable and thread-safe. + * + * @since 1.8 + */ +public final class OffsetDateTime + implements Temporal, TemporalAdjuster, Comparable<OffsetDateTime>, Serializable { + + /** + * The minimum supported {@code OffsetDateTime}, '-999999999-01-01T00:00:00+18:00'. + * This is the local date-time of midnight at the start of the minimum date + * in the maximum offset (larger offsets are earlier on the time-line). + * This combines {@link LocalDateTime#MIN} and {@link ZoneOffset#MAX}. + * This could be used by an application as a "far past" date-time. + */ + public static final OffsetDateTime MIN = LocalDateTime.MIN.atOffset(ZoneOffset.MAX); + /** + * The maximum supported {@code OffsetDateTime}, '+999999999-12-31T23:59:59.999999999-18:00'. + * This is the local date-time just before midnight at the end of the maximum date + * in the minimum offset (larger negative offsets are later on the time-line). + * This combines {@link LocalDateTime#MAX} and {@link ZoneOffset#MIN}. + * This could be used by an application as a "far future" date-time. + */ + public static final OffsetDateTime MAX = LocalDateTime.MAX.atOffset(ZoneOffset.MIN); + + /** + * Comparator for two {@code OffsetDateTime} instances based solely on the instant. + * <p> + * This method differs from the comparison in {@link #compareTo} in that it + * only compares the underlying instant. + * + * @see #isAfter + * @see #isBefore + * @see #isEqual + */ + public static final Comparator<OffsetDateTime> INSTANT_COMPARATOR = new Comparator<OffsetDateTime>() { + @Override + public int compare(OffsetDateTime datetime1, OffsetDateTime datetime2) { + int cmp = Long.compare(datetime1.toEpochSecond(), datetime2.toEpochSecond()); + if (cmp == 0) { + cmp = Long.compare(datetime1.toLocalTime().toNanoOfDay(), datetime2.toLocalTime().toNanoOfDay()); + } + return cmp; + } + }; + + /** + * Serialization version. + */ + private static final long serialVersionUID = 2287754244819255394L; + + /** + * The local date-time. + */ + private final LocalDateTime dateTime; + /** + * The offset from UTC/Greenwich. + */ + private final ZoneOffset offset; + + //----------------------------------------------------------------------- + /** + * Obtains the current date-time from the system clock in the default time-zone. + * <p> + * This will query the {@link java.time.Clock#systemDefaultZone() system clock} in the default + * time-zone to obtain the current date-time. + * The offset will be calculated from the time-zone in the clock. + * <p> + * Using this method will prevent the ability to use an alternate clock for testing + * because the clock is hard-coded. + * + * @return the current date-time using the system clock, not null + */ + public static OffsetDateTime now() { + return now(Clock.systemDefaultZone()); + } + + /** + * Obtains the current date-time from the system clock in the specified time-zone. + * <p> + * This will query the {@link Clock#system(java.time.ZoneId) system clock} to obtain the current date-time. + * Specifying the time-zone avoids dependence on the default time-zone. + * The offset will be calculated from the specified time-zone. + * <p> + * Using this method will prevent the ability to use an alternate clock for testing + * because the clock is hard-coded. + * + * @param zone the zone ID to use, not null + * @return the current date-time using the system clock, not null + */ + public static OffsetDateTime now(ZoneId zone) { + return now(Clock.system(zone)); + } + + /** + * Obtains the current date-time from the specified clock. + * <p> + * This will query the specified clock to obtain the current date-time. + * The offset will be calculated from the time-zone in the clock. + * <p> + * Using this method allows the use of an alternate clock for testing. + * The alternate clock may be introduced using {@link Clock dependency injection}. + * + * @param clock the clock to use, not null + * @return the current date-time, not null + */ + public static OffsetDateTime now(Clock clock) { + Objects.requireNonNull(clock, "clock"); + final Instant now = clock.instant(); // called once + return ofInstant(now, clock.getZone().getRules().getOffset(now)); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code OffsetDateTime} from a date, time and offset. + * <p> + * This creates an offset date-time with the specified local date, time and offset. + * + * @param date the local date, not null + * @param time the local time, not null + * @param offset the zone offset, not null + * @return the offset date-time, not null + */ + public static OffsetDateTime of(LocalDate date, LocalTime time, ZoneOffset offset) { + LocalDateTime dt = LocalDateTime.of(date, time); + return new OffsetDateTime(dt, offset); + } + + /** + * Obtains an instance of {@code OffsetDateTime} from a date-time and offset. + * <p> + * This creates an offset date-time with the specified local date-time and offset. + * + * @param dateTime the local date-time, not null + * @param offset the zone offset, not null + * @return the offset date-time, not null + */ + public static OffsetDateTime of(LocalDateTime dateTime, ZoneOffset offset) { + return new OffsetDateTime(dateTime, offset); + } + + /** + * Obtains an instance of {@code OffsetDateTime} from a year, month, day, + * hour, minute, second, nanosecond and offset. + * <p> + * This creates an offset date-time with the seven specified fields. + * <p> + * This method exists primarily for writing test cases. + * Non test-code will typically use other methods to create an offset time. + * {@code LocalDateTime} has five additional convenience variants of the + * equivalent factory method taking fewer arguments. + * They are not provided here to reduce the footprint of the API. + * + * @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 + * @param offset the zone offset, not null + * @return the offset date-time, not null + * @throws DateTimeException if the value of any field is out of range, or + * if the day-of-month is invalid for the month-year + */ + public static OffsetDateTime of( + int year, int month, int dayOfMonth, + int hour, int minute, int second, int nanoOfSecond, ZoneOffset offset) { + LocalDateTime dt = LocalDateTime.of(year, month, dayOfMonth, hour, minute, second, nanoOfSecond); + return new OffsetDateTime(dt, offset); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code OffsetDateTime} from an {@code Instant} and zone ID. + * <p> + * This creates an offset date-time with the same instant as that specified. + * Finding the offset from UTC/Greenwich is simple as there is only one valid + * offset for each instant. + * + * @param instant the instant to create the date-time from, not null + * @param zone the time-zone, which may be an offset, not null + * @return the offset date-time, not null + * @throws DateTimeException if the result exceeds the supported range + */ + public static OffsetDateTime ofInstant(Instant instant, ZoneId zone) { + Objects.requireNonNull(instant, "instant"); + Objects.requireNonNull(zone, "zone"); + ZoneRules rules = zone.getRules(); + ZoneOffset offset = rules.getOffset(instant); + LocalDateTime ldt = LocalDateTime.ofEpochSecond(instant.getEpochSecond(), instant.getNano(), offset); + return new OffsetDateTime(ldt, offset); + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code OffsetDateTime} from a temporal object. + * <p> + * This obtains an offset date-time based on the specified temporal. + * A {@code TemporalAccessor} represents an arbitrary set of date and time information, + * which this factory converts to an instance of {@code OffsetDateTime}. + * <p> + * The conversion will first obtain a {@code ZoneOffset} from the temporal object. + * It will then try to obtain a {@code LocalDateTime}, falling back to an {@code Instant} if necessary. + * The result will be the combination of {@code ZoneOffset} with either + * with {@code LocalDateTime} or {@code Instant}. + * Implementations are permitted to perform optimizations such as accessing + * those fields that are equivalent to the relevant objects. + * <p> + * This method matches the signature of the functional interface {@link TemporalQuery} + * allowing it to be used in queries via method reference, {@code OffsetDateTime::from}. + * + * @param temporal the temporal object to convert, not null + * @return the offset date-time, not null + * @throws DateTimeException if unable to convert to an {@code OffsetDateTime} + */ + public static OffsetDateTime from(TemporalAccessor temporal) { + if (temporal instanceof OffsetDateTime) { + return (OffsetDateTime) temporal; + } + ZoneOffset offset = ZoneOffset.from(temporal); + try { + try { + LocalDateTime ldt = LocalDateTime.from(temporal); + return OffsetDateTime.of(ldt, offset); + } catch (DateTimeException ignore) { + Instant instant = Instant.from(temporal); + return OffsetDateTime.ofInstant(instant, offset); + } + } catch (DateTimeException ex) { + throw new DateTimeException("Unable to obtain OffsetDateTime from TemporalAccessor: " + temporal.getClass(), ex); + } + } + + //----------------------------------------------------------------------- + /** + * Obtains an instance of {@code OffsetDateTime} from a text string + * such as {@code 2007-12-03T10:15:30+01:00}. + * <p> + * The string must represent a valid date-time and is parsed using + * {@link java.time.format.DateTimeFormatter#ISO_OFFSET_DATE_TIME}. + * + * @param text the text to parse such as "2007-12-03T10:15:30+01:00", not null + * @return the parsed offset date-time, not null + * @throws DateTimeParseException if the text cannot be parsed + */ + public static OffsetDateTime parse(CharSequence text) { + return parse(text, DateTimeFormatter.ISO_OFFSET_DATE_TIME); + } + + /** + * Obtains an instance of {@code OffsetDateTime} from a text string using a specific formatter. + * <p> + * The text is parsed using the formatter, returning a date-time. + * + * @param text the text to parse, not null + * @param formatter the formatter to use, not null + * @return the parsed offset date-time, not null + * @throws DateTimeParseException if the text cannot be parsed + */ + public static OffsetDateTime parse(CharSequence text, DateTimeFormatter formatter) { + Objects.requireNonNull(formatter, "formatter"); + return formatter.parse(text, OffsetDateTime::from); + } + + //----------------------------------------------------------------------- + /** + * Constructor. + * + * @param dateTime the local date-time, not null + * @param offset the zone offset, not null + */ + private OffsetDateTime(LocalDateTime dateTime, ZoneOffset offset) { + this.dateTime = Objects.requireNonNull(dateTime, "dateTime"); + this.offset = Objects.requireNonNull(offset, "offset"); + } + + /** + * Returns a new date-time based on this one, returning {@code this} where possible. + * + * @param dateTime the date-time to create with, not null + * @param offset the zone offset to create with, not null + */ + private OffsetDateTime with(LocalDateTime dateTime, ZoneOffset offset) { + if (this.dateTime == dateTime && this.offset.equals(offset)) { + return this; + } + return new OffsetDateTime(dateTime, offset); + } + + //----------------------------------------------------------------------- + /** + * Checks if the specified field is supported. + * <p> + * This checks if this date-time can be queried for the specified field. + * If false, then calling the {@link #range(TemporalField) range} and + * {@link #get(TemporalField) get} methods will throw an exception. + * <p> + * If the field is a {@link ChronoField} then the query is implemented here. + * The supported fields are: + * <ul> + * <li>{@code NANO_OF_SECOND} + * <li>{@code NANO_OF_DAY} + * <li>{@code MICRO_OF_SECOND} + * <li>{@code MICRO_OF_DAY} + * <li>{@code MILLI_OF_SECOND} + * <li>{@code MILLI_OF_DAY} + * <li>{@code SECOND_OF_MINUTE} + * <li>{@code SECOND_OF_DAY} + * <li>{@code MINUTE_OF_HOUR} + * <li>{@code MINUTE_OF_DAY} + * <li>{@code HOUR_OF_AMPM} + * <li>{@code CLOCK_HOUR_OF_AMPM} + * <li>{@code HOUR_OF_DAY} + * <li>{@code CLOCK_HOUR_OF_DAY} + * <li>{@code AMPM_OF_DAY} + * <li>{@code DAY_OF_WEEK} + * <li>{@code ALIGNED_DAY_OF_WEEK_IN_MONTH} + * <li>{@code ALIGNED_DAY_OF_WEEK_IN_YEAR} + * <li>{@code DAY_OF_MONTH} + * <li>{@code DAY_OF_YEAR} + * <li>{@code EPOCH_DAY} + * <li>{@code ALIGNED_WEEK_OF_MONTH} + * <li>{@code ALIGNED_WEEK_OF_YEAR} + * <li>{@code MONTH_OF_YEAR} + * <li>{@code EPOCH_MONTH} + * <li>{@code YEAR_OF_ERA} + * <li>{@code YEAR} + * <li>{@code ERA} + * <li>{@code INSTANT_SECONDS} + * <li>{@code OFFSET_SECONDS} + * </ul> + * All other {@code ChronoField} instances will return false. + * <p> + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.isSupportedBy(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.isSupportedBy(this)); + } + + /** + * Gets the range of valid values for the specified field. + * <p> + * The range object expresses the minimum and maximum valid values for a field. + * This date-time is used to enhance the accuracy of the returned range. + * If it is not possible to return the range, because the field is not supported + * or for some other reason, an exception is thrown. + * <p> + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return + * appropriate range instances. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + * <p> + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.rangeRefinedBy(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.rangeRefinedBy(this); + } + + /** + * Gets the value of the specified field from this date-time as an {@code int}. + * <p> + * This queries this date-time for the value for the specified field. + * The returned value will always be within the valid range of values for the field. + * If it is not possible to return the value, because the field is not supported + * or for some other reason, an exception is thrown. + * <p> + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return valid + * values based on this date-time, except {@code NANO_OF_DAY}, {@code MICRO_OF_DAY}, + * {@code EPOCH_DAY}, {@code EPOCH_MONTH} and {@code INSTANT_SECONDS} which are too + * large to fit in an {@code int} and throw a {@code DateTimeException}. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + * <p> + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} + * passing {@code this} as the argument. Whether the value can be obtained, + * and what the value represents, is determined by the field. + * + * @param field the field to get, not null + * @return the value for the field + * @throws DateTimeException if a value for the field cannot be obtained + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public int get(TemporalField field) { + if (field instanceof ChronoField) { + switch ((ChronoField) field) { + case INSTANT_SECONDS: throw new DateTimeException("Field too large for an int: " + field); + case OFFSET_SECONDS: return getOffset().getTotalSeconds(); + } + return dateTime.get(field); + } + return Temporal.super.get(field); + } + + /** + * Gets the value of the specified field from this date-time as a {@code long}. + * <p> + * This queries this date-time for the value for the specified field. + * If it is not possible to return the value, because the field is not supported + * or for some other reason, an exception is thrown. + * <p> + * If the field is a {@link ChronoField} then the query is implemented here. + * The {@link #isSupported(TemporalField) supported fields} will return valid + * values based on this date-time. + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + * <p> + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} + * passing {@code this} as the argument. Whether the value can be obtained, + * and what the value represents, is determined by the field. + * + * @param field the field to get, not null + * @return the value for the field + * @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.getFrom(this); + } + + //----------------------------------------------------------------------- + /** + * Gets the zone offset, such as '+01:00'. + * <p> + * This is the offset of the local date-time from UTC/Greenwich. + * + * @return the zone offset, not null + */ + public ZoneOffset getOffset() { + return offset; + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the specified offset ensuring + * that the result has the same local date-time. + * <p> + * This method returns an object with the same {@code LocalDateTime} and the specified {@code ZoneOffset}. + * No calculation is needed or performed. + * For example, if this time represents {@code 2007-12-03T10:30+02:00} and the offset specified is + * {@code +03:00}, then this method will return {@code 2007-12-03T10:30+03:00}. + * <p> + * To take into account the difference between the offsets, and adjust the time fields, + * use {@link #withOffsetSameInstant}. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param offset the zone offset to change to, not null + * @return an {@code OffsetDateTime} based on this date-time with the requested offset, not null + */ + public OffsetDateTime withOffsetSameLocal(ZoneOffset offset) { + return with(dateTime, offset); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the specified offset ensuring + * that the result is at the same instant. + * <p> + * This method returns an object with the specified {@code ZoneOffset} and a {@code LocalDateTime} + * adjusted by the difference between the two offsets. + * This will result in the old and new objects representing the same instant. + * This is useful for finding the local time in a different offset. + * For example, if this time represents {@code 2007-12-03T10:30+02:00} and the offset specified is + * {@code +03:00}, then this method will return {@code 2007-12-03T11:30+03:00}. + * <p> + * To change the offset without adjusting the local time use {@link #withOffsetSameLocal}. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param offset the zone offset to change to, not null + * @return an {@code OffsetDateTime} based on this date-time with the requested offset, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime withOffsetSameInstant(ZoneOffset offset) { + if (offset.equals(this.offset)) { + return this; + } + int difference = offset.getTotalSeconds() - this.offset.getTotalSeconds(); + LocalDateTime adjusted = dateTime.plusSeconds(difference); + return new OffsetDateTime(adjusted, offset); + } + + //----------------------------------------------------------------------- + /** + * Gets the {@code LocalDateTime} part of this offset date-time. + * <p> + * This returns a {@code LocalDateTime} with the same year, month, day and time + * as this date-time. + * + * @return the local date-time part of this date-time, not null + */ + public LocalDateTime toLocalDateTime() { + return dateTime; + } + + //----------------------------------------------------------------------- + /** + * Gets the {@code LocalDate} part of this date-time. + * <p> + * This returns a {@code LocalDate} with the same year, month and day + * as this date-time. + * + * @return the date part of this date-time, not null + */ + public LocalDate toLocalDate() { + return dateTime.toLocalDate(); + } + + /** + * Gets the year field. + * <p> + * This method returns the primitive {@code int} value for the year. + * <p> + * The year returned by this method is proleptic as per {@code get(YEAR)}. + * To obtain the year-of-era, use {@code get(YEAR_OF_ERA)}. + * + * @return the year, from MIN_YEAR to MAX_YEAR + */ + public int getYear() { + return dateTime.getYear(); + } + + /** + * Gets the month-of-year field from 1 to 12. + * <p> + * This method returns the month as an {@code int} from 1 to 12. + * Application code is frequently clearer if the enum {@link Month} + * is used by calling {@link #getMonth()}. + * + * @return the month-of-year, from 1 to 12 + * @see #getMonth() + */ + public int getMonthValue() { + return dateTime.getMonthValue(); + } + + /** + * Gets the month-of-year field using the {@code Month} enum. + * <p> + * This method returns the enum {@link Month} for the month. + * This avoids confusion as to what {@code int} values mean. + * If you need access to the primitive {@code int} value then the enum + * provides the {@link Month#getValue() int value}. + * + * @return the month-of-year, not null + * @see #getMonthValue() + */ + public Month getMonth() { + return dateTime.getMonth(); + } + + /** + * Gets the day-of-month field. + * <p> + * This method returns the primitive {@code int} value for the day-of-month. + * + * @return the day-of-month, from 1 to 31 + */ + public int getDayOfMonth() { + return dateTime.getDayOfMonth(); + } + + /** + * Gets the day-of-year field. + * <p> + * This method returns the primitive {@code int} value for the day-of-year. + * + * @return the day-of-year, from 1 to 365, or 366 in a leap year + */ + public int getDayOfYear() { + return dateTime.getDayOfYear(); + } + + /** + * Gets the day-of-week field, which is an enum {@code DayOfWeek}. + * <p> + * This method returns the enum {@link java.time.DayOfWeek} for the day-of-week. + * This avoids confusion as to what {@code int} values mean. + * If you need access to the primitive {@code int} value then the enum + * provides the {@link java.time.DayOfWeek#getValue() int value}. + * <p> + * Additional information can be obtained from the {@code DayOfWeek}. + * This includes textual names of the values. + * + * @return the day-of-week, not null + */ + public DayOfWeek getDayOfWeek() { + return dateTime.getDayOfWeek(); + } + + //----------------------------------------------------------------------- + /** + * Gets the {@code LocalTime} part of this date-time. + * <p> + * This returns a {@code LocalTime} with the same hour, minute, second and + * nanosecond as this date-time. + * + * @return the time part of this date-time, not null + */ + public LocalTime toLocalTime() { + return dateTime.toLocalTime(); + } + + /** + * Gets the hour-of-day field. + * + * @return the hour-of-day, from 0 to 23 + */ + public int getHour() { + return dateTime.getHour(); + } + + /** + * Gets the minute-of-hour field. + * + * @return the minute-of-hour, from 0 to 59 + */ + public int getMinute() { + return dateTime.getMinute(); + } + + /** + * Gets the second-of-minute field. + * + * @return the second-of-minute, from 0 to 59 + */ + public int getSecond() { + return dateTime.getSecond(); + } + + /** + * Gets the nano-of-second field. + * + * @return the nano-of-second, from 0 to 999,999,999 + */ + public int getNano() { + return dateTime.getNano(); + } + + //----------------------------------------------------------------------- + /** + * Returns an adjusted copy of this date-time. + * <p> + * This returns an {@code OffsetDateTime}, based on this one, with the date-time adjusted. + * The adjustment takes place using the specified adjuster strategy object. + * Read the documentation of the adjuster to understand what adjustment will be made. + * <p> + * A simple adjuster might simply set the one of the fields, such as the year field. + * A more complex adjuster might set the date to the last day of the month. + * A selection of common adjustments is provided in {@link java.time.temporal.Adjusters}. + * These include finding the "last day of the month" and "next Wednesday". + * Key date-time classes also implement the {@code TemporalAdjuster} interface, + * such as {@link Month} and {@link java.time.MonthDay MonthDay}. + * The adjuster is responsible for handling special cases, such as the varying + * lengths of month and leap years. + * <p> + * For example this code returns a date on the last day of July: + * <pre> + * import static java.time.Month.*; + * import static java.time.temporal.Adjusters.*; + * + * result = offsetDateTime.with(JULY).with(lastDayOfMonth()); + * </pre> + * <p> + * The classes {@link LocalDate}, {@link LocalTime} and {@link ZoneOffset} implement + * {@code TemporalAdjuster}, thus this method can be used to change the date, time or offset: + * <pre> + * result = offsetDateTime.with(date); + * result = offsetDateTime.with(time); + * result = offsetDateTime.with(offset); + * </pre> + * <p> + * The result of this method is obtained by invoking the + * {@link TemporalAdjuster#adjustInto(Temporal)} method on the + * specified adjuster passing {@code this} as the argument. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param adjuster the adjuster to use, not null + * @return an {@code OffsetDateTime} based on {@code this} with the adjustment made, not null + * @throws DateTimeException if the adjustment cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public OffsetDateTime with(TemporalAdjuster adjuster) { + // optimizations + if (adjuster instanceof LocalDate || adjuster instanceof LocalTime || adjuster instanceof LocalDateTime) { + return with(dateTime.with(adjuster), offset); + } else if (adjuster instanceof Instant) { + return ofInstant((Instant) adjuster, offset); + } else if (adjuster instanceof ZoneOffset) { + return with(dateTime, (ZoneOffset) adjuster); + } else if (adjuster instanceof OffsetDateTime) { + return (OffsetDateTime) adjuster; + } + return (OffsetDateTime) adjuster.adjustInto(this); + } + + /** + * Returns a copy of this date-time with the specified field set to a new value. + * <p> + * TThis returns an {@code OffsetDateTime}, based on this one, with the value + * for the specified field changed. + * This can be used to change any supported field, such as the year, month or day-of-month. + * If it is not possible to set the value, because the field is not supported or for + * some other reason, an exception is thrown. + * <p> + * In some cases, changing the specified field can cause the resulting date-time to become invalid, + * such as changing the month from 31st January to February would make the day-of-month invalid. + * In cases like this, the field is responsible for resolving the date. Typically it will choose + * the previous valid date, which would be the last valid day of February in this example. + * <p> + * If the field is a {@link ChronoField} then the adjustment is implemented here. + * <p> + * The {@code INSTANT_SECONDS} field will return a date-time with the specified instant. + * The offset and nano-of-second are unchanged. + * If the new instant value is outside the valid range then a {@code DateTimeException} will be thrown. + * <p> + * The {@code OFFSET_SECONDS} field will return a date-time with the specified offset. + * The local date-time is unaltered. If the new offset value is outside the valid range + * then a {@code DateTimeException} will be thrown. + * <p> + * The other {@link #isSupported(TemporalField) supported fields} will behave as per + * the matching method on {@link LocalDateTime#with(TemporalField, long) LocalDateTime}. + * In this case, the offset is not part of the calculation and will be unchanged. + * <p> + * All other {@code ChronoField} instances will throw a {@code DateTimeException}. + * <p> + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)} + * passing {@code this} as the argument. In this case, the field determines + * whether and how to adjust the instant. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param field the field to set in the result, not null + * @param newValue the new value of the field in the result + * @return an {@code OffsetDateTime} based on {@code this} with the specified field set, not null + * @throws DateTimeException if the field cannot be set + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public OffsetDateTime with(TemporalField field, long newValue) { + if (field instanceof ChronoField) { + ChronoField f = (ChronoField) field; + switch (f) { + case INSTANT_SECONDS: return ofInstant(Instant.ofEpochSecond(newValue, getNano()), offset); + case OFFSET_SECONDS: { + return with(dateTime, ZoneOffset.ofTotalSeconds(f.checkValidIntValue(newValue))); + } + } + return with(dateTime.with(field, newValue), offset); + } + return field.adjustInto(this, newValue); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this {@code OffsetDateTime} with the year altered. + * The offset does not affect the calculation and will be the same in the result. + * If the day-of-month is invalid for the year, it will be changed to the last valid day of the month. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param year the year to set in the result, from MIN_YEAR to MAX_YEAR + * @return an {@code OffsetDateTime} based on this date-time with the requested year, not null + * @throws DateTimeException if the year value is invalid + */ + public OffsetDateTime withYear(int year) { + return with(dateTime.withYear(year), offset); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the month-of-year altered. + * The offset does not affect the calculation and will be the same in the result. + * If the day-of-month is invalid for the year, it will be changed to the last valid day of the month. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param month the month-of-year to set in the result, from 1 (January) to 12 (December) + * @return an {@code OffsetDateTime} based on this date-time with the requested month, not null + * @throws DateTimeException if the month-of-year value is invalid + */ + public OffsetDateTime withMonth(int month) { + return with(dateTime.withMonth(month), offset); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the day-of-month altered. + * If the resulting {@code OffsetDateTime} is invalid, an exception is thrown. + * The offset does not affect the calculation and will be the same in the result. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param dayOfMonth the day-of-month to set in the result, from 1 to 28-31 + * @return an {@code OffsetDateTime} based on this date-time with the requested day, not null + * @throws DateTimeException if the day-of-month value is invalid, + * or if the day-of-month is invalid for the month-year + */ + public OffsetDateTime withDayOfMonth(int dayOfMonth) { + return with(dateTime.withDayOfMonth(dayOfMonth), offset); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the day-of-year altered. + * If the resulting {@code OffsetDateTime} is invalid, an exception is thrown. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param dayOfYear the day-of-year to set in the result, from 1 to 365-366 + * @return an {@code OffsetDateTime} based on this date with the requested day, not null + * @throws DateTimeException if the day-of-year value is invalid, + * or if the day-of-year is invalid for the year + */ + public OffsetDateTime withDayOfYear(int dayOfYear) { + return with(dateTime.withDayOfYear(dayOfYear), offset); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this {@code OffsetDateTime} with the hour-of-day value altered. + * <p> + * The offset does not affect the calculation and will be the same in the result. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param hour the hour-of-day to set in the result, from 0 to 23 + * @return an {@code OffsetDateTime} based on this date-time with the requested hour, not null + * @throws DateTimeException if the hour value is invalid + */ + public OffsetDateTime withHour(int hour) { + return with(dateTime.withHour(hour), offset); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the minute-of-hour value altered. + * <p> + * The offset does not affect the calculation and will be the same in the result. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param minute the minute-of-hour to set in the result, from 0 to 59 + * @return an {@code OffsetDateTime} based on this date-time with the requested minute, not null + * @throws DateTimeException if the minute value is invalid + */ + public OffsetDateTime withMinute(int minute) { + return with(dateTime.withMinute(minute), offset); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the second-of-minute value altered. + * <p> + * The offset does not affect the calculation and will be the same in the result. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param second the second-of-minute to set in the result, from 0 to 59 + * @return an {@code OffsetDateTime} based on this date-time with the requested second, not null + * @throws DateTimeException if the second value is invalid + */ + public OffsetDateTime withSecond(int second) { + return with(dateTime.withSecond(second), offset); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the nano-of-second value altered. + * <p> + * The offset does not affect the calculation and will be the same in the result. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param nanoOfSecond the nano-of-second to set in the result, from 0 to 999,999,999 + * @return an {@code OffsetDateTime} based on this date-time with the requested nanosecond, not null + * @throws DateTimeException if the nanos value is invalid + */ + public OffsetDateTime withNano(int nanoOfSecond) { + return with(dateTime.withNano(nanoOfSecond), offset); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this {@code OffsetDateTime} with the time truncated. + * <p> + * Truncation returns a copy of the original date-time with fields + * smaller than the specified unit set to zero. + * For example, truncating with the {@link ChronoUnit#MINUTES minutes} unit + * will set the second-of-minute and nano-of-second field to zero. + * <p> + * The unit must have a {@linkplain TemporalUnit#getDuration() duration} + * that divides into the length of a standard day without remainder. + * This includes all supplied time units on {@link ChronoUnit} and + * {@link ChronoUnit#DAYS DAYS}. Other units throw an exception. + * <p> + * The offset does not affect the calculation and will be the same in the result. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param unit the unit to truncate to, not null + * @return an {@code OffsetDateTime} based on this date-time with the time truncated, not null + * @throws DateTimeException if unable to truncate + */ + public OffsetDateTime truncatedTo(TemporalUnit unit) { + return with(dateTime.truncatedTo(unit), offset); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this date-time with the specified amount added. + * <p> + * This returns an {@code OffsetDateTime}, based on this one, with the specified amount added. + * The amount is typically {@link Period} or {@link Duration} but may be + * any other type implementing the {@link TemporalAmount} interface. + * <p> + * The calculation is delegated to the amount object by calling + * {@link TemporalAmount#addTo(Temporal)}. The amount implementation is free + * to implement the addition in any way it wishes, however it typically + * calls back to {@link #plus(long, TemporalUnit)}. Consult the documentation + * of the amount implementation to determine if it can be successfully added. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param amountToAdd the amount to add, not null + * @return an {@code OffsetDateTime} based on this date-time with the addition made, not null + * @throws DateTimeException if the addition cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public OffsetDateTime plus(TemporalAmount amountToAdd) { + return (OffsetDateTime) amountToAdd.addTo(this); + } + + /** + * Returns a copy of this date-time with the specified amount added. + * <p> + * This returns an {@code OffsetDateTime}, based on this one, with the amount + * in terms of the unit added. If it is not possible to add the amount, because the + * unit is not supported or for some other reason, an exception is thrown. + * <p> + * If the field is a {@link ChronoUnit} then the addition is implemented by + * {@link LocalDateTime#plus(long, TemporalUnit)}. + * The offset is not part of the calculation and will be unchanged in the result. + * <p> + * If the field is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)} + * passing {@code this} as the argument. In this case, the unit determines + * whether and how to perform the addition. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param amountToAdd the amount of the unit to add to the result, may be negative + * @param unit the unit of the amount to add, not null + * @return an {@code OffsetDateTime} based on this date-time with the specified amount added, not null + * @throws DateTimeException if the addition cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public OffsetDateTime plus(long amountToAdd, TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + return with(dateTime.plus(amountToAdd, unit), offset); + } + return unit.addTo(this, amountToAdd); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this {@code OffsetDateTime} with the specified period in years added. + * <p> + * This method adds the specified amount to the years field in three steps: + * <ol> + * <li>Add the input years to the year field</li> + * <li>Check if the resulting date would be invalid</li> + * <li>Adjust the day-of-month to the last valid day if necessary</li> + * </ol> + * <p> + * For example, 2008-02-29 (leap year) plus one year would result in the + * invalid date 2009-02-29 (standard year). Instead of returning an invalid + * result, the last valid day of the month, 2009-02-28, is selected instead. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param years the years to add, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the years added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime plusYears(long years) { + return with(dateTime.plusYears(years), offset); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the specified period in months added. + * <p> + * This method adds the specified amount to the months field in three steps: + * <ol> + * <li>Add the input months to the month-of-year field</li> + * <li>Check if the resulting date would be invalid</li> + * <li>Adjust the day-of-month to the last valid day if necessary</li> + * </ol> + * <p> + * For example, 2007-03-31 plus one month would result in the invalid date + * 2007-04-31. Instead of returning an invalid result, the last valid day + * of the month, 2007-04-30, is selected instead. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param months the months to add, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the months added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime plusMonths(long months) { + return with(dateTime.plusMonths(months), offset); + } + + /** + * Returns a copy of this OffsetDateTime with the specified period in weeks added. + * <p> + * This method adds the specified amount in weeks to the days field incrementing + * the month and year fields as necessary to ensure the result remains valid. + * The result is only invalid if the maximum/minimum year is exceeded. + * <p> + * For example, 2008-12-31 plus one week would result in the 2009-01-07. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param weeks the weeks to add, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the weeks added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime plusWeeks(long weeks) { + return with(dateTime.plusWeeks(weeks), offset); + } + + /** + * Returns a copy of this OffsetDateTime with the specified period in days added. + * <p> + * This method adds the specified amount to the days field incrementing the + * month and year fields as necessary to ensure the result remains valid. + * The result is only invalid if the maximum/minimum year is exceeded. + * <p> + * For example, 2008-12-31 plus one day would result in the 2009-01-01. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param days the days to add, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the days added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime plusDays(long days) { + return with(dateTime.plusDays(days), offset); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the specified period in hours added. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param hours the hours to add, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the hours added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime plusHours(long hours) { + return with(dateTime.plusHours(hours), offset); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the specified period in minutes added. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param minutes the minutes to add, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the minutes added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime plusMinutes(long minutes) { + return with(dateTime.plusMinutes(minutes), offset); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the specified period in seconds added. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param seconds the seconds to add, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the seconds added, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime plusSeconds(long seconds) { + return with(dateTime.plusSeconds(seconds), offset); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the specified period in nanoseconds added. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param nanos the nanos to add, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the nanoseconds added, not null + * @throws DateTimeException if the unit cannot be added to this type + */ + public OffsetDateTime plusNanos(long nanos) { + return with(dateTime.plusNanos(nanos), offset); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this date-time with the specified amount subtracted. + * <p> + * This returns an {@code OffsetDateTime}, based on this one, with the specified amount subtracted. + * The amount is typically {@link Period} or {@link Duration} but may be + * any other type implementing the {@link TemporalAmount} interface. + * <p> + * The calculation is delegated to the amount object by calling + * {@link TemporalAmount#subtractFrom(Temporal)}. The amount implementation is free + * to implement the subtraction in any way it wishes, however it typically + * calls back to {@link #minus(long, TemporalUnit)}. Consult the documentation + * of the amount implementation to determine if it can be successfully subtracted. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param amountToSubtract the amount to subtract, not null + * @return an {@code OffsetDateTime} based on this date-time with the subtraction made, not null + * @throws DateTimeException if the subtraction cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public OffsetDateTime minus(TemporalAmount amountToSubtract) { + return (OffsetDateTime) amountToSubtract.subtractFrom(this); + } + + /** + * Returns a copy of this date-time with the specified amount subtracted. + * <p> + * This returns an {@code OffsetDateTime}, based on this one, with the amount + * in terms of the unit subtracted. If it is not possible to subtract the amount, + * because the unit is not supported or for some other reason, an exception is thrown. + * <p> + * This method is equivalent to {@link #plus(long, TemporalUnit)} with the amount negated. + * See that method for a full description of how addition, and thus subtraction, works. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param amountToSubtract the amount of the unit to subtract from the result, may be negative + * @param unit the unit of the amount to subtract, not null + * @return an {@code OffsetDateTime} based on this date-time with the specified amount subtracted, not null + * @throws DateTimeException if the subtraction cannot be made + * @throws ArithmeticException if numeric overflow occurs + */ + @Override + public OffsetDateTime minus(long amountToSubtract, TemporalUnit unit) { + return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit)); + } + + //----------------------------------------------------------------------- + /** + * Returns a copy of this {@code OffsetDateTime} with the specified period in years subtracted. + * <p> + * This method subtracts the specified amount from the years field in three steps: + * <ol> + * <li>Subtract the input years to the year field</li> + * <li>Check if the resulting date would be invalid</li> + * <li>Adjust the day-of-month to the last valid day if necessary</li> + * </ol> + * <p> + * For example, 2008-02-29 (leap year) minus one year would result in the + * invalid date 2009-02-29 (standard year). Instead of returning an invalid + * result, the last valid day of the month, 2009-02-28, is selected instead. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param years the years to subtract, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the years subtracted, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime minusYears(long years) { + return (years == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-years)); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the specified period in months subtracted. + * <p> + * This method subtracts the specified amount from the months field in three steps: + * <ol> + * <li>Subtract the input months to the month-of-year field</li> + * <li>Check if the resulting date would be invalid</li> + * <li>Adjust the day-of-month to the last valid day if necessary</li> + * </ol> + * <p> + * For example, 2007-03-31 minus one month would result in the invalid date + * 2007-04-31. Instead of returning an invalid result, the last valid day + * of the month, 2007-04-30, is selected instead. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param months the months to subtract, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the months subtracted, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime minusMonths(long months) { + return (months == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-months)); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the specified period in weeks subtracted. + * <p> + * This method subtracts the specified amount in weeks from the days field decrementing + * the month and year fields as necessary to ensure the result remains valid. + * The result is only invalid if the maximum/minimum year is exceeded. + * <p> + * For example, 2008-12-31 minus one week would result in the 2009-01-07. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param weeks the weeks to subtract, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the weeks subtracted, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime minusWeeks(long weeks) { + return (weeks == Long.MIN_VALUE ? plusWeeks(Long.MAX_VALUE).plusWeeks(1) : plusWeeks(-weeks)); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the specified period in days subtracted. + * <p> + * This method subtracts the specified amount from the days field incrementing the + * month and year fields as necessary to ensure the result remains valid. + * The result is only invalid if the maximum/minimum year is exceeded. + * <p> + * For example, 2008-12-31 minus one day would result in the 2009-01-01. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param days the days to subtract, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the days subtracted, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime minusDays(long days) { + return (days == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-days)); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the specified period in hours subtracted. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param hours the hours to subtract, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the hours subtracted, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime minusHours(long hours) { + return (hours == Long.MIN_VALUE ? plusHours(Long.MAX_VALUE).plusHours(1) : plusHours(-hours)); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the specified period in minutes subtracted. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param minutes the minutes to subtract, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the minutes subtracted, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime minusMinutes(long minutes) { + return (minutes == Long.MIN_VALUE ? plusMinutes(Long.MAX_VALUE).plusMinutes(1) : plusMinutes(-minutes)); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the specified period in seconds subtracted. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param seconds the seconds to subtract, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the seconds subtracted, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime minusSeconds(long seconds) { + return (seconds == Long.MIN_VALUE ? plusSeconds(Long.MAX_VALUE).plusSeconds(1) : plusSeconds(-seconds)); + } + + /** + * Returns a copy of this {@code OffsetDateTime} with the specified period in nanoseconds subtracted. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param nanos the nanos to subtract, may be negative + * @return an {@code OffsetDateTime} based on this date-time with the nanoseconds subtracted, not null + * @throws DateTimeException if the result exceeds the supported date range + */ + public OffsetDateTime minusNanos(long nanos) { + return (nanos == Long.MIN_VALUE ? plusNanos(Long.MAX_VALUE).plusNanos(1) : plusNanos(-nanos)); + } + + //----------------------------------------------------------------------- + /** + * Queries this date-time using the specified query. + * <p> + * This queries this date-time using the specified query strategy object. + * The {@code TemporalQuery} object defines the logic to be used to + * obtain the result. Re